Commit a74b66cd authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq into upstream-ce

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

Conflicts:
	app/models/group.rb
	app/models/project.rb
	features/steps/shared/project.rb
parents efd08747 a019b49a
......@@ -7,6 +7,19 @@ v 7.1.0
- Add @all mention for comments
- Dont show reply button if user is not signed in
- Expose more information for issues with webhook
- Add a mention of the merge request into the default merge request commit message
- Imrpove code highlight, introduce support for more languages like Go, Clojure, Erlang etc
- Fix concurrency issue in repository download
- Dont allow repository name start with ?
- Improve email threading (Pierre de La Morinerie)
- Cleaner help page
- Group milestones
- Improved email notifications
- Contributors API (sponsored by Mobbr)
- Fix LDAP TLS authentication (Boris HUISGEN)
- Show VERSION information on project sidebar
- Improve branch removal logic when accept MR
- Fix bug where comment form is spawned inside the Reply button
v 7.0.0
- The CPU no longer overheats when you hold down the spacebar
......
......@@ -42,7 +42,7 @@ Please send a merge request with a tested solution or a merge request with a fai
1. **Observed behavior**
1. **Relevant logs and/or screenshots:** Please use code blocks (\`\`\`) to format console output, logs, and code as it's very hard to read otherwise.
1. **Output of checks**
* Results of GitLab [Application Check](doc/install/installation.md#check-application-status) (`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production`); we will only investigate if the tests are passing
* Results of GitLab [Application Check](doc/install/installation.md#check-application-status) (`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`); we will only investigate if the tests are passing
* Version of GitLab you are running; we will only investigate issues in the latest stable and development releases as per the [maintenance policy](MAINTENANCE.md)
* Add the last commit sha1 of the GitLab version you used to replicate the issue (obtainable from the help page)
* Describe your setup (use relevant parts from `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
......
......@@ -10,8 +10,6 @@ end
gem "rails", "~> 4.1.0"
gem "protected_attributes"
# Make links from text
gem 'rails_autolink', '~> 1.1'
......@@ -23,8 +21,8 @@ gem "mysql2", group: :mysql
gem "pg", group: :postgres
# Auth
gem "devise", '3.0.4'
gem "devise-async", '0.8.0'
gem "devise", '3.2.4'
gem "devise-async", '0.9.0'
gem 'omniauth', "~> 1.1.3"
gem 'omniauth-google-oauth2'
gem 'omniauth-twitter'
......@@ -49,7 +47,6 @@ gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
# API
gem "grape", "~> 0.6.1"
# Replace with rubygems when nesteted entities get released
gem "grape-entity", "~> 0.4.2"
gem 'rack-cors', require: 'rack/cors'
......
......@@ -40,7 +40,7 @@ GEM
axiom-types (0.0.5)
descendants_tracker (~> 0.0.1)
ice_nine (~> 0.9)
bcrypt-ruby (3.1.2)
bcrypt (3.1.7)
better_errors (1.0.1)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
......@@ -94,13 +94,14 @@ GEM
default_value_for (3.0.0)
activerecord (>= 3.2.0, < 5.0)
descendants_tracker (0.0.3)
devise (3.0.4)
bcrypt-ruby (~> 3.0)
devise (3.2.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
devise-async (0.8.0)
devise (>= 2.2, < 3.2)
devise-async (0.9.0)
devise (~> 3.2)
diff-lcs (1.2.5)
diffy (3.0.3)
docile (1.1.1)
......@@ -175,7 +176,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.0.1.1)
emoji (~> 1.0.1)
gitlab_git (6.0.0)
gitlab_git (6.0.1)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-grit (~> 2.6)
......@@ -282,7 +283,7 @@ GEM
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.0)
minitest (5.3.4)
minitest (5.3.5)
multi_json (1.10.1)
multi_xml (0.5.5)
multipart-post (1.2.0)
......@@ -331,8 +332,6 @@ GEM
websocket-driver (>= 0.2.0)
polyglot (0.3.4)
posix-spawn (0.3.8)
protected_attributes (1.0.5)
activemodel (>= 4.0.1, < 5.0)
pry (0.9.12.4)
coderay (~> 1.0)
method_source (~> 0.8)
......@@ -586,8 +585,8 @@ DEPENDENCIES
d3_rails (~> 3.1.4)
database_cleaner
default_value_for (~> 3.0.0)
devise (= 3.0.4)
devise-async (= 0.8.0)
devise (= 3.2.4)
devise-async (= 0.9.0)
diffy (~> 3.0.3)
dropzonejs-rails
email_spec
......@@ -636,7 +635,6 @@ DEPENDENCIES
org-ruby
pg
poltergeist (~> 1.5.1)
protected_attributes
pry
quiet_assets (~> 1.0.1)
rack-attack
......
......@@ -23,7 +23,7 @@
#= require g.raphael-min
#= require g.bar-min
#= require branch-graph
#= require highlightjs.min
#= require highlight.pack
#= require ace/ace
#= require d3
#= require underscore
......
......@@ -376,7 +376,7 @@ class Notes
###
replyToDiscussionNote: (e) =>
form = $(".js-new-note-form")
replyLink = $(e.target)
replyLink = $(e.target).closest(".js-discussion-reply-button")
replyLink.hide()
# insert the form after the button
......
......@@ -152,16 +152,16 @@
}
&.btn-close {
color: #B94A48;
font-weight: bold;
color: $bg_danger;
border-color: $border_danger;
&:hover {
color: #B94A48;
}
}
&.btn-reopen {
color: #468847;
font-weight: bold;
color: $bg_success;
border-color: $border_success;
&:hover {
color: #468847;
}
......
......@@ -177,10 +177,18 @@ li.commit {
.commit-row-description {
font-size: 14px;
border-left: 1px solid #e5e5e5;
padding: 0 15px 0 7px;
border-left: 1px solid #EEE;
padding: 10px 15px;
margin: 5px 0 10px 5px;
background: #f9f9f9;
display: none;
pre {
border: none;
background: inherit;
padding: 0;
margin: 0;
}
}
.commit-row-info {
......
......@@ -7,3 +7,7 @@
.member-search-form {
float: left;
}
.milestone-row {
@include str-truncated(90%);
}
......@@ -53,13 +53,9 @@ header {
font-size: 18px;
.app_logo { margin-left: -15px; }
.title {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top;
white-space: nowrap;
max-width: 70%;
@include str-truncated(70%);
}
.navbar-collapse {
......@@ -130,6 +126,7 @@ header {
margin: 0;
margin-left: 5px;
@include header-font;
@include str-truncated(37%);
}
.profile-pic {
......@@ -254,7 +251,7 @@ header {
.search .search-input {
width: 300px;
&:focus {
width: 400px;
width: 330px;
}
}
......@@ -262,7 +259,7 @@ header {
.search .search-input {
width: 200px;
&:focus {
width: 300px;
width: 230px;
}
}
}
......
......@@ -28,6 +28,7 @@
}
td {
border-color: #F1F1F1 !important;
border-bottom: 1px solid;
}
&:hover {
td {
......
......@@ -6,7 +6,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
end
def create
@broadcast_message = BroadcastMessage.new(params[:broadcast_message])
@broadcast_message = BroadcastMessage.new(broadcast_message_params)
if @broadcast_message.save
redirect_to admin_broadcast_messages_path, notice: 'Broadcast Message was successfully created.'
......@@ -29,4 +29,11 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
def broadcast_messages
@broadcast_messages ||= BroadcastMessage.order("starts_at DESC").page(params[:page])
end
def broadcast_message_params
params.require(:broadcast_message).permit(
:alert_type, :color, :ends_at, :font,
:message, :starts_at
)
end
end
......@@ -20,7 +20,7 @@ class Admin::GroupsController < Admin::ApplicationController
end
def create
@group = Group.new(params[:group])
@group = Group.new(group_params)
@group.path = @group.name.dup.parameterize if @group.name
if @group.save
......@@ -32,7 +32,7 @@ class Admin::GroupsController < Admin::ApplicationController
end
def update
if @group.update_attributes(params[:group])
if @group.update_attributes(group_params)
redirect_to [:admin, @group], notice: 'Group was successfully updated.'
else
render "edit"
......@@ -56,4 +56,8 @@ class Admin::GroupsController < Admin::ApplicationController
def group
@group = Group.find_by(path: params[:id])
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar)
end
end
......@@ -5,7 +5,7 @@ class Admin::HooksController < Admin::ApplicationController
end
def create
@hook = SystemHook.new(params[:hook])
@hook = SystemHook.new(hook_params)
if @hook.save
redirect_to admin_hooks_path, notice: 'Hook was successfully created.'
......@@ -37,4 +37,8 @@ class Admin::HooksController < Admin::ApplicationController
redirect_to :back
end
def hook_params
params.require(:hook).permit(:url)
end
end
......@@ -13,7 +13,7 @@ class Admin::UsersController < Admin::ApplicationController
end
def new
@user = User.build_user
@user = User.new
end
def edit
......@@ -37,15 +37,12 @@ class Admin::UsersController < Admin::ApplicationController
end
def create
admin = params[:user].delete("admin")
opts = {
force_random_password: true,
password_expires_at: Time.now
}
@user = User.build_user(params[:user].merge(opts), as: :admin)
@user.admin = (admin && admin.to_i > 0)
@user = User.new(user_params.merge(opts))
@user.created_by_id = current_user.id
@user.generate_password
@user.skip_confirmation!
......@@ -62,19 +59,15 @@ class Admin::UsersController < Admin::ApplicationController
end
def update
admin = params[:user].delete("admin")
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
if admin.present?
user.admin = !admin.to_i.zero?
if params[:user][:password].present?
user_params.merge(
password: params[:user][:password],
password_confirmation: params[:user][:password_confirmation],
)
end
respond_to do |format|
if user.update_attributes(params[:user], as: :admin)
if user.update_attributes(user_params)
user.confirm!
format.html { redirect_to [:admin, user], notice: 'User was successfully updated.' }
format.json { head :ok }
......@@ -115,4 +108,13 @@ class Admin::UsersController < Admin::ApplicationController
def user
@user ||= User.find_by!(username: params[:id])
end
def user_params
params.require(:user).permit(
:email, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id, :force_random_password,
:extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key,
:projects_limit, :can_create_group, :admin
)
end
end
require 'gon'
class ApplicationController < ActionController::Base
before_filter :authenticate_user_from_token!
before_filter :authenticate_user!
before_filter :reject_blocked!
before_filter :check_password_expiration
......@@ -28,6 +29,25 @@ class ApplicationController < ActionController::Base
protected
# From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example
# https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
def authenticate_user_from_token!
user_token = if params[:authenticity_token].presence
params[:authenticity_token].presence
elsif params[:private_token].presence
params[:private_token].presence
end
user = user_token && User.find_by_authentication_token(user_token.to_s)
if user
# Notice we are passing store false, so the user is not
# actually stored in the session and a token is needed
# for every request. If you want the token to work as a
# sign in token, you can simply remove store: false.
sign_in user, store: false
end
end
def log_exception(exception)
application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
application_trace.map!{ |t| " #{t}\n" }
......@@ -227,8 +247,7 @@ class ApplicationController < ActionController::Base
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :name, :password, :password_confirmation) }
devise_parameter_sanitizer.sanitize(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me) }
end
def hexdigest(string)
......
class Groups::MilestonesController < ApplicationController
layout 'group'
before_filter :authorize_group_milestone!, only: :update
def index
project_milestones = case params[:status]
when 'all'; status
when 'closed'; status('closed')
else status('active')
end
@group_milestones = Milestones::GroupService.new(project_milestones).execute
@group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(30)
end
def show
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
@group_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
end
def update
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
@group_milestones = Milestones::GroupService.new(project_milestones).milestone(title)
@group_milestones.milestones.each do |milestone|
Milestones::UpdateService.new(milestone.project, current_user, params[:milestone]).execute(milestone)
end
respond_to do |format|
format.js
format.html do
redirect_to group_milestones_path(group)
end
end
end
private
def group
@group ||= Group.find_by(path: params[:group_id])
end
def title
params[:title]
end
def status(state = nil)
conditions = { project_id: group.projects }
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
end
def authorize_group_milestone!
return render_404 unless can?(current_user, :manage_group, group)
end
end
......@@ -22,7 +22,7 @@ class GroupsController < ApplicationController
end
def create
@group = Group.new(params[:group])
@group = Group.new(group_params)
@group.path = @group.name.dup.parameterize if @group.name
if @group.save
......@@ -86,7 +86,7 @@ class GroupsController < ApplicationController
end
def update
if @group.update_attributes(params[:group])
if @group.update_attributes(group_params)
redirect_to edit_group_path(@group), notice: 'Group was successfully updated.'
else
render action: "edit"
......@@ -161,4 +161,8 @@ class GroupsController < ApplicationController
params[:state] = 'opened' if params[:state].blank?
params[:group_id] = @group.id
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :ldap_access, :ldap_cn)
end
end
......@@ -7,7 +7,7 @@ class Profiles::EmailsController < ApplicationController
end
def create
@email = current_user.emails.new(params[:email])
@email = current_user.emails.new(email_params)
flash[:alert] = @email.errors.full_messages.first unless @email.save
......@@ -23,4 +23,10 @@ class Profiles::EmailsController < ApplicationController
format.js { render nothing: true }
end
end
private
def email_params
params.require(:email).permit(:email)
end
end
......@@ -15,7 +15,7 @@ class Profiles::KeysController < ApplicationController
end
def create
@key = current_user.keys.new(params[:key])
@key = current_user.keys.new(key_params)
if @key.save
redirect_to profile_key_path(@key)
......@@ -53,4 +53,9 @@ class Profiles::KeysController < ApplicationController
end
end
private
def key_params
params.require(:key).permit(:title, :key)
end
end
......@@ -11,8 +11,8 @@ class Profiles::PasswordsController < ApplicationController
end
def create
new_password = params[:user][:password]
new_password_confirmation = params[:user][:password_confirmation]
new_password = user_params[:password]
new_password_confirmation = user_params[:password_confirmation]
result = @user.update_attributes(
password: new_password,
......@@ -31,11 +31,11 @@ class Profiles::PasswordsController < ApplicationController
end
def update
password_attributes = params[:user].select do |key, value|
password_attributes = user_params.select do |key, value|
%w(password password_confirmation).include?(key.to_s)
end
unless @user.valid_password?(params[:user][:current_password])
unless @user.valid_password?(user_params[:current_password])
redirect_to edit_profile_password_path, alert: 'You must provide a valid current password'
return
end
......@@ -74,4 +74,8 @@ class Profiles::PasswordsController < ApplicationController
def authorize_change_password!
return render_404 if @user.ldap_user?
end
def user_params
params.require(:user).permit(:current_password, :password, :password_confirmation)
end
end
......@@ -14,9 +14,9 @@ class ProfilesController < ApplicationController
end
def update
params[:user].delete(:email) if @user.ldap_user?
user_params.except!(:email) if @user.ldap_user?
if @user.update_attributes(params[:user])
if @user.update_attributes(user_params)
flash[:notice] = "Profile was successfully updated"
else
flash[:alert] = "Failed to update profile"
......@@ -41,7 +41,7 @@ class ProfilesController < ApplicationController
end
def update_username
@user.update_attributes(username: params[:user][:username])
@user.update_attributes(username: user_params[:username])
respond_to do |format|
format.js
......@@ -57,4 +57,12 @@ class ProfilesController < ApplicationController
def authorize_change_username!
return render_404 unless @user.can_change_username?
end
def user_params
params.require(:user).permit(
:email, :password, :password_confirmation, :bio, :name, :username,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id,
:avatar, :hide_no_ssh_key,
)
end
end
......@@ -30,8 +30,12 @@ class Projects::BlobController < Projects::ApplicationController
def blob
@blob ||= @repository.blob_at(@commit.id, @path)
return not_found! unless @blob
if @blob
@blob
elsif tree.entries.any?
redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
else
return not_found!
end
end
end
......@@ -22,7 +22,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
end
def create
@key = DeployKey.new(params[:deploy_key])
@key = DeployKey.new(deploy_key_params)
if @key.valid? && @project.deploy_keys << @key
redirect_to project_deploy_keys_path(@project)
......@@ -58,4 +58,8 @@ class Projects::DeployKeysController < Projects::ApplicationController
def available_keys
@available_keys ||= current_user.accessible_deploy_keys
end
def deploy_key_params
params.require(:deploy_key).permit(:key, :title)
end
end
......@@ -28,8 +28,6 @@ class Projects::EditTreeController < Projects::BaseTreeController
def preview
@content = params[:content]
#FIXME workaround https://github.com/gitlabhq/gitlabhq/issues/5936
@content += "\n" if @blob.data.end_with?("\n")
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
include_diff_info: true)
......
......@@ -12,7 +12,7 @@ class Projects::HooksController < Projects::ApplicationController
end
def create
@hook = @project.hooks.new(params[:hook])
@hook = @project.hooks.new(hook_params)
@hook.save
if @hook.valid?
......@@ -40,4 +40,8 @@ class Projects::HooksController < Projects::ApplicationController
def hook
@hook ||= @project.hooks.find(params[:id])
end
def hook_params
params.require(:hook).permit(:url, :push_events, :issues_events, :merge_requests_events, :tag_push_events)
end
end
......@@ -42,7 +42,11 @@ class Projects::IssuesController < Projects::ApplicationController
end
def new
@issue = @project.issues.new(params[:issue])
params[:issue] ||= ActionController::Parameters.new(
assignee_id: ""
)
@issue = @project.issues.new(issue_params)
respond_with(@issue)
end
......@@ -59,7 +63,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def create
@issue = Issues::CreateService.new(project, current_user, params[:issue]).execute
@issue = Issues::CreateService.new(project, current_user, issue_params).execute
respond_to do |format|
format.html do
......@@ -76,7 +80,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def update
@issue = Issues::UpdateService.new(project, current_user, params[:issue]).execute(issue)
@issue = Issues::UpdateService.new(project, current_user, issue_params).execute(issue)
respond_to do |format|
format.js
......@@ -144,4 +148,11 @@ class Projects::IssuesController < Projects::ApplicationController
raise ActiveRecord::RecordNotFound.new
end
end
def issue_params
params.require(:issue).permit(
:title, :assignee_id, :position, :description,
:milestone_id, :label_list, :state_event
)
end
end
......@@ -60,7 +60,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def new
@merge_request = MergeRequest.new(params[:merge_request])
params[:merge_request] ||= ActionController::Parameters.new(
source_project: @project
)
@merge_request = MergeRequest.new(merge_request_params)
@merge_request.source_project = @project unless @merge_request.source_project
@merge_request.target_project ||= (@project.forked_from_project || @project)
@target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names
......@@ -111,7 +115,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def create
@target_branches ||= []
@merge_request = MergeRequests::CreateService.new(project, current_user, params[:merge_request]).execute
@merge_request = MergeRequests::CreateService.new(project, current_user, merge_request_params).execute
if @merge_request.valid?
redirect_to project_merge_request_path(@merge_request.target_project, @merge_request), notice: 'Merge request was successfully created.'
......@@ -123,7 +127,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def update
@merge_request = MergeRequests::UpdateService.new(project, current_user, params[:merge_request]).execute(@merge_request)
@merge_request = MergeRequests::UpdateService.new(project, current_user, merge_request_params).execute(@merge_request)
if @merge_request.valid?
respond_to do |format|
......@@ -264,4 +268,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
can?(current_user, action, project)
end
def merge_request_params
params.require(:merge_request).permit(
:title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id,
:state_event, :description, :label_list
)
end
end
......@@ -37,7 +37,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def create
@milestone = Milestones::CreateService.new(project, current_user, params[:milestone]).execute
@milestone = Milestones::CreateService.new(project, current_user, milestone_params).execute
if @milestone.save
redirect_to project_milestone_path(@project, @milestone)
......@@ -47,7 +47,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def update
@milestone = Milestones::UpdateService.new(project, current_user, params[:milestone]).execute(milestone)
@milestone = Milestones::UpdateService.new(project, current_user, milestone_params).execute(milestone)
respond_to do |format|
format.js
......@@ -105,4 +105,8 @@ class Projects::MilestonesController < Projects::ApplicationController
def module_enabled
return render_404 unless @project.issues_enabled
end
def milestone_params
params.require(:milestone).permit(:title, :description, :due_date, :state_event)
end
end
......@@ -21,7 +21,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def create
@note = Notes::CreateService.new(project, current_user, params[:note]).execute
@note = Notes::CreateService.new(project, current_user, note_params).execute
respond_to do |format|
format.json { render_note_json(@note) }
......@@ -30,7 +30,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def update
note.update_attributes(params[:note])
note.update_attributes(note_params)
note.reset_events_cache
respond_to do |format|
......@@ -109,4 +109,11 @@ class Projects::NotesController < Projects::ApplicationController
def authorize_admin_note!
return access_denied! unless can?(current_user, :admin_note, note)
end
def note_params
params.require(:note).permit(
:note, :noteable, :noteable_id, :noteable_type, :project_id,
:attachment, :line_code, :commit_id
)
end
end
......@@ -11,7 +11,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
end
def create
@project.protected_branches.create(params[:protected_branch])
@project.protected_branches.create(protected_branch_params)
redirect_to project_protected_branches_path(@project)
end
......@@ -23,4 +23,10 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
format.js { render nothing: true }
end
end
private
def protected_branch_params
params.require(:protected_branch).permit(:name)
end
end
......@@ -22,6 +22,7 @@ class Projects::RepositoriesController < Projects::ApplicationController
if file_path
# Send file to user
response.headers["Content-Length"] = File.open(file_path).size.to_s
send_file file_path
else
render_404
......
......@@ -16,7 +16,7 @@ class Projects::ServicesController < Projects::ApplicationController
end
def update
if @service.update_attributes(params[:service])
if @service.update_attributes(service_params)
redirect_to edit_project_service_path(@project, @service.to_param)
else
render 'edit'
......@@ -36,4 +36,11 @@ class Projects::ServicesController < Projects::ApplicationController
def service
@service ||= @project.services.find { |service| service.to_param == params[:id] }
end
def service_params
params.require(:service).permit(
:title, :token, :type, :active, :api_key, :subdomain,
:room, :recipients, :project_url
)
end
end
......@@ -25,7 +25,7 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def create
@snippet = @project.snippets.build(params[:project_snippet])
@snippet = @project.snippets.build(snippet_params)
@snippet.author = current_user
if @snippet.save
......@@ -39,7 +39,7 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def update
if @snippet.update_attributes(params[:project_snippet])
if @snippet.update_attributes(snippet_params)
redirect_to project_snippet_path(@project, @snippet)
else
respond_with(@snippet)
......@@ -86,4 +86,8 @@ class Projects::SnippetsController < Projects::ApplicationController
def module_enabled
return render_404 unless @project.snippets_enabled
end
def snippet_params
params.require(:project_snippet).permit(:title, :content, :file_name, :private)
end
end
......@@ -27,7 +27,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
def update
@user_project_relation = project.users_projects.find_by(user_id: member)
@user_project_relation.update_attributes(params[:team_member])
@user_project_relation.update_attributes(member_params)
unless @user_project_relation.valid?
flash[:alert] = "User should have at least one role"
......@@ -67,4 +67,8 @@ class Projects::TeamMembersController < Projects::ApplicationController
def member
@member ||= User.find_by(username: params[:id])
end
def member_params
params.require(:team_member).permit(:user_id, :project_access)
end
end
# Controller for viewing a repository's file structure
class Projects::TreeController < Projects::BaseTreeController
def show
return not_found! if tree.entries.empty?
if tree.entries.empty?
if @repository.blob_at(@commit.id, @path)
redirect_to project_blob_path(@project, File.join(@ref, @path)) and return
else
return not_found!
end
end
respond_to do |format|
format.html
......
......@@ -20,7 +20,7 @@ class ProjectsController < ApplicationController
end
def create
@project = ::Projects::CreateService.new(current_user, params[:project]).execute
@project = ::Projects::CreateService.new(current_user, project_params).execute
flash[:notice] = 'Project was successfully created.' if @project.saved?
respond_to do |format|
......@@ -29,7 +29,7 @@ class ProjectsController < ApplicationController
end
def update
status = ::Projects::UpdateService.new(@project, current_user, params).execute
status = ::Projects::UpdateService.new(@project, current_user, project_params).execute
respond_to do |format|
if status
......@@ -44,7 +44,7 @@ class ProjectsController < ApplicationController
end
def transfer
::Projects::TransferService.new(project, current_user, params[:project]).execute
::Projects::TransferService.new(project, current_user, project_params).execute
end
def show
......@@ -85,7 +85,7 @@ class ProjectsController < ApplicationController
redirect_to import_project_path(@project)
end
@project.import_url = params[:project][:import_url]
@project.import_url = project_params[:import_url]
if @project.save
@project.reload
......@@ -185,4 +185,12 @@ class ProjectsController < ApplicationController
def user_layout
current_user ? "projects" : "public_projects"
end
def project_params
params.require(:project).permit(
:name, :path, :description, :issues_tracker, :label_list,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :merge_requests_template
)
end
end
......@@ -13,7 +13,14 @@ class RegistrationsController < Devise::RegistrationsController
def build_resource(hash=nil)
super
self.resource.with_defaults
end
def after_sign_up_path_for resource
new_user_session_path
end
def after_inactive_sign_up_path_for resource
new_user_session_path
end
private
......@@ -21,4 +28,8 @@ class RegistrationsController < Devise::RegistrationsController
def signup_enabled?
redirect_to new_user_session_path unless Gitlab.config.gitlab.signup_enabled
end
def sign_up_params
params.require(:user).permit(:username, :email, :name, :password, :password_confirmation)
end
end
......@@ -51,7 +51,7 @@ class SnippetsController < ApplicationController
end
def create
@snippet = PersonalSnippet.new(params[:personal_snippet])
@snippet = PersonalSnippet.new(snippet_params)
@snippet.author = current_user
if @snippet.save
......@@ -65,7 +65,7 @@ class SnippetsController < ApplicationController
end
def update
if @snippet.update_attributes(params[:personal_snippet])
if @snippet.update_attributes(snippet_params)
redirect_to snippet_path(@snippet)
else
respond_with @snippet
......@@ -109,4 +109,8 @@ class SnippetsController < ApplicationController
def set_title
@title = 'Snippets'
end
def snippet_params
params.require(:personal_snippet).permit(:title, :content, :file_name, :private)
end
end
......@@ -14,7 +14,7 @@ class UsersGroupsController < ApplicationController
def update
@member = @group.users_groups.find(params[:id])
@member.update_attributes(params[:users_group])
@member.update_attributes(member_params)
end
def destroy
......@@ -41,4 +41,8 @@ class UsersGroupsController < ApplicationController
return render_404
end
end
def member_params
params.require(:users_group).permit(:group_access, :user_id)
end
end
......@@ -14,7 +14,7 @@ class NotesFinder
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"
when "snippet", "project_snippet"
project.snippets.find(target_id).notes.fresh
else
raise 'invalid target_type'
......
......@@ -180,6 +180,17 @@ module CommitsHelper
return old_lines, new_lines
end
def link_to_browse_code(project, commit)
if current_controller?(:projects, :commits)
if @repo.blob_at(commit.id, @path)
return link_to "Browse File »", project_blob_path(project, tree_join(commit.id, @path)), class: "pull-right"
elsif @path.present?
return link_to "Browse Dir »", project_tree_path(project, tree_join(commit.id, @path)), class: "pull-right"
end
end
link_to "Browse Code »", project_tree_path(project, commit), class: "pull-right"
end
protected
# Private: Returns a link to a person. If the person has a matching user and
......
......@@ -35,4 +35,42 @@ module DashboardHelper
path << "?#{options.to_param}"
path
end
def assigned_entities_count(current_user, entity, scope = nil)
items = current_user.send("assigned_" + entity.pluralize).opened
if scope.kind_of?(Group)
items = items.of_group(scope)
elsif scope.kind_of?(Project)
items = items.of_projects(scope)
end
items.count
end
def authored_entities_count(current_user, entity, scope = nil)
items = current_user.send(entity.pluralize).opened
if scope.kind_of?(Group)
items = items.of_group(scope)
elsif scope.kind_of?(Project)
items = items.of_projects(scope)
end
items.count
end
def authorized_entities_count(current_user, entity, scope = nil)
items = entity.classify.constantize.opened
if scope.kind_of?(Group)
items = items.of_group(scope)
elsif scope.kind_of?(Project)
items = items.of_projects(scope)
else
items = items.of_projects(current_user.authorized_projects)
end
items.count
end
end
......@@ -64,7 +64,16 @@ module EventsHelper
project_issue_url(event.project, event.issue)
elsif event.merge_request?
project_merge_request_url(event.project, event.merge_request)
elsif event.note?
if event.note_target
if event.note_commit?
project_commit_path(event.project, event.note_commit_id, anchor: dom_id(event.target))
elsif event.note_project_snippet?
project_snippet_path(event.project, event.note_target)
else
event_note_target_path(event)
end
end
elsif event.push?
if event.push_with_commits?
if event.commits_count > 1
......@@ -83,6 +92,10 @@ module EventsHelper
render "events/event_issue", issue: event.issue
elsif event.push?
render "events/event_push", event: event
elsif event.merge_request?
render "events/event_merge_request", merge_request: event.merge_request
elsif event.note?
render "events/event_note", note: event.note
end
end
......
......@@ -138,7 +138,7 @@ module GitlabMarkdownHelper
# If we are at doc/api/README.md and the README.md contains relative links like [Users](users.md)
# this takes the request path(doc/api/README.md), and replaces the README.md with users.md so the path looks like doc/api/users.md
# If we are at doc/api and the README.md shown in below the tree view
# this takes the rquest path(doc/api) and adds users.md so the path looks like doc/api/users.md
# this takes the request path(doc/api) and adds users.md so the path looks like doc/api/users.md
def build_nested_path(path, request_path)
return request_path if path == ""
return path unless request_path
......
......@@ -31,6 +31,17 @@ module GroupsHelper
end
title
end
def group_filter_path(entity, options={})
exist_opts = {
status: params[:status]
}
options = exist_opts.merge(options)
path = request.path
path << "?#{options.to_param}"
path
end
end
......@@ -4,8 +4,8 @@ module Emails
@issue = Issue.find(issue_id)
@project = @issue.project
@target_url = project_issue_url(@project, @issue)
set_message_id("issue_#{issue_id}")
mail(from: sender(@issue.author_id),
mail_new_thread(@issue,
from: sender(@issue.author_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......@@ -15,8 +15,8 @@ module Emails
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @issue.project
@target_url = project_issue_url(@project, @issue)
set_reference("issue_#{issue_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......@@ -26,8 +26,8 @@ module Emails
@project = @issue.project
@updated_by = User.find updated_by_user_id
@target_url = project_issue_url(@project, @issue)
set_reference("issue_#{issue_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......@@ -38,8 +38,8 @@ module Emails
@project = @issue.project
@updated_by = User.find updated_by_user_id
@target_url = project_issue_url(@project, @issue)
set_reference("issue_#{issue_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......
......@@ -4,8 +4,8 @@ module Emails
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request)
set_message_id("merge_request_#{merge_request_id}")
mail(from: sender(@merge_request.author_id),
mail_new_thread(@merge_request,
from: sender(@merge_request.author_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
......@@ -15,8 +15,8 @@ module Emails
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request)
set_reference("merge_request_#{merge_request_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
......@@ -26,8 +26,8 @@ module Emails
@updated_by = User.find updated_by_user_id
@project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request)
set_reference("merge_request_#{merge_request_id}")
mail(from: sender(updated_by_user_id),
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
......@@ -36,10 +36,22 @@ module Emails
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request)
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id)
@mr_status = status
@project = @merge_request.project
@updated_by = User.find updated_by_user_id
@target_url = project_merge_request_url(@project, @merge_request)
set_reference("merge_request_#{merge_request_id}")
mail(from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
subject: subject("#{@merge_request.title} (##{@merge_request.iid}) #{@mr_status}"))
end
end
......
......@@ -5,7 +5,8 @@ module Emails
@commit = @note.noteable
@project = @note.project
@target_url = project_commit_url(@project, @commit, anchor: "note_#{@note.id}")
mail(from: sender(@note.author_id),
mail_answer_thread(@commit,
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@commit.title} (#{@commit.short_id})"))
end
......@@ -15,8 +16,8 @@ module Emails
@issue = @note.noteable
@project = @note.project
@target_url = project_issue_url(@project, @issue, anchor: "note_#{@note.id}")
set_reference("issue_#{@issue.id}")
mail(from: sender(@note.author_id),
mail_answer_thread(@issue,
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
end
......@@ -26,8 +27,8 @@ module Emails
@merge_request = @note.noteable
@project = @note.project
@target_url = project_merge_request_url(@project, @merge_request, anchor: "note_#{@note.id}")
set_reference("merge_request_#{@merge_request.id}")
mail(from: sender(@note.author_id),
mail_answer_thread(@merge_request,
from: sender(@note.author_id),
to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
......
class Notify < ActionMailer::Base
include ActionDispatch::Routing::PolymorphicRoutes
include Emails::Issues
include Emails::MergeRequests
include Emails::Notes
......@@ -53,14 +55,6 @@ class Notify < ActionMailer::Base
end
end
# Set the Message-ID header field
#
# local_part - The local part of the message ID
#
def set_message_id(local_part)
headers["Message-ID"] = "<#{local_part}@#{Gitlab.config.gitlab.host}>"
end
# Set the References header field
#
# local_part - The local part of the referenced message ID
......@@ -93,4 +87,40 @@ class Notify < ActionMailer::Base
subject << extra.join(' | ') if extra.present?
subject
end
# Return a string suitable for inclusion in the 'Message-Id' mail header.
#
# The message-id is generated from the unique URL to a model object.
def message_id(model)
model_name = model.class.model_name.singular_route_key
"<#{model_name}_#{model.id}@#{Gitlab.config.gitlab.host}>"
end
# Send an email that starts a new conversation thread,
# with headers suitable for grouping by thread in email clients.
#
# See: mail_answer_thread
def mail_new_thread(model, headers = {}, &block)
headers['Message-ID'] = message_id(model)
mail(headers, &block)
end
# Send an email that responds to an existing conversation thread,
# with headers suitable for grouping by thread in email clients.
#
# For grouping emails by thread, email clients heuristics require the answers to:
#
# * have a subject that begin by 'Re: '
# * have a 'In-Reply-To' or 'References' header that references the original 'Message-ID'
#
def mail_answer_thread(model, headers = {}, &block)
headers['In-Reply-To'] = message_id(model)
headers['References'] = message_id(model)
if (headers[:subject])
headers[:subject].prepend('Re: ')
end
mail(headers, &block)
end
end
......@@ -14,8 +14,6 @@
#
class BroadcastMessage < ActiveRecord::Base
attr_accessible :alert_type, :color, :ends_at, :font, :message, :starts_at
validates :message, presence: true
validates :starts_at, presence: true
validates :ends_at, presence: true
......
module TokenAuthenticatable
extend ActiveSupport::Concern
module ClassMethods
def find_by_authentication_token(authentication_token = nil)
if authentication_token
where(authentication_token: authentication_token).first
end
end
end
def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end
def reset_authentication_token!
self.authentication_token = generate_authentication_token
save
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless self.class.unscoped.where(authentication_token: token).first
end
end
end
......@@ -10,13 +10,10 @@
#
class DeployKeysProject < ActiveRecord::Base
attr_accessible :key_id, :project_id
belongs_to :project
belongs_to :deploy_key
validates :deploy_key_id, presence: true
validates :deploy_key_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
validates :project_id, presence: true
end
......@@ -10,16 +10,8 @@
#
class Email < ActiveRecord::Base
attr_accessible :email, :user_id
#
# Relations
#
belongs_to :user
#
# Validations
#
validates :user_id, presence: true
validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
validate :unique_email, if: ->(email) { email.email_changed? }
......
......@@ -15,9 +15,6 @@
#
class Event < ActiveRecord::Base
attr_accessible :project, :action, :data, :author_id, :project_id,
:target_id, :target_type
default_scope { where.not(author_id: nil) }
CREATED = 1
......@@ -33,6 +30,7 @@ class Event < ActiveRecord::Base
delegate :name, :email, to: :author, prefix: true, allow_nil: true
delegate :title, to: :issue, prefix: true, allow_nil: true
delegate :title, to: :merge_request, prefix: true, allow_nil: true
delegate :title, to: :note, prefix: true, allow_nil: true
belongs_to :author, class_name: "User"
belongs_to :project
......@@ -150,6 +148,10 @@ class Event < ActiveRecord::Base
target if target_type == "MergeRequest"
end
def note
target if target_type == "Note"
end
def action_name
if closed?
"closed"
......
......@@ -10,10 +10,6 @@
#
class ForkedProjectLink < ActiveRecord::Base
attr_accessible :forked_from_project_id, :forked_to_project_id
# Relations
belongs_to :forked_to_project, class_name: Project
belongs_to :forked_from_project, class_name: Project
end
......@@ -19,19 +19,14 @@ require 'file_size_validator'
class Group < Namespace
has_many :users_groups, dependent: :destroy
has_many :users, through: :users_groups
has_many :project_group_links, dependent: :destroy
has_many :shared_projects, through: :project_group_links, source: :project
attr_accessible :ldap_cn, :ldap_access
validates :ldap_access,
inclusion: { in: UsersGroup.group_access_roles.values },
presence: true,
if: ->(group) { group.ldap_cn.present? }
attr_accessible :avatar
validate :avatar_type, if: ->(user) { user.avatar_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
......
class GroupMilestone
def initialize(title, milestones)
@title = title
@milestones = milestones
end
def title
@title
end
def safe_title
@title.parameterize
end
def milestones
@milestones
end
def projects
milestones.map { |milestone| milestone.project }
end
def issue_count
milestones.map { |milestone| milestone.issues.count }.sum
end
def merge_requests_count
milestones.map { |milestone| milestone.merge_requests.count }.sum
end
def open_items_count
milestones.map { |milestone| milestone.open_items_count }.sum
end
def closed_items_count
milestones.map { |milestone| milestone.closed_items_count }.sum
end
def total_items_count
milestones.map { |milestone| milestone.total_items_count }.sum
end
def percent_complete
((closed_items_count * 100) / total_items_count).abs
rescue ZeroDivisionError
100
end
def state
state = milestones.map { |milestone| milestone.state }
if state.count('active') == state.size
'active'
else
'closed'
end
end
def active?
state == 'active'
end
def closed?
state == 'closed'
end
def issues
@group_issues ||= milestones.map { |milestone| milestone.issues }.flatten.group_by(&:state)
end
def merge_requests
@group_merge_requests ||= milestones.map { |milestone| milestone.merge_requests }.flatten.group_by(&:state)
end
def participants
milestones.map { |milestone| milestone.participants.uniq }.reject(&:empty?).flatten
end
def opened_issues
issues.values_at("opened", "reopened").compact.flatten
end
def closed_issues
issues['closed']
end
def opened_merge_requests
merge_requests.values_at("opened", "reopened").compact.flatten
end
def closed_merge_requests
merge_requests.values_at("closed", "merged", "locked").compact.flatten
end
end
......@@ -33,9 +33,6 @@ class Issue < ActiveRecord::Base
scope :of_group, ->(group) { where(project_id: group.project_ids) }
scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) }
attr_accessible :title, :assignee_id, :position, :description,
:milestone_id, :label_list, :state_event
acts_as_taggable_on :labels
scope :cared, ->(user) { where(assignee_id: user) }
......
......@@ -19,8 +19,6 @@ class Key < ActiveRecord::Base
belongs_to :user
attr_accessible :key, :title
before_validation :strip_white_space, :generate_fingerpint
validates :title, presence: true, length: { within: 0..255 }
......
......@@ -36,10 +36,6 @@ class MergeRequest < ActiveRecord::Base
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
attr_accessible :title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id,
:state_event, :description, :label_list
attr_accessor :should_remove_source_branch
# When this attribute is true some MR validation is ignored
......@@ -62,11 +58,11 @@ class MergeRequest < ActiveRecord::Base
transition closed: :reopened
end
event :lock do
event :lock_mr do
transition [:reopened, :opened] => :locked
end
event :unlock do
event :unlock_mr do
transition locked: :reopened
end
......@@ -297,6 +293,8 @@ class MergeRequest < ActiveRecord::Base
message << title.to_s
message << "\n\n"
message << description.to_s
message << "\n\n"
message << "See merge request !#{iid}"
message
end
......
......@@ -22,8 +22,6 @@ class MergeRequestDiff < ActiveRecord::Base
belongs_to :merge_request
attr_accessible :state, :st_commits, :st_diffs
delegate :target_branch, :source_branch, to: :merge_request, prefix: nil
state_machine :state, initial: :empty do
......
......@@ -16,8 +16,6 @@
class Milestone < ActiveRecord::Base
include InternalId
attr_accessible :title, :description, :due_date, :state_event
belongs_to :project
has_many :issues
has_many :merge_requests
......
......@@ -16,8 +16,6 @@
class Namespace < ActiveRecord::Base
include Gitlab::ShellAdapter
attr_accessible :name, :description, :path
has_many :projects, dependent: :destroy
belongs_to :owner, class_name: "User"
......@@ -25,12 +23,12 @@ class Namespace < ActiveRecord::Base
validates :name, presence: true, uniqueness: true,
length: { within: 0..255 },
format: { with: Gitlab::Regex.name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed." }
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: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
message: Gitlab::Regex.path_regex_message }
delegate :name, to: :owner, allow_nil: true, prefix: true
......
......@@ -25,8 +25,6 @@ class Note < ActiveRecord::Base
default_value_for :system, false
attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id,
:attachment, :line_code, :commit_id
attr_mentionable :note
belongs_to :project
......@@ -63,13 +61,13 @@ class Note < ActiveRecord::Base
def create_status_change_note(noteable, project, author, status, source)
body = "_Status changed to #{status}#{' by ' + source.gfm_reference if source}_"
create({
create(
noteable: noteable,
project: project,
author: author,
note: body,
system: true
}, without_protection: true)
)
end
# +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note.
......@@ -88,7 +86,7 @@ class Note < ActiveRecord::Base
note_options.merge!(noteable: noteable)
end
create(note_options, without_protection: true)
create(note_options)
end
def create_milestone_change_note(noteable, project, author, milestone)
......@@ -98,13 +96,13 @@ class Note < ActiveRecord::Base
"_Milestone changed to #{milestone.title}_"
end
create({
create(
noteable: noteable,
project: project,
author: author,
note: body,
system: true
}, without_protection: true)
)
end
def create_assignee_change_note(noteable, project, author, assignee)
......@@ -116,7 +114,7 @@ class Note < ActiveRecord::Base
author: author,
note: body,
system: true
}, without_protection: true)
})
end
def discussions_from_notes(notes)
......
......@@ -27,24 +27,20 @@
class Project < ActiveRecord::Base
include Gitlab::ShellAdapter
include Gitlab::VisibilityLevel
include Gitlab::ConfigHelper
extend Gitlab::ConfigHelper
extend Enumerize
default_value_for :archived, false
default_value_for :issues_enabled, true
default_value_for :merge_requests_enabled, true
default_value_for :wiki_enabled, true
default_value_for :visibility_level, gitlab_config_features.visibility_level
default_value_for :issues_enabled, gitlab_config_features.issues
default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests
default_value_for :wiki_enabled, gitlab_config_features.wiki
default_value_for :wall_enabled, false
default_value_for :snippets_enabled, true
default_value_for :snippets_enabled, gitlab_config_features.snippets
ActsAsTaggableOn.strict_case_match = true
attr_accessible :name, :path, :description, :issues_tracker, :label_list,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at,
:merge_requests_template, as: [:default, :admin]
attr_accessible :namespace_id, :creator_id, as: :admin
acts_as_taggable_on :labels, :issues_default_labels
attr_accessor :new_default_branch
......@@ -101,13 +97,16 @@ class Project < ActiveRecord::Base
validates :description, length: { maximum: 2000 }, allow_blank: true
validates :name, presence: true, length: { within: 0..255 },
format: { with: Gitlab::Regex.project_name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed. Letter or digit should be first" }
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: "only letters, digits & '_' '-' '.' allowed. Letter or digit should be first" }
message: Gitlab::Regex.path_regex_message }
validates :issues_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] }
validates :visibility_level,
exclusion: { in: gitlab_config.restricted_visibility_levels },
if: -> { gitlab_config.restricted_visibility_levels.any? }
validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true
validates :namespace, presence: true
validates_uniqueness_of :name, scope: :namespace_id
......@@ -251,7 +250,7 @@ class Project < ActiveRecord::Base
end
def check_limit
unless creator.can_create_project?
unless creator.can_create_project? or namespace.kind == 'group'
errors[:limit_reached] << ("Your project limit is #{creator.projects_limit} projects! Please contact your administrator to increase it")
end
rescue
......@@ -263,7 +262,7 @@ class Project < ActiveRecord::Base
end
def web_url
[Gitlab.config.gitlab.url, path_with_namespace].join("/")
[gitlab_config.url, path_with_namespace].join("/")
end
def web_url_without_protocol
......@@ -403,7 +402,11 @@ class Project < ActiveRecord::Base
services.each do |service|
# Call service hook only if it is active
begin
service.execute(data) if service.active
rescue => e
logger.error(e)
end
end
end
......@@ -488,7 +491,7 @@ class Project < ActiveRecord::Base
end
def http_url_to_repo
[Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
[gitlab_config.url, "/", path_with_namespace, ".git"].join('')
end
# Check if current branch name is marked as protected in the system
......
......@@ -18,8 +18,6 @@
class ProjectHook < WebHook
belongs_to :project
attr_accessible :push_events, :issues_events, :merge_requests_events, :tag_push_events
scope :push_hooks, -> { where(push_events: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true) }
scope :issue_hooks, -> { where(issues_events: true) }
......
......@@ -18,8 +18,6 @@
#
class AssemblaService < Service
attr_accessible :subdomain
include HTTParty
validates :token, presence: true, if: :activated?
......
......@@ -18,8 +18,6 @@
#
class CampfireService < Service
attr_accessible :subdomain, :room
validates :token, presence: true, if: :activated?
def title
......
......@@ -18,8 +18,6 @@
#
class EmailsOnPushService < Service
attr_accessible :recipients
validates :recipients, presence: true, if: :activated?
def title
......
......@@ -18,8 +18,6 @@
#
class GitlabCiService < CiService
attr_accessible :project_url
validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
......
......@@ -18,8 +18,6 @@
#
class HipchatService < Service
attr_accessible :room
validates :token, presence: true, if: :activated?
def title
......
......@@ -18,9 +18,6 @@
#
class SlackService < Service
attr_accessible :room
attr_accessible :subdomain
validates :room, presence: true, if: :activated?
validates :subdomain, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
......
......@@ -12,8 +12,6 @@
class ProtectedBranch < ActiveRecord::Base
include Gitlab::ShellAdapter
attr_accessible :name
belongs_to :project
validates :name, presence: true
validates :project, presence: true
......
......@@ -242,4 +242,25 @@ class Repository
branches
end
end
def contributors
log = graph_log.group_by { |i| i[:author_email] }
log.map do |email, contributions|
contributor = Gitlab::Contributor.new
contributor.email = email
contributions.each do |contribution|
if contributor.name.blank?
contributor.name = contribution[:author_name]
end
contributor.commits += 1
contributor.additions += contribution[:additions] || 0
contributor.deletions += contribution[:deletions] || 0
end
contributor
end
end
end
......@@ -22,8 +22,6 @@
class Service < ActiveRecord::Base
default_value_for :active, false
attr_accessible :title, :token, :type, :active, :api_key
belongs_to :project
has_one :service_hook
......
......@@ -18,8 +18,6 @@
class Snippet < ActiveRecord::Base
include Linguist::BlobHelper
attr_accessible :title, :content, :file_name, :expires_at, :private
default_value_for :private, true
belongs_to :author, class_name: "User"
......
......@@ -50,31 +50,25 @@ require 'carrierwave/orm/activerecord'
require 'file_size_validator'
class User < ActiveRecord::Base
include Gitlab::ConfigHelper
extend Gitlab::ConfigHelper
include TokenAuthenticatable
default_value_for :admin, false
default_value_for :can_create_group, true
default_value_for :can_create_group, gitlab_config.default_can_create_group
default_value_for :can_create_team, false
default_value_for :hide_no_ssh_key, false
default_value_for :projects_limit, gitlab_config.default_projects_limit
default_value_for :theme_id, gitlab_config.default_theme
devise :database_authenticatable, :token_authenticatable, :lockable, :async,
devise :database_authenticatable, :lockable, :async,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id, :force_random_password,
:extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key,
as: [:default, :admin]
attr_accessible :projects_limit, :can_create_group,
as: :admin
attr_accessor :force_random_password
# Virtual attribute for authenticating by either username or email
attr_accessor :login
# Add login to attr_accessible
attr_accessible :login
#
# Relations
#
......@@ -120,7 +114,7 @@ class User < ActiveRecord::Base
validates :username, presence: true, uniqueness: { case_sensitive: false },
exclusion: { in: Gitlab::Blacklist.path },
format: { with: Gitlab::Regex.username_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
message: Gitlab::Regex.username_regex_message }
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
......@@ -223,20 +217,8 @@ class User < ActiveRecord::Base
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
end
def build_user(attrs = {}, options= {})
if options[:as] == :admin
User.new(defaults.merge(attrs.symbolize_keys), options)
else
User.new(attrs, options).with_defaults
end
end
def defaults
{
projects_limit: Gitlab.config.gitlab.default_projects_limit,
can_create_group: Gitlab.config.gitlab.default_can_create_group,
theme_id: Gitlab.config.gitlab.default_theme
}
def build_user(attrs = {})
User.new(attrs)
end
end
......@@ -315,7 +297,7 @@ class User < ActiveRecord::Base
end
def can_change_username?
Gitlab.config.gitlab.username_changing_enabled
gitlab_config.username_changing_enabled
end
def can_create_project?
......@@ -490,7 +472,7 @@ class User < ActiveRecord::Base
def avatar_url(size = nil)
if avatar.present?
URI::join(Gitlab.config.gitlab.url, avatar.url).to_s
URI::join(gitlab_config.url, avatar.url).to_s
else
GravatarService.new.execute(email, size)
end
......
......@@ -19,8 +19,6 @@ class UsersGroup < ActiveRecord::Base
Gitlab::Access.options_with_owner
end
attr_accessible :group_access, :user_id
belongs_to :user
belongs_to :group
......
......@@ -16,8 +16,6 @@ class UsersProject < ActiveRecord::Base
include Notifiable
include Gitlab::Access
attr_accessible :user, :user_id, :project_access
belongs_to :user
belongs_to :project
......@@ -126,7 +124,7 @@ class UsersProject < ActiveRecord::Base
author_id: self.user.id
)
notification_service.new_team_member(self)
notification_service.new_team_member(self) unless owner?
system_hook_service.execute_hooks_for(self, :create)
end
......
......@@ -22,8 +22,6 @@ class WebHook < ActiveRecord::Base
default_value_for :issues_events, false
default_value_for :merge_requests_events, false
attr_accessible :url
# HTTParty timeout
default_timeout 10
......
......@@ -25,7 +25,10 @@ module Files
file_path = path
unless file_name =~ Gitlab::Regex.path_regex
return error("Your changes could not be committed, because file name contains not allowed characters")
return error(
'Your changes could not be committed, because the file name ' +
Gitlab::Regex.path_regex_message
)
end
blob = repository.blob_at_branch(ref, file_path)
......
......@@ -4,6 +4,7 @@ module Issues
if issue.reopen
event_service.reopen_issue(issue, current_user)
create_note(issue)
notification_service.reopen_issue(issue, current_user)
execute_hooks(issue, 'reopen')
end
......
module Issues
class UpdateService < Issues::BaseService
def execute(issue)
state = params.delete('state_event') || params.delete(:state_event)
state = params[:state_event]
case state
when 'reopen'
......@@ -10,7 +10,7 @@ module Issues
Issues::CloseService.new(project, current_user, {}).execute(issue)
end
if params.present? && issue.update_attributes(params)
if params.present? && issue.update_attributes(params.except(:state_event))
issue.reset_events_cache
if issue.previous_changes.include?('milestone_id')
......
......@@ -6,7 +6,7 @@ module MergeRequests
# Called when you do merge via GitLab UI
class AutoMergeService < BaseMergeService
def execute(merge_request, current_user, commit_message)
merge_request.lock
merge_request.lock_mr
if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
merge_request.merge
......@@ -17,11 +17,11 @@ module MergeRequests
true
else
merge_request.unlock
merge_request.unlock_mr
false
end
rescue
merge_request.unlock if merge_request.locked?
merge_request.unlock_mr if merge_request.locked?
merge_request.mark_as_unmergeable
false
end
......
......@@ -3,6 +3,7 @@ module MergeRequests
def execute(merge_request)
if merge_request.reopen
event_service.reopen_mr(merge_request, current_user)
notification_service.reopen_mr(merge_request, current_user)
create_note(merge_request)
execute_hooks(merge_request)
merge_request.reload_code
......
......@@ -7,10 +7,10 @@ module MergeRequests
def execute(merge_request)
# We dont allow change of source/target projects
# after merge request was created
params.delete(:source_project_id)
params.delete(:target_project_id)
params.except!(:source_project_id)
params.except!(:target_project_id)
state = params.delete('state_event') || params.delete(:state_event)
state = params[:state_event]
case state
when 'reopen'
......@@ -19,7 +19,7 @@ module MergeRequests
MergeRequests::CloseService.new(project, current_user, {}).execute(merge_request)
end
if params.present? && merge_request.update_attributes(params)
if params.present? && merge_request.update_attributes(params.except(:state_event))
merge_request.reset_events_cache
if merge_request.previous_changes.include?('milestone_id')
......
module Milestones
class GroupService < Milestones::BaseService
def initialize(project_milestones)
@project_milestones = project_milestones.group_by(&:title)
end
def execute
build(@project_milestones)
end
def milestone(title)
if title
group_milestone = @project_milestones[title].group_by(&:title)
build(group_milestone).first
else
nil
end
end
private
def build(milestone)
milestone.map{ |title, milestones| GroupMilestone.new(title, milestones) }
end
end
end
module Milestones
class UpdateService < Milestones::BaseService
def execute(milestone)
state = params.delete('state_event') || params.delete(:state_event)
state = params[:state_event]
case state
when 'activate'
......@@ -11,7 +11,7 @@ module Milestones
end
if params.present?
milestone.update_attributes(params)
milestone.update_attributes(params.except(:state_event))
end
milestone
......
......@@ -80,6 +80,10 @@ class NotificationService
close_resource_email(merge_request, merge_request.target_project, current_user, 'closed_merge_request_email')
end
def reopen_issue(issue, current_user)
reopen_resource_email(issue, issue.project, current_user, 'issue_status_changed_email', 'reopened')
end
# When we merge a merge request we should send next emails:
#
# * merge_request author if their notification level is not Disabled
......@@ -89,12 +93,17 @@ class NotificationService
def merge_mr(merge_request, current_user)
recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project)
recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
recipients.delete(current_user)
recipients.each do |recipient|
mailer.merged_merge_request_email(recipient.id, merge_request.id, current_user.id)
end
end
def reopen_mr(merge_request, current_user)
reopen_resource_email(merge_request, merge_request.target_project, current_user, 'merge_request_status_email', 'reopened')
end
# Notify new user with email after creation
def new_user(user)
# Don't email omniauth created users
......@@ -301,7 +310,9 @@ class NotificationService
end
def reassign_resource_email(target, project, current_user, method)
recipients = User.where(id: [target.assignee_id, target.assignee_id_was])
assignee_id_was = previous_record(target, "assignee_id")
recipients = User.where(id: [target.assignee_id, assignee_id_was])
# Add watchers to email list
recipients = recipients.concat(project_watchers(project))
......@@ -313,11 +324,29 @@ class NotificationService
recipients.delete(current_user)
recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, target.assignee_id_was, current_user.id)
mailer.send(method, recipient.id, target.id, assignee_id_was, current_user.id)
end
end
def reopen_resource_email(target, project, current_user, method, status)
recipients = reject_muted_users([target.author, target.assignee], project)
recipients = recipients.concat(project_watchers(project)).uniq
recipients.delete(current_user)
recipients.each do |recipient|
mailer.send(method, recipient.id, target.id, status, current_user.id)
end
end
def mailer
Notify.delay
end
def previous_record(object, attribute)
if object && attribute
if object.previous_changes.include?(attribute)
object.previous_changes[attribute].first
end
end
end
end
......@@ -5,27 +5,13 @@ module Projects
end
def execute
# get namespace id
namespace_id = params.delete(:namespace_id)
@project = Project.new(params)
# check that user is allowed to set specified visibility_level
# Reset visibility levet if is not allowed to set it
unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
params.delete(:visibility_level)
@project.visibility_level = default_features.visibility_level
end
# Load default feature settings
default_features = Gitlab.config.gitlab.default_projects_features
default_opts = {
issues_enabled: default_features.issues,
wiki_enabled: default_features.wiki,
snippets_enabled: default_features.snippets,
merge_requests_enabled: default_features.merge_requests,
visibility_level: default_features.visibility_level
}.stringify_keys
@project = Project.new(default_opts.merge(params))
# Parametrize path for project
#
# Ex.
......@@ -33,13 +19,14 @@ module Projects
#
@project.path = @project.name.dup.parameterize unless @project.path.present?
# get namespace id
namespace_id = params[:namespace_id]
if namespace_id
# Find matching namespace and check if it allowed
# for current user if namespace_id passed.
if allowed_namespace?(current_user, namespace_id)
@project.namespace_id = namespace_id
else
unless allowed_namespace?(current_user, namespace_id)
@project.namespace_id = nil
deny_namespace
return @project
end
......
......@@ -12,7 +12,7 @@ module Projects
class TransferError < StandardError; end
def execute
namespace_id = params.delete(:namespace_id)
namespace_id = params[:namespace_id]
namespace = Namespace.find_by(id: namespace_id)
if allowed_transfer?(current_user, project, namespace)
......
module Projects
class UpdateService < BaseService
def execute(role = :default)
params[:project].delete(:namespace_id)
def execute
# check that user is allowed to set specified visibility_level
unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:project][:visibility_level])
params[:project].delete(:visibility_level)
unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
params[:visibility_level] = project.visibility_level
end
new_branch = params[:project].delete(:default_branch)
new_branch = params[:default_branch]
if project.repository.exists? && new_branch && new_branch != project.default_branch
project.change_head(new_branch)
end
if project.update_attributes(params[:project], as: role)
if project.previous_changes.include?('namespace_id')
project.send_move_instructions
end
if project.update_attributes(params.except(:default_branch))
if project.previous_changes.include?('path')
project.rename_repo
end
......
%h3.page-title
Issues
%span.pull-right #{@issues.total_count} issues
%p.light
List all issues from all projects you have access to.
......
%h3.page-title
Merge Requests
%span.pull-right #{@merge_requests.total_count} merge requests
%p.light
......
......@@ -6,4 +6,4 @@
<p>You can confirm your account through the link below:</p>
<% end %>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @resource.confirmation_token) %></p>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
......@@ -2,7 +2,7 @@
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @resource.reset_password_token) %></p>
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
......@@ -4,4 +4,4 @@
<p>Click the link below to unlock your account:</p>
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @resource.unlock_token) %></p>
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
%div{:xmlns => "http://www.w3.org/1999/xhtml"}
%p= simple_format issue.description
%p= markdown issue.description
%div{xmlns: "http://www.w3.org/1999/xhtml"}
%p= markdown merge_request.description
%div{:xmlns => "http://www.w3.org/1999/xhtml"}
%p= markdown note.note
......@@ -6,7 +6,7 @@
%i
at
= commit[:timestamp].to_time.to_s(:short)
%blockquote= simple_format(escape_once(commit[:message]))
%blockquote= markdown(escape_once(commit[:message]))
- if event.commits_count > 15
%p
%i
......
= form_tag group_filter_path(entity), method: 'get' do
%fieldset
%ul.nav.nav-pills.nav-stacked
%li{class: ("active" if (params[:status] == 'active' || !params[:status]))}
= link_to group_filter_path(entity, status: 'active') do
Active
%li{class: ("active" if params[:status] == 'closed')}
= link_to group_filter_path(entity, status: 'closed') do
Closed
%li{class: ("active" if params[:status] == 'all')}
= link_to group_filter_path(entity, status: 'all') do
All
%h3.page-title
Issues
%span.pull-right #{@issues.total_count} issues
%p.light
Only issues from
......
%h3.page-title
Merge Requests
%span.pull-right #{@merge_requests.total_count} merge requests
%p.light
Only merge requests from
......
%li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid }
%span.milestone-row
- project = issue.project
%strong #{project.name} &middot;
= link_to [project, issue] do
%span.cgray ##{issue.iid}
= link_to_gfm issue.title, [project, issue], title: issue.title
.pull-right.assignee-icon
- if issue.assignee
= image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
.panel.panel-default
.panel-heading= title
%ul{ class: "well-list issues-sortable-list" }
- if issues
- issues.each do |issue|
= render 'issue', issue: issue
%li{ id: dom_id(merge_request, 'sortable'), class: 'mr-row', 'data-iid' => merge_request.iid }
%span.milestone-row
- project = merge_request.project
%strong #{project.name} &middot;
= link_to [project, merge_request] do
%span.cgray ##{merge_request.iid}
= link_to_gfm merge_request.title, [project, merge_request], title: merge_request.title
.pull-right.assignee-icon
- if merge_request.assignee
= image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16"
.panel.panel-default
.panel-heading= title
%ul{ class: "well-list merge_requests-sortable-list" }
- if merge_requests
- merge_requests.each do |merge_request|
= render 'merge_request', merge_request: merge_request
%h3.page-title
Milestones
%span.pull-right #{@group_milestones.count} milestones
%p.light
Only milestones from
%strong #{@group.name}
group are listed here.
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.icon-list.icon-2x
.col-md-3.responsive-side
= render 'groups/filter', entity: 'milestone'
.col-md-9
.panel.panel-default
%ul.well-list
- if @group_milestones.blank?
%li
.nothing-here-block No milestones to show
- else
- @group_milestones.each do |milestone|
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
.pull-right
- if can?(current_user, :manage_group, @group)
- if milestone.closed?
= link_to 'Reopen Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped btn-reopen"
- else
= link_to 'Close Milestone', group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-close"
%h4
= link_to_gfm truncate(milestone.title, length: 100), group_milestone_path(@group, milestone.safe_title, title: milestone.title)
%div
%div
= link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
= pluralize milestone.issue_count, 'Issue'
&nbsp;
= link_to group_milestone_path(@group, milestone.safe_title, title: milestone.title) do
= pluralize milestone.merge_requests_count, 'Merge Request'
&nbsp;
%span.light #{milestone.percent_complete}% complete
.progress.progress-info
.progress-bar{style: "width: #{milestone.percent_complete}%;"}
%div
%br
- milestone.projects.each do |project|
%span.label.label-default
= project.name
= paginate @group_milestones, theme: "gitlab"
%h3.page-title
Milestone #{@group_milestone.title}
.pull-right
- if can?(current_user, :manage_group, @group)
- if @group_milestone.active?
= link_to 'Close Milestone', group_milestone_path(@group, @group_milestone.safe_title, title: @group_milestone.title, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-close"
- else
= link_to 'Reopen Milestone', group_milestone_path(@group, @group_milestone.safe_title, title: @group_milestone.title, milestone: {state_event: :activate }), method: :put, class: "btn btn-small btn-grouped btn-reopen"
- if (@group_milestone.total_items_count == @group_milestone.closed_items_count) && @group_milestone.active?
.alert.alert-success
%span All issues for this milestone are closed. You may close the milestone now.
.back-link
= link_to group_milestones_path(@group) do
&larr; To milestones list
.issue-box{ class: "issue-box-#{@group_milestone.closed? ? 'closed' : 'open'}" }
.state.clearfix
.state-label
- if @group_milestone.closed?
Closed
- else
Open
%h4.title
= gfm escape_once(@group_milestone.title)
.description
- @group_milestone.milestones.each do |milestone|
%hr
%h4
= link_to "#{milestone.project.name} - #{milestone.title}", project_milestone_path(milestone.project, milestone)
%span.pull-right= milestone.expires_at
= preserve do
- if milestone.description.present?
= milestone.description
- else
%em Project milestone has no description
.context
%p
Progress:
#{@group_milestone.closed_items_count} closed
&ndash;
#{@group_milestone.open_items_count} open
.progress.progress-info
.progress-bar{style: "width: #{@group_milestone.percent_complete}%;"}
%ul.nav.nav-tabs
%li.active
= link_to '#tab-issues', 'data-toggle' => 'tab' do
Issues
%span.badge= @group_milestone.issue_count
%li
= link_to '#tab-merge-requests', 'data-toggle' => 'tab' do
Merge Requests
%span.badge= @group_milestone.merge_requests_count
%li
= link_to '#tab-participants', 'data-toggle' => 'tab' do
Participants
%span.badge= @group_milestone.participants.count
.tab-content
.tab-pane.active#tab-issues
.row
.col-md-6
= render 'issues', title: "Open", issues: @group_milestone.opened_issues
.col-md-6
= render 'issues', title: "Closed", issues: @group_milestone.closed_issues
.tab-pane#tab-merge-requests
.row
.col-md-6
= render 'merge_requests', title: "Open", merge_requests: @group_milestone.opened_merge_requests
.col-md-6
= render 'merge_requests', title: "Closed", merge_requests: @group_milestone.closed_merge_requests
.tab-pane#tab-participants
%ul.bordered-list
- @group_milestone.participants.each do |user|
%li
= link_to user, title: user.name, class: "darken" do
= image_tag avatar_icon(user.email, 32), class: "avatar s32"
%strong= truncate(user.name, lenght: 40)
%br
%small.cgray= user.username
.jumbotron
%h2
%div
%h1
GitLab
%span.light Enterprise Edition
%span= Gitlab::VERSION
......@@ -17,7 +17,17 @@
%br
Read more about GitLab at #{link_to "www.gitlab.com", "https://www.gitlab.com/", target: "_blank"}.
%hr
.row
.col-md-8
.documentation-index
= preserve do
- readme_text = File.read(Rails.root.join("doc", "README.md"))
- text = readme_text.dup
- readme_text.scan(/\]\(([^(]+)\)/) { |match| text.gsub!(match.first, "help/#{match.first}") }
= markdown text
.col-md-4
.panel.panel-default
.panel-heading
......@@ -33,13 +43,3 @@
%li
Use
= link_to "shortcuts", '#', onclick: "new Shortcuts()"
.col-md-8
.panel.panel-default.documentation-index
.panel-heading Documentation
.panel-body
= preserve do
- readme_text = File.read(Rails.root.join("doc", "README.md"))
- text = readme_text.dup
- readme_text.scan(/\]\(([^(]+)\)/) { |match| text.gsub!(match.first, "help/#{match.first}") }
= markdown text
......@@ -2,6 +2,9 @@
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
= link_to group_path(@group), title: "Home" do
Activity
= nav_link(controller: [:group, :milestones]) do
= link_to group_milestones_path(@group) do
Milestones
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group) do
Issues
......
......@@ -4,6 +4,10 @@
%title
GitLab
:css
img {
max-width: 100%;
height: auto;
}
p.details {
font-style:italic;
color:#777
......
%p
= "Merge Request ##{@merge_request.iid} was #{@mr_status} by #{@updated_by.name}"
= "Merge Request ##{@merge_request.iid} was #{@mr_status} by #{@updated_by.name}"
Merge Request url: #{project_merge_request_url(@merge_request.target_project, @merge_request)}
= merge_path_description(@merge_request, 'to')
Author: #{@merge_request.author_name}
Assignee: #{@merge_request.assignee_name}
......@@ -5,7 +5,11 @@
= link_to project_url(@project) do
= @project.name_with_namespace
%p
To update the remote url in your local repository run:
To update the remote url in your local repository run (for ssh):
%p{ style: "background:#f5f5f5; padding:10px; border:1px solid #ddd" }
git remote set-url origin #{@project.ssh_url_to_repo}
%p
or for http(s):
%p{ style: "background:#f5f5f5; padding:10px; border:1px solid #ddd" }
git remote set-url origin #{@project.http_url_to_repo}
%br
......@@ -4,5 +4,7 @@ The project is now located under
<%= project_url(@project) %>
To update the remote url in your local repository run:
To update the remote url in your local repository run (for ssh):
git remote set-url origin <%= @project.ssh_url_to_repo %>
or for http(s):
git remote set-url origin <%= @project.http_url_to_repo %>
......@@ -4,5 +4,8 @@
from
%strong #{@previous_assignee.name}
to
- if @issue.assignee_id
%strong #{@issue.assignee_name}
- else
%strong Unassigned
......@@ -2,4 +2,4 @@ Reassigned Issue <%= @issue.iid %>
<%= url_for(project_issue_url(@issue.project, @issue)) %>
Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee %> to <%= @issue.assignee_name %>
Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee %> to <%= "#{@issue.assignee_id ? @issue.assignee_name : 'Unassigned'}" %>
......@@ -5,7 +5,9 @@
%ul
- @commits.each do |commit|
%li
#{commit.short_id} - #{commit.title}
%strong #{commit.short_id}
%span by #{commit.author_name}
%pre #{commit.safe_message}
%h4 Changes:
- @diffs.each do |diff|
......
......@@ -3,7 +3,9 @@
\
Commits:
- @commits.each do |commit|
#{commit.short_id} - #{truncate(commit.title, length: 40)}
#{commit.short_id} by #{commit.author_name}
#{commit.safe_message}
\- - - - -
\
\
Changes:
......
......@@ -7,7 +7,8 @@
- if commit.description?
%a.text-expander.js-toggle-button ...
= link_to "Browse Code »", project_tree_path(project, commit), class: "pull-right"
= link_to_browse_code(project, commit)
.notes_count
- if @note_counts
- note_count = @note_counts.fetch(commit.id, 0)
......@@ -21,7 +22,8 @@
- if commit.description?
.commit-row-description.js-toggle-content
= simple_format(commit.description)
%pre
= commit.description
.commit-row-info
= commit_author_link(commit, avatar: true, size: 16)
......
......@@ -16,7 +16,7 @@
.btn-group.tree-btn-group
= link_to "Cancel", @after_edit_path, class: "btn btn-tiny btn-cancel", data: { confirm: leave_edit_message }
.file-content.code
%pre.js-edit-mode-pane#editor= @blob.data
%pre.js-edit-mode-pane#editor
.js-edit-mode-pane#preview.hide
.center
%h2
......@@ -43,6 +43,7 @@
ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace")
var ace_mode = "#{@blob.language.try(:ace_mode)}";
var editor = ace.edit("editor");
editor.setValue("#{escape_javascript(@blob.data)}");
if (ace_mode) {
editor.getSession().setMode('ace/mode/' + ace_mode);
}
......
......@@ -2,8 +2,6 @@
= nav_link(controller: :issues) do
= link_to project_issues_path(@project), class: "tab" do
Browse Issues
- if current_controller?(:issues)
%span.badge.issue_counter #{@issues.total_count}
= nav_link(controller: :milestones) do
= link_to 'Milestones', project_milestones_path(@project), class: "tab"
= nav_link(controller: :labels) do
......
......@@ -38,9 +38,9 @@
.issue-actions
- if can? current_user, :modify_issue, issue
- if issue.closed?
= link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small btn-grouped reopen_issue", remote: true
= link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small btn-grouped reopen_issue btn-reopen", remote: true
- else
= link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small btn-grouped close_issue", remote: true
= link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small btn-grouped close_issue btn-close", remote: true
= link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link btn-grouped" do
%i.icon-edit
Edit
......
......@@ -4,6 +4,6 @@
%i.icon-list.icon-2x
.col-md-3.responsive-side
= render 'shared/project_filter', project_entities_path: project_issues_path(@project),
labels: true, redirect: 'issues'
labels: true, redirect: 'issues', entity: 'issue'
.col-md-9.issues-holder
= render "issues"
......@@ -4,14 +4,13 @@
New Merge Request
%h3.page-title
Merge Requests
%span (#{@merge_requests.total_count})
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.icon-list.icon-2x
.col-md-3.responsive-side
= render 'shared/project_filter', project_entities_path: project_merge_requests_path(@project),
labels: true, redirect: 'merge_requests'
labels: true, redirect: 'merge_requests', entity: 'merge_request'
.col-md-9
.mr-filters.append-bottom-10
.dropdown.inline
......
......@@ -38,7 +38,7 @@
.accept-group
.pull-left
= f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
- if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch)
- if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork?
.remove_branch_holder.pull-left
= label_tag :should_remove_source_branch, class: "checkbox" do
= check_box_tag :should_remove_source_branch
......
- if @commits.any?
.ci_widget.ci-success{style: "display:none"}
%i.icon-ok
%strong CI build passed
%span CI build passed
for #{@merge_request.last_commit_short_sha}.
= link_to "Build page", ci_build_details_path(@merge_request)
.ci_widget.ci-failed{style: "display:none"}
%i.icon-remove
%strong CI build failed
%span CI build failed
for #{@merge_request.last_commit_short_sha}.
= link_to "Build page", ci_build_details_path(@merge_request)
- [:running, :pending].each do |status|
.ci_widget{class: "ci-#{status}", style: "display:none"}
%i.icon-time
%strong CI build #{status}
%span CI build #{status}
for #{@merge_request.last_commit_short_sha}.
= link_to "Build page", ci_build_details_path(@merge_request)
......@@ -26,4 +26,4 @@
.ci_widget.ci-error{style: "display:none"}
%i.icon-remove
%strong Cannot connect to the CI server. Please check your settings and try again.
%span Cannot connect to the CI server. Please check your settings and try again.
......@@ -2,7 +2,7 @@
%span.str-truncated
= link_to [@project, issue] do
%span.cgray ##{issue.iid}
= link_to_gfm issue.title, [@project, issue]
= link_to_gfm issue.title, [@project, issue], title: issue.title
.pull-right.assignee-icon
- if issue.assignee
= image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
......
......@@ -2,4 +2,4 @@
%span.str-truncated
= link_to [@project, merge_request] do
%span.cgray ##{merge_request.iid}
= link_to_gfm truncate(merge_request.title, length: 60), [@project, merge_request]
= link_to_gfm merge_request.title, [@project, merge_request], title: merge_request.title
......@@ -4,7 +4,7 @@
= link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link btn-grouped" do
%i.icon-edit
Edit
= link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-remove"
= link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-close"
%h4
= link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone)
- if milestone.expired? and not milestone.closed?
......
......@@ -7,9 +7,9 @@
%i.icon-edit
Edit
- if @milestone.active?
= link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-remove btn-grouped"
= link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
- else
= link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-grouped"
= link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
- if @milestone.issues.any? && @milestone.can_be_closed?
.alert.alert-success
......
......@@ -6,4 +6,4 @@
= truncate issue.title, length: 50
%span.light (#{issue.project.name_with_namespace})
- if issue.closed?
%span.label Closed
%span.label.label-danger Closed
......@@ -8,5 +8,7 @@
%span.light (#{merge_request.source_project.name_with_namespace}:#{merge_request.source_branch} &rarr; #{merge_request.target_project.name_with_namespace}:#{merge_request.target_branch})
- else
%span.light (#{merge_request.source_branch} &rarr; #{merge_request.target_branch})
- if merge_request.closed?
%span.label Closed
- if merge_request.merged?
%span.label.label-primary Merged
- elsif merge_request.closed?
%span.label.label-danger Closed
......@@ -6,12 +6,18 @@
%li{class: ("active" if params[:scope] == 'assigned-to-me')}
= link_to filter_path(entity, scope: 'assigned-to-me') do
Assigned to me
%span.pull-right
= assigned_entities_count(current_user, entity, @group)
%li{class: ("active" if params[:scope] == 'authored')}
= link_to filter_path(entity, scope: 'authored') do
Created by me
%span.pull-right
= authored_entities_count(current_user, entity, @group)
%li{class: ("active" if params[:scope] == 'all')}
= link_to filter_path(entity, scope: 'all') do
Everyone's
%span.pull-right
= authorized_entities_count(current_user, entity, @group)
%fieldset.status-filter
%legend State
......
......@@ -6,12 +6,18 @@
%li{class: ("active" if params[:scope] == 'all')}
= link_to project_filter_path(scope: 'all') do
Everyone's
%span.pull-right
= authorized_entities_count(current_user, entity, @project)
%li{class: ("active" if params[:scope] == 'assigned-to-me')}
= link_to project_filter_path(scope: 'assigned-to-me') do
Assigned to me
%span.pull-right
= assigned_entities_count(current_user, entity, @project)
%li{class: ("active" if params[:scope] == 'created-by-me')}
= link_to project_filter_path(scope: 'created-by-me') do
Created by me
%span.pull-right
= authored_entities_count(current_user, entity, @project)
%fieldset
%legend State
......
......@@ -41,12 +41,6 @@ module Gitlab
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
# Enforce whitelist mode for mass assignment.
# This will create an empty whitelist of attributes available for mass-assignment for all models
# in your app. As such, your models will need to explicitly whitelist or blacklist accessible
# parameters by using an attr_accessible or attr_protected declaration.
config.active_record.whitelist_attributes = true
# Enable the asset pipeline
config.assets.enabled = true
config.assets.paths << Emoji.images_path
......
......@@ -10,7 +10,6 @@ production:
# password:
# host: localhost
# port: 5432
# socket: /tmp/postgresql.sock
#
# Development specific
......@@ -22,7 +21,6 @@ development:
pool: 5
username: postgres
password:
# socket: /tmp/postgresql.sock
#
# Staging specific
......@@ -34,7 +32,6 @@ staging:
pool: 5
username: postgres
password:
# socket: /tmp/postgresql.sock
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
......@@ -46,4 +43,3 @@ test: &test
pool: 5
username: postgres
password:
# socket: /tmp/postgresql.sock
......@@ -19,9 +19,6 @@ Gitlab::Application.configure do
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict
# Do not compress assets
config.assets.compress = false
......
......@@ -26,9 +26,6 @@ Gitlab::Application.configure do
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Raise exception on mass assignment protection for Active Record models
# config.active_record.mass_assignment_sanitizer = :strict
# Print deprecation notices to the stderr
config.active_support.deprecation = :stderr
......
......@@ -49,15 +49,6 @@ production: &base
## COLOR = 5
# default_theme: 2 # default: 2
## Users management
# default: false - Account passwords are not sent via the email if signup is enabled.
# signup_enabled: true
#
# default: true - If set to false, standard login form won't be shown on the sign-in page
# signin_enabled: false
# Restrict setting visibility levels for non-admin users.
# The default is to allow all levels.
#restricted_visibility_levels: [ "public" ]
......@@ -121,6 +112,16 @@ production: &base
# 2. Auth settings
# ==========================
## Users can create accounts
# This also allows normal users to sign up for accounts themselves
# default: false - By default GitLab administrators must create all new accounts
# signup_enabled: true
## Standard login settings
# The standard login can be disabled to force login via LDAP
# default: true - If set to false the standard login form won't be shown on the sign-in page
# signin_enabled: false
## LDAP settings
# You can inspect a sample of the LDAP users with login access by running:
# bundle exec rake gitlab:ldap:check RAILS_ENV=production
......
......@@ -150,6 +150,6 @@ Settings['extra'] ||= Settingslogic.new({})
#
if Rails.env.test?
Settings.gitlab['default_projects_limit'] = 42
Settings.gitlab['default_can_create_group'] = false
Settings.gitlab['default_can_create_group'] = true
Settings.gitlab['default_can_create_team'] = false
end
......@@ -155,10 +155,6 @@ Devise.setup do |config|
# REST_AUTH_SITE_KEY to pepper)
# config.encryptor = :sha512
# ==> Configuration for :token_authenticatable
# Defines name of the authentication token params key
config.token_authentication_key = :private_token
# Authentication through token does not store user in session and needs
# to be supplied on each request. Useful if you are using the token as API token.
config.skip_session_storage << :token_auth
......
......@@ -25,6 +25,9 @@ en:
sessions:
signed_in: 'Signed in successfully.'
signed_out: 'Signed out successfully.'
users_sessions:
user:
signed_in: 'Signed in successfully.'
passwords:
send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
updated: 'Your password was changed successfully. You are now signed in.'
......
......@@ -165,8 +165,10 @@ Gitlab::Application.routes.draw do
end
resources :users_groups, only: [:create, :update, :destroy]
scope module: :groups do
resource :avatar, only: [:destroy]
resources :milestones
end
end
......
......@@ -220,3 +220,32 @@ Response:
"compare_same_ref": false
}
```
## Contributors
Get repository contributors list
```
GET /projects/:id/repository/contributors
```
Parameters:
+ `id` (required) - The ID of a project
Response:
```
[{
"name": "Dmitriy Zaporozhets",
"email": "dmitriy.zaporozhets@gmail.com",
"commits": 117,
"additions": 2097,
"deletions": 517
}, {
"name": "Jacob Vosmaer",
"email": "contact@jacobvosmaer.nl",
"commits": 33,
"additions": 338,
"deletions": 244
}]
```
......@@ -331,6 +331,8 @@ To make sure you didn't miss anything run a more thorough check with:
If all items are green, then congratulations on successfully installing GitLab!
NOTE: Supply `SANITIZE=true` environment variable to `gitlab:check` to omit project names from the output of the check command.
### Initial Login
Visit YOUR_SERVER in your web browser for your first GitLab login. The setup has created an admin account for you. You can use it to log in:
......
......@@ -4,39 +4,25 @@
**[GitLab Flavored Markdown](#gitlab-flavored-markdown-gfm)**
[Newlines](#newlines)
[Multiple underscores in words](#multiple-underscores-in-words)
[URL autolinking](#url-autolinking)
[Code and Syntax Highlighting](#code-and-syntax-highlighting)
[Emoji](#emoji)
[Special GitLab references](#special-gitlab-references)
* [Newlines](#newlines)
* [Multiple underscores in words](#multiple-underscores-in-words)
* [URL autolinking](#url-autolinking)
* [Code and Syntax Highlighting](#code-and-syntax-highlighting)
* [Emoji](#emoji)
* [Special GitLab references](#special-gitlab-references)
**[Standard Markdown](#standard-markdown)**
[Headers](#headers)
[Emphasis](#emphasis)
[Lists](#lists)
[Links](#links)
[Images](#images)
[Blockquotes](#blockquotes)
[Inline HTML](#inline-html)
[Horizontal Rule](#horizontal-rule)
[Line Breaks](#line-breaks)
[Tables](#tables)
* [Headers](#headers)
* [Emphasis](#emphasis)
* [Lists](#lists)
* [Links](#links)
* [Images](#images)
* [Blockquotes](#blockquotes)
* [Inline HTML](#inline-html)
* [Horizontal Rule](#horizontal-rule)
* [Line Breaks](#line-breaks)
* [Tables](#tables)
**[References](#references)**
......
......@@ -12,7 +12,7 @@ Public projects can be cloned **without any** authentication.
It will also be listed on the [public access directory](/public).
**Any logged in user** will have [Guest](/help/permissions) permissions on the repository.
**Any logged in user** will have [Guest](../permissions/permissions) permissions on the repository.
## Internal projects
......@@ -20,7 +20,7 @@ Internal projects can be cloned by any logged in user.
It will also be listed on the [public access directory](/public) for logged in users.
Any logged in user will have [Guest](/help/permissions) permissions on the repository.
Any logged in user will have [Guest](../permissions/permissions) permissions on the repository.
## How to change project visibility
......
# Backup restore
![backup banner](backup_hrz.png)
## Create a backup of the GitLab system
Creates a backup archive of the database and all repositories. This archive will be saved in backup_path (see `config/gitlab.yml`).
......
......@@ -18,21 +18,3 @@ New path: `git@example.org:username/myrepo.git` or `git@example.org:groupname/my
```
bundle exec rake gitlab:enable_namespaces RAILS_ENV=production
```
## Rebuild project satellites
This command will build missing satellites for projects. After this you will be able to **merge a merge request** via GitLab and use the **online editor**.
```
bundle exec rake gitlab:satellites:create RAILS_ENV=production
```
Example output:
```
Creating satellite for abcd.git
[git clone output]
Creating satellite for abcd2.git
[git clone output]
done
```
......@@ -63,6 +63,8 @@ sudo gitlab-rake gitlab:check
bundle exec rake gitlab:check RAILS_ENV=production
```
NOTE: Use SANITIZE=true for gitlab:check if you want to omit project names from the output.
Example output:
```
......
......@@ -107,20 +107,12 @@ Create an annotated tag that points to the version change commit:
git tag -a vx.x.0.rc1 -m 'Version x.x.0.rc1'
```
### **7. Tweet**
Tweet about the RC release:
> GitLab x.x.x.rc1 is out. This is a release candidate intended for testing only. Please let us know if you find regressions.
n
### **8. Update GitLab.com**
### **7. Update GitLab.com**
Merge the RC1 code into GitLab.com. Once the build is green, deploy in the morning.
It is important to do this as soon as possible, so we can catch any errors before we release the full version.
### **9. Create a regressions issue**
### **8. Create a regressions issue**
On [the GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues/) create an issue titled "GitLab X.X regressions" add the following text:
......@@ -131,6 +123,12 @@ The release manager will comment here about the plans for patch releases.
Assign the issue to the release manager and /cc all the core-team members active on the issue tracker. If there are any known bugs in the release add them immediately.
### **9. Tweet**
Tweet about the RC release:
> GitLab x.x.x.rc1 is out. This release candidate is only suitable for testing. Please create issues for regressions and add a link from LINK_TO_ISSUE.
# **21st - Preparation **
### **1. Prepare the blog post**
......
......@@ -56,7 +56,7 @@ sudo apt-get install logrotate
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
sudo -u git -H git checkout v1.9.3 # Addresses multiple critical security vulnerabilities
sudo -u git -H git checkout v1.9.6 # Addresses multiple critical security vulnerabilities
```
## 5. Install libs, migrations, etc.
......
......@@ -91,7 +91,7 @@ cd tmp/backups/postgresql
sudo -u git -H mysqldump --compatible=postgresql --default-character-set=utf8 -r gitlabhq_production.mysql -u root gitlabhq_production
# Clone the database converter
sudo -u git -H git clone https://github.com/lanyrd/mysql-postgresql-converter.git
sudo -u git -H git clone https://github.com/gitlabhq/mysql-postgresql-converter.git
# Convert gitlabhq_production.mysql
sudo -u git -H mkdir db
......
......@@ -120,3 +120,24 @@ Feature: Groups
When I search for 'Mary' member
Then I should see user "Mary Jane" in team list
Then I should not see user "John Doe" in team list
# Group milestones
Scenario: I should see group "Owned" milestone index page with no milestones
When I visit group "Owned" page
And I click on group milestones
Then I should see group milestones index page has no milestones
Scenario: I should see group "Owned" milestone index page with milestones
Given Group has projects with milestones
When I visit group "Owned" page
And I click on group milestones
Then I should see group milestones index page with milestones
Scenario: I should see group "Owned" milestone show page
Given Group has projects with milestones
When I visit group "Owned" page
And I click on group milestones
And I click on one group milestone
Then I should see group milestone with descriptions and expiry date
And I should see group milestone with all issues and MRs assigned to that milestone
......@@ -38,4 +38,16 @@ Feature: Project Browse files
And I click link "Diff"
Then I see diff
Scenario: I can browse directory with Browse Dir
Given I click on app directory
And I click on history link
Then I see Browse dir link
Scenario: I can browse file with Browse File
Given I click on readme file
And I click on history link
Then I see Browse file link
Scenario: I can browse code with Browse Code
Given I click on history link
Then I see Browse code link
......@@ -175,6 +175,42 @@ class Groups < Spinach::FeatureSteps
end
end
step 'I click on group milestones' do
click_link 'Milestones'
end
step 'I should see group milestones index page has no milestones' do
page.should have_content('No milestones to show')
end
step 'Group has projects with milestones' do
group_milestone
end
step 'I should see group milestones index page with milestones' do
page.should have_content('Version 7.2')
page.should have_content('GL-113')
page.should have_link('2 Issues', href: group_milestone_path("owned", "version-7-2", title: "Version 7.2"))
page.should have_link('3 Merge Requests', href: group_milestone_path("owned", "gl-113", title: "GL-113"))
end
step 'I click on one group milestone' do
click_link 'GL-113'
end
step 'I should see group milestone with descriptions and expiry date' do
page.should have_content('Lorem Ipsum is simply dummy text of the printing and typesetting industry')
page.should have_content('expires at Aug 20, 2014')
page.should have_content('Project milestone has no description')
end
step 'I should see group milestone with all issues and MRs assigned to that milestone' do
page.should have_content('Milestone GL-113')
page.should have_content('Progress: 0 closed – 4 open')
page.should have_link(@issue1.title, href: project_issue_path(@project1, @issue1))
page.should have_link(@mr3.title, href: project_merge_request_path(@project3, @mr3))
end
protected
def assigned_to_me key
......@@ -184,4 +220,70 @@ class Groups < Spinach::FeatureSteps
def project
Group.find_by(name: "Owned").projects.first
end
def group_milestone
group = Group.find_by(name: "Owned")
@project1 = create :project,
group: group
project2 = create :project,
path: 'gitlab-ci',
group: group
@project3 = create :project,
path: 'cookbook-gitlab',
group: group
milestone1_project1 = create :milestone,
title: "Version 7.2",
project: @project1
milestone1_project2 = create :milestone,
title: "Version 7.2",
project: project2
milestone1_project3 = create :milestone,
title: "Version 7.2",
project: @project3
milestone2_project1 = create :milestone,
title: "GL-113",
project: @project1
milestone2_project2 = create :milestone,
title: "GL-113",
project: project2
milestone2_project3 = create :milestone,
title: "GL-113",
project: @project3,
due_date: '2014-08-20',
description: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry'
@issue1 = create :issue,
project: @project1,
assignee: current_user,
author: current_user,
milestone: milestone2_project1
issue2 = create :issue,
project: project2,
assignee: current_user,
author: current_user,
milestone: milestone1_project2
issue3 = create :issue,
project: @project3,
assignee: current_user,
author: current_user,
milestone: milestone1_project1
mr1 = create :merge_request,
source_project: @project1,
target_project: @project1,
assignee: current_user,
author: current_user,
milestone: milestone2_project1
mr2 = create :merge_request,
source_project: project2,
target_project: project2,
assignee: current_user,
author: current_user,
milestone: milestone2_project2
@mr3 = create :merge_request,
source_project: @project3,
target_project: @project3,
assignee: current_user,
author: current_user,
milestone: milestone2_project3
end
end
......@@ -62,4 +62,32 @@ class ProjectBrowseFiles < Spinach::FeatureSteps
page.should have_content "File name"
page.should have_content "Commit message"
end
step 'I click on app directory' do
click_link 'app'
end
step 'I click on history link' do
click_link 'history'
end
step 'I see Browse dir link' do
page.should have_link 'Browse Dir »'
page.should_not have_link 'Browse Code »'
end
step 'I click on readme file' do
click_link 'README.md'
end
step 'I see Browse file link' do
page.should have_link 'Browse File »'
page.should_not have_link 'Browse Code »'
end
step 'I see Browse code link' do
page.should have_link 'Browse Code »'
page.should_not have_link 'Browse File »'
page.should_not have_link 'Browse Dir »'
end
end
......@@ -10,7 +10,7 @@ module SharedProject
# Create a specific project called "Shop"
And 'I own project "Shop"' do
@project = Project.find_by(name: "Shop")
@project ||= create(:project, name: "Shop", namespace: @user.namespace, merge_requests_template: "This merge request should contain the following.")
@project ||= create(:project, name: "Shop", namespace: @user.namespace, snippets_enabled: true, merge_requests_template: "This merge request should contain the following.")
@project.team << [@user, :master]
end
......
......@@ -226,5 +226,9 @@ module API
expose :same, as: :compare_same_ref
end
class Contributor < Grape::Entity
expose :name, :email, :commits, :additions, :deletions
end
end
end
......@@ -98,10 +98,14 @@ module API
def attributes_for_keys(keys)
attrs = {}
keys.each do |key|
attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false)
if params[key].present? or (params.has_key?(key) and params[key] == false)
attrs[key] = params[key]
end
end
attrs
ActionController::Parameters.new(attrs).permit!
end
# error helpers
......
......@@ -150,6 +150,18 @@ module API
compare = Gitlab::Git::Compare.new(user_project.repository.raw_repository, params[:from], params[:to], MergeRequestDiff::COMMITS_SAFE_SIZE)
present compare, with: Entities::Compare
end
# Get repository contributors
#
# Parameters:
# id (required) - The ID of a project
# Example Request:
# GET /projects/:id/repository/contributors
get ':id/repository/contributors' do
authorize! :download_code, user_project
present user_project.repository.contributors, with: Entities::Contributor
end
end
end
end
......@@ -59,7 +59,7 @@ module API
authenticated_as_admin!
required_attributes! [:email, :password, :name, :username]
attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio, :can_create_group, :admin]
user = User.build_user(attrs, as: :admin)
user = User.build_user(attrs)
admin = attrs.delete(:admin)
user.admin = admin unless admin.nil?
if user.save
......@@ -96,7 +96,7 @@ module API
admin = attrs.delete(:admin)
user.admin = admin unless admin.nil?
if user.update_attributes(attrs, as: :admin)
if user.update_attributes(attrs)
present user, with: Entities::UserFull
else
not_found!
......
module Gitlab::ConfigHelper
def gitlab_config_features
Gitlab.config.gitlab.default_projects_features
end
def gitlab_config
Gitlab.config.gitlab
end
end
module Gitlab
class Contributor
attr_accessor :email, :name, :commits, :additions, :deletions
def initialize
@commits, @additions, @deletions = 0, 0, 0
end
end
end
......@@ -14,7 +14,15 @@ module Gitlab
end
def self.adapter_options
encryption = config['method'].to_s == 'ssl' ? :simple_tls : nil
encryption =
case config['method'].to_s
when 'ssl'
:simple_tls
when 'tls'
:start_tls
else
nil
end
options = {
host: config['host'],
......
......@@ -27,7 +27,7 @@ module Gitlab
password_confirmation: password,
}
user = model.build_user(opts, as: :admin)
user = model.build_user(opts)
user.skip_confirmation!
# Services like twitter and github does not return email via oauth
......
......@@ -6,18 +6,35 @@ module Gitlab
default_regex
end
def username_regex_message
default_regex_message
end
def project_name_regex
/\A[a-zA-Z0-9_][a-zA-Z0-9_\-\. ]*\z/
end
def project_regex_message
"can contain only letters, digits, '_', '-' and '.' and space. " \
"It must start with letter, digit or '_'."
end
def name_regex
/\A[a-zA-Z0-9_\-\. ]*\z/
end
def name_regex_message
"can contain only letters, digits, '_', '-' and '.' and space."
end
def path_regex
default_regex
end
def path_regex_message
default_regex_message
end
def archive_formats_regex
#|zip|tar| tar.gz | tar.bz2 |
/(zip|tar|tar\.gz|tgz|gz|tar\.bz2|tbz|tbz2|tb2|bz2)/
......@@ -48,8 +65,14 @@ module Gitlab
protected
def default_regex_message
"can contain only letters, digits, '_', '-' and '.'. " \
"It must start with letter, digit or '_', optionally preceeded by '.'. " \
"It must not end in '.git'."
end
def default_regex
/\A[.?]?[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*(?<!\.git)\z/
/\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\.]*(?<!\.git)\z/
end
end
end
......@@ -31,8 +31,9 @@ module Gitlab
# push merge back to bare repo
# will raise CommandFailed when push fails
merge_repo.git.push(default_options, :origin, merge_request.target_branch)
# remove source branch
if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch)
if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch) && !merge_request.for_fork?
# will raise CommandFailed when push fails
merge_repo.git.push(default_options, :origin, ":#{merge_request.source_branch}")
end
......
......@@ -216,7 +216,7 @@ namespace :gitlab do
puts ""
Project.find_each(batch_size: 100) do |project|
print "#{project.name_with_namespace.yellow} ... "
print sanitized_message(project)
if project.satellite.exists?
puts "yes".green
......@@ -525,7 +525,7 @@ namespace :gitlab do
puts ""
Project.find_each(batch_size: 100) do |project|
print "#{project.name_with_namespace.yellow} ... "
print sanitized_message(project)
if project.empty_repo?
puts "repository is empty".magenta
......@@ -588,7 +588,7 @@ namespace :gitlab do
puts ""
Project.find_each(batch_size: 100) do |project|
print "#{project.name_with_namespace.yellow} ... "
print sanitized_message(project)
if project.namespace
puts "yes".green
......@@ -837,4 +837,20 @@ namespace :gitlab do
def omnibus_gitlab?
Dir.pwd == '/opt/gitlab/embedded/service/gitlab-rails'
end
def sanitized_message(project)
if sanitize
"#{project.namespace_id.to_s.yellow}/#{project.id.to_s.yellow} ... "
else
"#{project.name_with_namespace.yellow} ... "
end
end
def sanitize
if ENV['SANITIZE'] == "true"
true
else
false
end
end
end
......@@ -84,5 +84,29 @@ namespace :gitlab do
puts "To cleanup this directories run this command with REMOVE=true".yellow
end
end
desc "GITLAB | Cleanup | Block users that have been removed in LDAP"
task block_removed_ldap_users: :environment do
warn_user_is_not_gitlab
block_flag = ENV['BLOCK']
User.ldap.each do |ldap_user|
print "#{ldap_user.name} (#{ldap_user.extern_uid}) ..."
if Gitlab::LDAP::Access.open { |access| access.allowed?(ldap_user) }
puts " [OK]".green
else
if block_flag
ldap_user.block!
puts " [BLOCKED]".red
else
puts " [NOT IN LDAP]".yellow
end
end
end
unless block_flag
puts "To block these users run this command with BLOCK=true".yellow
end
end
end
end
......@@ -34,4 +34,18 @@ describe Projects::BlobController do
it { should respond_with(:not_found) }
end
end
describe 'GET show with tree path' do
render_views
before do
get :show, project_id: project.to_param, id: id
controller.instance_variable_set(:@blob, nil)
end
context 'redirect to tree' do
let(:id) { 'master/doc' }
it { should redirect_to("/#{project.path_with_namespace}/tree/master/doc") }
end
end
end
......@@ -40,4 +40,17 @@ describe Projects::TreeController do
it { should respond_with(:not_found) }
end
end
describe 'GET show with blob path' do
render_views
before do
get :show, project_id: project.to_param, id: id
end
context 'redirect to blob' do
let(:id) { 'master/README.md' }
it { should redirect_to("/#{project.path_with_namespace}/blob/master/README.md") }
end
end
end
......@@ -32,6 +32,7 @@ FactoryGirl.define do
path { name.downcase.gsub(/\s/, '_') }
namespace
creator
snippets_enabled true
trait :public do
visibility_level Gitlab::VisibilityLevel::PUBLIC
......
require 'spec_helper'
describe Gitlab::Regex do
describe 'path regex' do
it { 'gitlab-ce'.should match(Gitlab::Regex.path_regex) }
it { 'gitlab_git'.should match(Gitlab::Regex.path_regex) }
it { '_underscore.js'.should match(Gitlab::Regex.path_regex) }
it { '100px.com'.should match(Gitlab::Regex.path_regex) }
it { '?gitlab'.should_not match(Gitlab::Regex.path_regex) }
it { 'git lab'.should_not match(Gitlab::Regex.path_regex) }
it { 'gitlab.git'.should_not match(Gitlab::Regex.path_regex) }
end
describe 'project name regex' do
it { 'gitlab-ce'.should match(Gitlab::Regex.project_name_regex) }
it { 'GitLab CE'.should match(Gitlab::Regex.project_name_regex) }
it { '100 lines'.should match(Gitlab::Regex.project_name_regex) }
it { 'gitlab.git'.should match(Gitlab::Regex.project_name_regex) }
it { '?gitlab'.should_not match(Gitlab::Regex.project_name_regex) }
end
end
......@@ -22,6 +22,23 @@ describe Notify do
end
end
shared_examples 'an email starting a new thread' do |message_id_prefix|
it 'has a discussion identifier' do
should have_header 'Message-ID', /<#{message_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
end
end
shared_examples 'an answer to an existing thread' do |thread_id_prefix|
it 'has a subject that begins with Re: ' do
should have_subject /^Re: /
end
it 'has headers that reference an existing thread' do
should have_header 'References', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
should have_header 'In-Reply-To', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
end
end
describe 'for new users, the email' do
let(:example_site_path) { root_path }
let(:new_user) { create(:user, email: 'newguy@example.com', created_by_id: 1) }
......@@ -153,6 +170,7 @@ describe Notify do
subject { Notify.new_issue_email(issue.assignee_id, issue.id) }
it_behaves_like 'an assignee email'
it_behaves_like 'an email starting a new thread', 'issue'
it 'has the correct subject' do
should have_subject /#{project.name} \| #{issue.title} \(##{issue.iid}\)/
......@@ -161,10 +179,6 @@ describe Notify do
it 'contains a link to the new issue' do
should have_body_text /#{project_issue_path project, issue}/
end
it 'has the correct message-id set' do
should have_header 'Message-ID', "<issue_#{issue.id}@#{Gitlab.config.gitlab.host}>"
end
end
describe 'that are new with a description' do
......@@ -179,6 +193,7 @@ describe Notify do
subject { Notify.reassigned_issue_email(recipient.id, issue.id, previous_assignee.id, current_user) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread', 'issue'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
......@@ -201,16 +216,14 @@ describe Notify do
it 'contains a link to the issue' do
should have_body_text /#{project_issue_path project, issue}/
end
it 'has the correct reference set' do
should have_header 'References', "<issue_#{issue.id}@#{Gitlab.config.gitlab.host}>"
end
end
describe 'status changed' do
let(:status) { 'closed' }
subject { Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user) }
it_behaves_like 'an answer to an existing thread', 'issue'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
sender.display_name.should eq(current_user.name)
......@@ -232,10 +245,6 @@ describe Notify do
it 'contains a link to the issue' do
should have_body_text /#{project_issue_path project, issue}/
end
it 'has the correct reference set' do
should have_header 'References', "<issue_#{issue.id}@#{Gitlab.config.gitlab.host}>"
end
end
end
......@@ -249,6 +258,7 @@ describe Notify do
subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) }
it_behaves_like 'an assignee email'
it_behaves_like 'an email starting a new thread', 'merge_request'
it 'has the correct subject' do
should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
......@@ -283,6 +293,7 @@ describe Notify do
subject { Notify.reassigned_merge_request_email(recipient.id, merge_request.id, previous_assignee.id, current_user.id) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread', 'merge_request'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
......@@ -311,6 +322,7 @@ describe Notify do
subject { Notify.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread', 'merge_request'
it 'is sent as the merge author' do
sender = subject.header[:from].addrs[0]
......@@ -329,10 +341,6 @@ describe Notify do
it 'contains a link to the merge request' do
should have_body_text /#{project_merge_request_path project, merge_request}/
end
it 'has the correct reference set' do
should have_header 'References', "<merge_request_#{merge_request.id}@#{Gitlab.config.gitlab.host}>"
end
end
end
end
......@@ -410,6 +418,7 @@ describe Notify do
subject { Notify.note_commit_email(recipient.id, note.id) }
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread', 'commits'
it 'has the correct subject' do
should have_subject /#{commit.title} \(#{commit.short_id}\)/
......@@ -428,6 +437,7 @@ describe Notify do
subject { Notify.note_merge_request_email(recipient.id, note.id) }
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread', 'merge_request'
it 'has the correct subject' do
should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
......@@ -446,6 +456,7 @@ describe Notify do
subject { Notify.note_issue_email(recipient.id, note.id) }
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread', 'issue'
it 'has the correct subject' do
should have_subject /#{issue.title} \(##{issue.iid}\)/
......
......@@ -26,7 +26,6 @@ describe GitlabCiService do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:project_id) }
end
describe 'commits methods' do
......
......@@ -25,8 +25,6 @@ describe Issue do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:author_id) }
it { should_not allow_mass_assignment_of(:project_id) }
end
describe 'modules' do
......
......@@ -20,8 +20,6 @@ describe Key do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:project_id) }
it { should_not allow_mass_assignment_of(:user_id) }
end
describe "Validation" do
......
......@@ -28,8 +28,6 @@ describe MergeRequest do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:author_id) }
it { should_not allow_mass_assignment_of(:project_id) }
end
describe "Respond to" do
......
......@@ -22,7 +22,6 @@ describe Milestone do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:project_id) }
end
describe "Validation" do
......
......@@ -26,8 +26,6 @@ describe Namespace do
it { should validate_presence_of :owner }
describe "Mass assignment" do
it { should allow_mass_assignment_of(:name) }
it { should allow_mass_assignment_of(:path) }
end
describe "Respond to" do
......
......@@ -27,8 +27,6 @@ describe Note do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:author) }
it { should_not allow_mass_assignment_of(:author_id) }
end
describe "Validation" do
......
......@@ -23,7 +23,6 @@ describe ProjectSnippet do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:project_id) }
end
describe "Validation" do
......
......@@ -48,8 +48,6 @@ describe Project do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:namespace_id) }
it { should_not allow_mass_assignment_of(:creator_id) }
end
describe "Validation" do
......
......@@ -17,7 +17,6 @@ describe ProtectedBranch do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:project_id) }
end
describe 'Validation' do
......
......@@ -27,7 +27,6 @@ describe Service do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:project_id) }
end
describe "Test Button" do
......
......@@ -24,7 +24,6 @@ describe Snippet do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:author_id) }
end
describe "Validation" do
......
......@@ -65,8 +65,6 @@ describe User do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:projects_limit) }
it { should allow_mass_assignment_of(:projects_limit).as(:admin) }
end
describe 'validations' do
......@@ -243,18 +241,8 @@ describe User do
it { user.first_name.should == 'John' }
end
describe 'without defaults' do
let(:user) { User.new }
it "should not apply defaults to user" do
user.projects_limit.should == 10
user.can_create_group.should be_true
user.theme_id.should == Gitlab::Theme::BASIC
end
end
context 'as admin' do
describe 'with defaults' do
let(:user) { User.build_user({}, as: :admin) }
let(:user) { User.new }
it "should apply defaults to user" do
user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
......@@ -264,42 +252,16 @@ describe User do
end
describe 'with default overrides' do
let(:user) { User.build_user({projects_limit: 123, can_create_group: true, can_create_team: true, theme_id: Gitlab::Theme::BASIC}, as: :admin) }
let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true, theme_id: Gitlab::Theme::BASIC) }
it "should apply defaults to user" do
Gitlab.config.gitlab.default_projects_limit.should_not == 123
Gitlab.config.gitlab.default_can_create_group.should_not be_true
Gitlab.config.gitlab.default_theme.should_not == Gitlab::Theme::BASIC
user.projects_limit.should == 123
user.can_create_group.should be_true
user.can_create_group.should be_false
user.theme_id.should == Gitlab::Theme::BASIC
end
end
end
context 'as user' do
describe 'with defaults' do
let(:user) { User.build_user }
it "should apply defaults to user" do
user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group
user.theme_id.should == Gitlab.config.gitlab.default_theme
end
end
describe 'with default overrides' do
let(:user) { User.build_user(projects_limit: 123, can_create_group: true, theme_id: Gitlab::Theme::BASIC) }
it "should apply defaults to user" do
user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group
user.theme_id.should == Gitlab.config.gitlab.default_theme
end
end
end
end
describe 'search' do
let(:user1) { create(:user, username: 'James', email: 'james@testing.com') }
let(:user2) { create(:user, username: 'jameson', email: 'jameson@example.com') }
......
......@@ -20,7 +20,6 @@ describe UsersGroup do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:group_id) }
end
describe "Validation" do
......
......@@ -20,7 +20,6 @@ describe UsersProject do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:project_id) }
end
describe "Validation" do
......
......@@ -23,7 +23,6 @@ describe ProjectHook do
end
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:project_id) }
end
describe "Validations" do
......
......@@ -128,7 +128,7 @@ describe API::API, api: true do
end
end
describe 'GET /GET /projects/:id/repository/compare' do
describe 'GET /projects/:id/repository/compare' do
it "should compare branches" do
get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'simple_merge_request'
response.status.should == 200
......@@ -166,4 +166,18 @@ describe API::API, api: true do
json_response['compare_same_ref'].should be_true
end
end
describe 'GET /projects/:id/repository/contributors' do
it 'should return valid data' do
get api("/projects/#{project.id}/repository/contributors", user)
response.status.should == 200
json_response.should be_an Array
contributor = json_response.first
contributor['email'].should == 'dmitriy.zaporozhets@gmail.com'
contributor['name'].should == 'Dmitriy Zaporozhets'
contributor['commits'].should == 185
contributor['additions'].should == 66072
contributor['deletions'].should == 63013
end
end
end
......@@ -97,19 +97,6 @@ describe API::API, api: true do
response.status.should == 201
end
it "creating a user should respect default project limit" do
limit = 123456
Gitlab.config.gitlab.stub(:default_projects_limit).and_return(limit)
attr = attributes_for(:user )
expect {
post api("/users", admin), attr
}.to change { User.count }.by(1)
user = User.find_by(username: attr[:username])
user.projects_limit.should == limit
user.theme_id.should == Gitlab::Theme::MARS
Gitlab.config.gitlab.unstub(:default_projects_limit)
end
it "should not create user with invalid email" do
post api("/users", admin), { email: "invalid email", password: 'password' }
response.status.should == 400
......
require 'spec_helper'
describe Milestones::GroupService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) }
let(:project1) { create(:project, group: group) }
let(:project2) { create(:project, path: 'gitlab-ci', group: group) }
let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) }
let(:milestone1_project1) { create(:milestone, title: "Milestone v1.2", project: project1) }
let(:milestone1_project2) { create(:milestone, title: "Milestone v1.2", project: project2) }
let(:milestone1_project3) { create(:milestone, title: "Milestone v1.2", project: project3) }
let(:milestone2_project1) { create(:milestone, title: "VD-123", project: project1) }
let(:milestone2_project2) { create(:milestone, title: "VD-123", project: project2) }
let(:milestone2_project3) { create(:milestone, title: "VD-123", project: project3) }
describe 'execute' do
context 'with valid projects' do
before do
milestones =
[
milestone1_project1,
milestone1_project2,
milestone1_project3,
milestone2_project1,
milestone2_project2,
milestone2_project3
]
@group_milestones = Milestones::GroupService.new(milestones).execute
end
it 'should have all project milestones' do
expect(@group_milestones.count).to eq(2)
end
it 'should have all project milestones titles' do
expect(@group_milestones.map { |group_milestone| group_milestone.title }).to match_array(['Milestone v1.2', 'VD-123'])
end
it 'should have all project milestones' do
expect(@group_milestones.map { |group_milestone| group_milestone.milestones.count }.sum).to eq(6)
end
end
end
describe 'milestone' do
context 'with valid title' do
before do
milestones =
[
milestone1_project1,
milestone1_project2,
milestone1_project3,
milestone2_project1,
milestone2_project2,
milestone2_project3
]
@group_milestones = Milestones::GroupService.new(milestones).milestone('Milestone v1.2')
end
it 'should have exactly one group milestone' do
expect(@group_milestones.title).to eq('Milestone v1.2')
end
it 'should have all project milestones with the same title' do
expect(@group_milestones.milestones.count).to eq(3)
end
end
end
end
......@@ -11,7 +11,6 @@ describe Notes::CreateService do
project.team << [user, :master]
opts = {
note: 'Awesome comment',
description: 'please fix',
noteable_type: 'Issue',
noteable_id: issue.id
}
......
......@@ -215,7 +215,7 @@ describe NotificationService do
end
def should_email(user_id)
Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id, @u_disabled.id)
Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, nil, @u_disabled.id)
end
def should_not_email(user_id)
......@@ -242,6 +242,26 @@ describe NotificationService do
Notify.should_not_receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
end
end
describe :reopen_issue do
it 'should send email to issue assignee and issue author' do
should_email(issue.assignee_id)
should_email(issue.author_id)
should_email(@u_watcher.id)
should_not_email(@u_participating.id)
should_not_email(@u_disabled.id)
notification.reopen_issue(issue, @u_disabled)
end
def should_email(user_id)
Notify.should_receive(:issue_status_changed_email).with(user_id, issue.id, 'reopened', @u_disabled.id)
end
def should_not_email(user_id)
Notify.should_not_receive(:issue_status_changed_email).with(user_id, issue.id, 'reopened', @u_disabled.id)
end
end
end
describe 'Merge Requests' do
......@@ -279,7 +299,7 @@ describe NotificationService do
end
def should_email(user_id)
Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id, merge_request.author_id)
Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, nil, merge_request.author_id)
end
def should_not_email(user_id)
......@@ -322,6 +342,24 @@ describe NotificationService do
Notify.should_not_receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
end
end
describe :reopen_merge_request do
it do
should_email(merge_request.assignee_id)
should_email(@u_watcher.id)
should_not_email(@u_participating.id)
should_not_email(@u_disabled.id)
notification.reopen_mr(merge_request, @u_disabled)
end
def should_email(user_id)
Notify.should_receive(:merge_request_status_email).with(user_id, merge_request.id, 'reopened', @u_disabled.id)
end
def should_not_email(user_id)
Notify.should_not_receive(:merge_request_status_email).with(user_id, merge_request.id, 'reopened', @u_disabled.id)
end
end
end
describe 'Projects' do
......
......@@ -55,95 +55,6 @@ describe Projects::CreateService do
it { File.exists?(@path).should be_false }
end
end
context 'respect configured visibility setting' do
before(:each) do
@settings = double("settings")
@settings.stub(:issues) { true }
@settings.stub(:merge_requests) { true }
@settings.stub(:wiki) { true }
@settings.stub(:snippets) { true }
Gitlab.config.gitlab.stub(restricted_visibility_levels: [])
Gitlab.config.gitlab.stub(:default_projects_features).and_return(@settings)
end
context 'should be public when setting is public' do
before do
@settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PUBLIC }
@project = create_project(@user, @opts)
end
it { @project.public?.should be_true }
end
context 'should be private when setting is private' do
before do
@settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE }
@project = create_project(@user, @opts)
end
it { @project.private?.should be_true }
end
context 'should be internal when setting is internal' do
before do
@settings.stub(:visibility_level) { Gitlab::VisibilityLevel::INTERNAL }
@project = create_project(@user, @opts)
end
it { @project.internal?.should be_true }
end
end
context 'respect configured visibility restrictions setting' do
before(:each) do
@settings = double("settings")
@settings.stub(:issues) { true }
@settings.stub(:merge_requests) { true }
@settings.stub(:wiki) { true }
@settings.stub(:snippets) { true }
@settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE }
@restrictions = [ Gitlab::VisibilityLevel::PUBLIC ]
Gitlab.config.gitlab.stub(restricted_visibility_levels: @restrictions)
Gitlab.config.gitlab.stub(:default_projects_features).and_return(@settings)
end
context 'should be private when option is public' do
before do
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
@project = create_project(@user, @opts)
end
it { @project.private?.should be_true }
end
context 'should be public when option is public for admin' do
before do
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
@project = create_project(@admin, @opts)
end
it { @project.public?.should be_true }
end
context 'should be private when option is private' do
before do
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
@project = create_project(@user, @opts)
end
it { @project.private?.should be_true }
end
context 'should be internal when option is internal' do
before do
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
@project = create_project(@user, @opts)
end
it { @project.internal?.should be_true }
end
end
end
def create_project(user, opts)
......
......@@ -6,14 +6,14 @@ describe Projects::UpdateService do
@user = create :user
@admin = create :user, admin: true
@project = create :project, creator_id: @user.id, namespace: @user.namespace
@opts = { project: {} }
@opts = {}
end
context 'should be private when updated to private' do
before do
@created_private = @project.private?
@opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
update_project(@project, @user, @opts)
end
......@@ -25,7 +25,7 @@ describe Projects::UpdateService do
before do
@created_private = @project.private?
@opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
update_project(@project, @user, @opts)
end
......@@ -37,7 +37,7 @@ describe Projects::UpdateService do
before do
@created_private = @project.private?
@opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
update_project(@project, @user, @opts)
end
......@@ -56,7 +56,7 @@ describe Projects::UpdateService do
before do
@created_private = @project.private?
@opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
update_project(@project, @user, @opts)
end
......@@ -68,7 +68,7 @@ describe Projects::UpdateService do
before do
@created_private = @project.private?
@opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
update_project(@project, @user, @opts)
end
......@@ -80,7 +80,7 @@ describe Projects::UpdateService do
before do
@created_private = @project.private?
@opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
update_project(@project, @user, @opts)
end
......@@ -92,7 +92,7 @@ describe Projects::UpdateService do
before do
@created_private = @project.private?
@opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
@opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
update_project(@project, @admin, @opts)
end
......
......@@ -11,7 +11,7 @@ def common_mentionable_setup
let(:mentioned_issue) { create :issue, project: mproject }
let(:other_issue) { create :issue, project: mproject }
let(:mentioned_mr) { create :merge_request, source_project: mproject, source_branch: 'different' }
let(:mentioned_mr) { create :merge_request, :simple, source_project: mproject }
let(:mentioned_commit) { double('commit', sha: '1234567890abcdef').as_null_object }
# Override to add known commits to the repository stub.
......@@ -29,11 +29,7 @@ def common_mentionable_setup
# unrecognized commits.
commitmap = { '123456' => mentioned_commit }
extra_commits.each { |c| commitmap[c.sha[0..5]] = c }
repo = double('repository')
repo.stub(:commit) { |sha| commitmap[sha] }
mproject.stub(repository: repo)
mproject.repository.stub(:commit) { |sha| commitmap[sha] }
set_mentionable_text.call(ref_string)
end
end
......
This source diff could not be displayed because it is too large. You can view the blob instead.
var hljs=new function(){function k(v){return v.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset<y[0].offset)?w:y}return y[0].event=="start"?w:y}function A(H){function G(I){return" "+I.nodeName+'="'+k(I.value)+'"'}F+="<"+t(H)+Array.prototype.map.call(H.attributes,G).join("")+">"}function E(G){F+="</"+t(G)+">"}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T<V.c.length;T++){if(i(V.c[T].bR,U)){return V.c[T]}}}function z(U,T){if(i(U.eR,T)){return U}if(U.eW){return z(U.parent,T)}}function A(T,U){return !J&&i(U.iR,T)}function E(V,T){var U=M.cI?T[0].toLowerCase():T[0];return V.k.hasOwnProperty(U)&&V.k[U]}function w(Z,X,W,V){var T=V?"":b.classPrefix,U='<span class="'+T,Y=W?"":"</span>";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+="</span>"}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"<unnamed>")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+="</span>"}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"<br>")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("cs",function(b){var a="abstract as base bool break byte case catch char checked const continue decimal default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long new null object operator out override params private protected public readonly ref return sbyte sealed short sizeof stackalloc static string struct switch this throw true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while async await ascending descending from get group into join let orderby partial select set value var where yield";return{k:a,c:[{cN:"comment",b:"///",e:"$",rB:true,c:[{cN:"xmlDocTag",b:"///|<!--|-->"},{cN:"xmlDocTag",b:"</?",e:">"}]},b.CLCM,b.CBLCLM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line region endregion pragma checksum"},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},b.ASM,b.QSM,b.CNM,{bK:"protected public private internal",e:/[{;=]/,k:a,c:[{bK:"class namespace interface",starts:{c:[b.TM]}},{b:b.IR+"\\s*\\(",rB:true,c:[b.TM]}]}]}});hljs.registerLanguage("ruby",function(e){var h="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?";var g="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor";var a={cN:"yardoctag",b:"@[A-Za-z]+"};var i={cN:"comment",v:[{b:"#",e:"$",c:[a]},{b:"^\\=begin",e:"^\\=end",c:[a],r:10},{b:"^__END__",e:"\\n$"}]};var c={cN:"subst",b:"#\\{",e:"}",k:g};var d={cN:"string",c:[e.BE,c],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:"%[qw]?\\(",e:"\\)"},{b:"%[qw]?\\[",e:"\\]"},{b:"%[qw]?{",e:"}"},{b:"%[qw]?<",e:">",r:10},{b:"%[qw]?/",e:"/",r:10},{b:"%[qw]?%",e:"%",r:10},{b:"%[qw]?-",e:"-",r:10},{b:"%[qw]?\\|",e:"\\|",r:10},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]};var b={cN:"params",b:"\\(",e:"\\)",k:g};var f=[d,i,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+e.IR+"::)?"+e.IR}]},i]},{cN:"function",bK:"def",e:" |$|;",r:0,c:[e.inherit(e.TM,{b:h}),b,i]},{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:":",c:[d,{b:h}],r:0},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:[i,{cN:"regexp",c:[e.BE,c],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}],r:0}];c.c=f;b.c=f;return{k:g,c:f}});hljs.registerLanguage("diff",function(a){return{c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/</,e:/>;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/</,r:0,c:[d,{cN:"attribute",b:c,r:0},{b:"=",r:0,c:[{cN:"value",v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s\/>]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"<!DOCTYPE",e:">",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"<!--",e:"-->",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"<style(?=\\s|>|$)",e:">",k:{title:"style"},c:[b],starts:{e:"</style>",rE:true,sL:"css"}},{cN:"tag",b:"<script(?=\\s|>|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"</?",e:"/?>",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("java",function(b){var a="false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws";return{k:a,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}],r:10},b.CLCM,b.CBLCLM,b.ASM,b.QSM,{bK:"protected public private",e:/[{;=]/,k:a,c:[{cN:"class",bK:"class interface",eW:true,i:/[:"<>]/,c:[{bK:"extends implements",r:10},b.UTM]},{b:b.UIR+"\\s*\\(",rB:true,c:[b.UTM]}]},b.CNM,{cN:"annotation",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("php",function(b){var e={cN:"variable",b:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"};var a={cN:"preprocessor",b:/<\?(php)?|\?>/};var c={cN:"string",c:[b.BE,a],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},b.inherit(b.ASM,{i:null}),b.inherit(b.QSM,{i:null})]};var d={v:[b.BNM,b.CNM]};return{cI:true,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[b.CLCM,b.HCM,{cN:"comment",b:"/\\*",e:"\\*/",c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"},a]},{cN:"comment",b:"__halt_compiler.+?;",eW:true,k:"__halt_compiler",l:b.UIR},{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[b.BE]},a,e,{cN:"function",bK:"function",e:/[;{]/,i:"\\$|\\[|%",c:[b.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",e,b.CBLCLM,c,d]}]},{cN:"class",bK:"class interface",e:"{",i:/[:\(\$"]/,c:[{bK:"extends implements",r:10},b.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[b.UTM]},{bK:"use",e:";",c:[b.UTM]},{b:"=>"},c,d]}});hljs.registerLanguage("python",function(a){var f={cN:"prompt",b:/^(>>>|\.\.\.) /};var b={cN:"string",c:[a.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[f],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[f],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/,},{b:/(b|br)"/,e:/"/,},a.ASM,a.QSM]};var d={cN:"number",r:0,v:[{b:a.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:a.CNR+"[lLjJ]?"}]};var e={cN:"params",b:/\(/,e:/\)/,c:["self",f,d,b]};var c={e:/:/,i:/[${=;\n]/,c:[a.UTM,e]};return{k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},i:/(<\/|->|\?)/,c:[f,d,b,a.HCM,a.inherit(c,{cN:"function",bK:"def",r:10}),a.inherit(c,{cN:"class",bK:"class"}),{cN:"decorator",b:/@/,e:/$/},{b:/\b(print|exec)\(/}]}});hljs.registerLanguage("sql",function(a){return{cI:true,i:/[<>]/,c:[{cN:"operator",b:"\\b(begin|end|start|commit|rollback|savepoint|lock|alter|create|drop|rename|call|delete|do|handler|insert|load|replace|select|truncate|update|set|show|pragma|grant|merge)\\b(?!:)",e:";",eW:true,k:{keyword:"all partial global month current_timestamp using go revoke smallint indicator end-exec disconnect zone with character assertion to add current_user usage input local alter match collate real then rollback get read timestamp session_user not integer bit unique day minute desc insert execute like ilike|2 level decimal drop continue isolation found where constraints domain right national some module transaction relative second connect escape close system_user for deferred section cast current sqlstate allocate intersect deallocate numeric public preserve full goto initially asc no key output collation group by union session both last language constraint column of space foreign deferrable prior connection unknown action commit view or first into float year primary cascaded except restrict set references names table outer open select size are rows from prepare distinct leading create only next inner authorization schema corresponding option declare precision immediate else timezone_minute external varying translation true case exception join hour default double scroll value cursor descriptor values dec fetch procedure delete and false int is describe char as at in varchar null trailing any absolute current_time end grant privileges when cross check write current_date pad begin temporary exec time update catalog user sql date on identity timezone_hour natural whenever interval work order cascade diagnostics nchar having left call do handler load replace truncate start lock show pragma exists number trigger if before after each row merge matched database",aggregate:"count sum min max avg"},c:[{cN:"string",b:"'",e:"'",c:[a.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[a.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[a.BE]},a.CNM]},a.CBLCLM,{cN:"comment",b:"--",e:"$"}]}});hljs.registerLanguage("ini",function(a){return{cI:true,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM],r:0}]}]}});hljs.registerLanguage("perl",function(c){var d="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when";var f={cN:"subst",b:"[$@]\\{",e:"\\}",k:d};var g={b:"->{",e:"}"};var a={cN:"variable",v:[{b:/\$\d/},{b:/[\$\%\@\*](\^\w\b|#\w+(\:\:\w+)*|{\w+}|\w+(\:\:\w*)*)/},{b:/[\$\%\@\*][^\s\w{]/,r:0}]};var e={cN:"comment",b:"^(__END__|__DATA__)",e:"\\n$",r:5};var h=[c.BE,f,a];var b=[a,c.HCM,e,{cN:"comment",b:"^\\=\\w",e:"\\=cut",eW:true},g,{cN:"string",c:h,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[c.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[c.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+c.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[c.HCM,e,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[c.BE],r:0}]},{cN:"sub",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",r:5},{cN:"operator",b:"-\\w\\b",r:0}];f.c=b;g.c=b;return{k:d,c:b}});hljs.registerLanguage("objectivec",function(a){var d={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign self synchronized id nonatomic super unichar IBOutlet IBAction strong weak @private @protected @public @try @property @end @throw @catch @finally @synthesize @dynamic @selector @optional @required",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"NSString NSDictionary CGRect CGPoint UIButton UILabel UITextView UIWebView MKMapView UISegmentedControl NSObject UITableViewDelegate UITableViewDataSource NSThread UIActivityIndicator UITabbar UIToolBar UIBarButtonItem UIImageView NSAutoreleasePool UITableView BOOL NSInteger CGFloat NSException NSLog NSMutableString NSMutableArray NSMutableDictionary NSURL NSIndexPath CGSize UITableViewCell UIView UIViewController UINavigationBar UINavigationController UITabBarController UIPopoverController UIPopoverControllerDelegate UIImage NSNumber UISearchBar NSFetchedResultsController NSFetchedResultsChangeType UIScrollView UIScrollViewDelegate UIEdgeInsets UIColor UIFont UIApplication NSNotFound NSNotificationCenter NSNotification UILocalNotification NSBundle NSFileManager NSTimeInterval NSDate NSCalendar NSUserDefaults UIWindow NSRange NSArray NSError NSURLRequest NSURLConnection UIInterfaceOrientation MPMoviePlayerController dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"};var c=/[a-zA-Z@][a-zA-Z0-9_]*/;var b="@interface @class @protocol @implementation";return{k:d,l:c,i:"</",c:[a.CLCM,a.CBLCLM,a.CNM,a.QSM,{cN:"string",b:"'",e:"[^\\\\]'",i:"[^\\\\][^']"},{cN:"preprocessor",b:"#import",e:"$",c:[{cN:"title",b:'"',e:'"'},{cN:"title",b:"<",e:">"}]},{cN:"preprocessor",b:"#",e:"$"},{cN:"class",b:"("+b.split(" ").join("|")+")\\b",e:"({|$)",k:b,l:c,c:[a.UTM]},{cN:"variable",b:"\\."+a.UIR,r:0}]}});hljs.registerLanguage("coffeescript",function(c){var b={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",reserved:"case default function var void with const let enum export import native __hasProp __extends __slice __bind __indexOf",built_in:"npm require console print module exports global window document"};var a="[A-Za-z$_][0-9A-Za-z$_]*";var f=c.inherit(c.TM,{b:a});var e={cN:"subst",b:/#\{/,e:/}/,k:b};var d=[c.BNM,c.inherit(c.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[c.BE]},{b:/'/,e:/'/,c:[c.BE]},{b:/"""/,e:/"""/,c:[c.BE,e]},{b:/"/,e:/"/,c:[c.BE,e]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[e,c.HCM]},{b:"//[gim]*",r:0},{b:"/\\S(\\\\.|[^\\n])*?/[gim]*(?=\\s|\\W|$)"}]},{cN:"property",b:"@"+a},{b:"`",e:"`",eB:true,eE:true,sL:"javascript"}];e.c=d;return{k:b,c:d.concat([{cN:"comment",b:"###",e:"###"},c.HCM,{cN:"function",b:"("+a+"\\s*=\\s*)?(\\(.*\\))?\\s*\\B[-=]>",e:"[-=]>",rB:true,c:[f,{cN:"params",b:"\\(",rB:true,c:[{b:/\(/,e:/\)/,k:b,c:["self"].concat(d)}]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:true,i:/[:="\[\]]/,c:[f]},f]},{cN:"attribute",b:a+":",e:":",rB:true,eE:true,r:0}])}});hljs.registerLanguage("nginx",function(c){var b={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+c.UIR}]};var a={eW:true,l:"[a-z/_]+",k:{built_in:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[c.HCM,{cN:"string",c:[c.BE,b],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{cN:"url",b:"([a-z]+):/",e:"\\s",eW:true,eE:true},{cN:"regexp",c:[c.BE,b],v:[{b:"\\s\\^",e:"\\s|{|;",rE:true},{b:"~\\*?\\s+",e:"\\s|{|;",rE:true},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},b]};return{c:[c.HCM,{b:c.UIR+"\\s",e:";|{",rB:true,c:[c.inherit(c.UTM,{starts:a})],r:0}],i:"[^\\s\\}]"}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}});hljs.registerLanguage("apache",function(a){var b={cN:"number",b:"[\\$%]\\d+"};return{cI:true,c:[a.HCM,{cN:"tag",b:"</?",e:">"},{cN:"keyword",b:/\w+/,r:0,k:{common:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"sqbracket",b:"\\s\\[",e:"\\]$"},{cN:"cbracket",b:"[\\$%]\\{",e:"\\}",c:["self",b]},b,a.QSM]}}],i:/\S/}});hljs.registerLanguage("cpp",function(a){var b={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long throw volatile static protected bool template mutable if public friend do return goto auto void enum else break new extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex _Complex _Imaginary",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf"};return{aliases:["c"],k:b,i:"</",c:[a.CLCM,a.CBLCLM,a.QSM,{cN:"string",b:"'\\\\?.",e:"'",i:"."},{cN:"number",b:"\\b(\\d+(\\.\\d*)?|\\.\\d+)(u|U|l|L|ul|UL|f|F)"},a.CNM,{cN:"preprocessor",b:"#",e:"$",c:[{b:"include\\s*<",e:">",i:"\\n"},a.CLCM]},{cN:"stl_container",b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:b,r:10,c:["self"]}]}});hljs.registerLanguage("makefile",function(a){var b={cN:"variable",b:/\$\(/,e:/\)/,c:[a.BE]};return{c:[a.HCM,{b:/^\w+\s*\W*=/,rB:true,r:0,starts:{cN:"constant",e:/\s*\W*=/,eE:true,starts:{e:/$/,r:0,c:[b],}}},{cN:"title",b:/^[\w]+:\s*$/},{cN:"phony",b:/^\.PHONY:/,e:/$/,k:".PHONY",l:/[\.\w]+/},{b:/^\t+/,e:/$/,c:[a.QSM,b]}]}});
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment