Merge branch 'master' into ldap-sync-group-members
@@ -1,8 +1,16 @@
|
||||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 7.14.0 (unreleased)
|
||||
- Fix multi-line syntax highlighting (Stan Hu)
|
||||
- Fix network graph when branch name has single quotes (Stan Hu)
|
||||
- Upgrade gitlab_git to version 7.2.6 to fix Error 500 when creating network graphs (Stan Hu)
|
||||
- Add support for Unicode filenames in relative links (Hiroyuki Sato)
|
||||
- Fix URL used for refreshing notes if relative_url is present (Bartłomiej Święcki)
|
||||
- Fix commit data retrieval when branch name has single quotes (Stan Hu)
|
||||
- Check that project was actually created rather than just validated in import:repos task (Stan Hu)
|
||||
- Fix full screen mode for snippet comments (Daniel Gerhardt)
|
||||
- Fix 404 error in files view after deleting the last file in a repository (Stan Hu)
|
||||
- Fix the "Reload with full diff" URL button (Stan Hu)
|
||||
- Fix label read access for unauthenticated users (Daniel Gerhardt)
|
||||
- Fix access to disabled features for unauthenticated users (Daniel Gerhardt)
|
||||
- Fix OAuth provider bug where GitLab would not go return to the redirect_uri after sign-in (Stan Hu)
|
||||
@@ -10,17 +18,40 @@ v 7.14.0 (unreleased)
|
||||
- Set OmniAuth full_host parameter to ensure redirect URIs are correct (Stan Hu)
|
||||
- Expire Rails cache entries after two weeks to prevent endless Redis growth
|
||||
- Add support for destroying project milestones (Stan Hu)
|
||||
- Add fetch command to the MR page
|
||||
- Add project star and fork count, group avatar URL and user/group web URL attributes to API
|
||||
- Fix bug causing Bitbucket importer to crash when OAuth application had been removed.
|
||||
- Add fetch command to the MR page.
|
||||
- Fix bug causing "Remove source-branch" option not to work for merge requests from the same project.
|
||||
- Fix approvals for forks. Now you can change approvals settings on the new merge request form
|
||||
- Suggested approvers are shown on the new merge request form
|
||||
- Disabled autocapitalize and autocorrect on login field (Daryl Chan)
|
||||
- Mention group and project name in creation, update and deletion notices (Achilleas Pipinellis)
|
||||
|
||||
v 7.13.2
|
||||
- Fix randomly failed spec
|
||||
- Create project services on Project creation
|
||||
- Add admin_merge_request ability to Developer level and up
|
||||
- Fix Error 500 when browsing projects with no HEAD (Stan Hu)
|
||||
- Fix labels / assignee / milestone for the merge requests when issues are disabled
|
||||
- Show the first tab automatically on MergeRequests#new
|
||||
- Add rake task 'gitlab:update_commit_count' (Daniel Gerhardt)
|
||||
- Fix Gmail Actions
|
||||
|
||||
v 7.13.1
|
||||
- Revert issue caching
|
||||
- Reverted cache for events
|
||||
- Fix: Label modifications are not reflected in existing notes and in the issue list
|
||||
- Fix: Label not shown in the Issue list, although it's set through web interface
|
||||
- Fix: Group/project references are linked incorrectly
|
||||
- Improve documentation
|
||||
- Fix of migration: Check if session_expire_delay column exists before adding the column
|
||||
- Fix: ActionView::Template::Error
|
||||
- Fix: "Create Merge Request" isn't always shown in event for newly pushed branch
|
||||
- Fix bug causing "Remove source-branch" option not to work for merge requests from the same project.
|
||||
- Render Note field hints consistently for "new" and "edit" forms
|
||||
|
||||
v 7.13.0 (unreleased)
|
||||
v 7.13.0
|
||||
- Remove repository graph log to fix slow cache updates after push event (Stan Hu)
|
||||
- Return comments in created order in merge request API (Stan Hu)
|
||||
- Only enable HSTS header for HTTPS and port 443 (Stan Hu)
|
||||
- Fix user autocomplete for unauthenticated users accessing public projects (Stan Hu)
|
||||
- Fix redirection to home page URL for unauthorized users (Daniel Gerhardt)
|
||||
@@ -74,6 +105,7 @@ v 7.12.2
|
||||
- Faster automerge check and merge itself when source and target branches are in same repository
|
||||
- Audit log for user authentication
|
||||
- Fix transferring of project to another group using the API.
|
||||
- Allow custom label to be set for authentication providers.
|
||||
|
||||
v 7.12.1
|
||||
- Fix error when deleting a user who has projects (Stan Hu)
|
||||
|
||||
@@ -38,7 +38,7 @@ gem "browser", '~> 0.8.0'
|
||||
|
||||
# Extracting information from a git repository
|
||||
# Provide access to Gitlab::Git library
|
||||
gem "gitlab_git", '~> 7.2.5'
|
||||
gem "gitlab_git", '~> 7.2.6'
|
||||
|
||||
# Ruby/Rack Git Smart-HTTP Server Handler
|
||||
# GitLab fork with a lot of changes (improved thread-safety, better memory usage etc)
|
||||
@@ -275,4 +275,3 @@ end
|
||||
gem "newrelic_rpm"
|
||||
|
||||
gem 'octokit', '3.7.0'
|
||||
gem "rugments", "~> 1.0.0.beta8"
|
||||
|
||||
@@ -272,7 +272,7 @@ GEM
|
||||
mime-types (~> 1.19)
|
||||
gitlab_emoji (0.1.0)
|
||||
gemojione (~> 2.0)
|
||||
gitlab_git (7.2.5)
|
||||
gitlab_git (7.2.6)
|
||||
activesupport (~> 4.0)
|
||||
charlock_holmes (~> 0.6)
|
||||
gitlab-linguist (~> 3.0)
|
||||
@@ -289,7 +289,7 @@ GEM
|
||||
github-markup (~> 1.3.1)
|
||||
gollum-grit_adapter (~> 0.1, >= 0.1.1)
|
||||
nokogiri (~> 1.6.4)
|
||||
rouge (~> 1.7.4)
|
||||
rouge (~> 1.9)
|
||||
sanitize (~> 2.1.0)
|
||||
stringex (~> 2.5.1)
|
||||
gon (5.0.1)
|
||||
@@ -537,7 +537,7 @@ GEM
|
||||
netrc (~> 0.7)
|
||||
rinku (1.7.3)
|
||||
rotp (1.6.1)
|
||||
rouge (1.7.7)
|
||||
rouge (1.9.1)
|
||||
rqrcode (0.4.2)
|
||||
rqrcode-rails3 (0.1.7)
|
||||
rqrcode (>= 0.4.2)
|
||||
@@ -580,7 +580,6 @@ GEM
|
||||
rubyntlm (0.5.0)
|
||||
rubypants (0.2.0)
|
||||
rugged (0.22.2)
|
||||
rugments (1.0.0.beta8)
|
||||
safe_yaml (1.0.4)
|
||||
sanitize (2.1.0)
|
||||
nokogiri (>= 1.4.4)
|
||||
@@ -786,7 +785,7 @@ DEPENDENCIES
|
||||
gitlab-license (~> 0.0.2)
|
||||
gitlab-linguist (~> 3.0.1)
|
||||
gitlab_emoji (~> 0.1)
|
||||
gitlab_git (~> 7.2.5)
|
||||
gitlab_git (~> 7.2.6)
|
||||
gitlab_meta (= 7.0)
|
||||
gitlab_omniauth-ldap (= 1.2.1)
|
||||
gollum-lib (~> 4.0.2)
|
||||
@@ -839,7 +838,6 @@ DEPENDENCIES
|
||||
rqrcode-rails3
|
||||
rspec-rails (~> 3.3.0)
|
||||
rubocop (= 0.28.0)
|
||||
rugments (~> 1.0.0.beta8)
|
||||
sanitize (~> 2.0)
|
||||
sass-rails (~> 4.0.5)
|
||||
sdoc
|
||||
|
||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 6.4 KiB |
@@ -166,9 +166,10 @@ $ ->
|
||||
$('.account-box').hover -> $(@).toggleClass('hover')
|
||||
|
||||
# Commit show suppressed diff
|
||||
$(".diff-content").on "click", ".supp_diff_link", ->
|
||||
$(@).next('table').show()
|
||||
$(@).remove()
|
||||
$(document).on 'click', '.diff-content .js-show-suppressed-diff', ->
|
||||
$container = $(@).parent()
|
||||
$container.next('table').show()
|
||||
$container.remove()
|
||||
|
||||
$('.navbar-toggle').on 'click', ->
|
||||
$('.header-content .title').toggle()
|
||||
|
||||
@@ -31,6 +31,10 @@ class @Diff
|
||||
bottom: unfoldBottom
|
||||
offset: offset
|
||||
unfold: unfold
|
||||
# indent is used to compensate for single space indent to fit
|
||||
# '+' and '-' prepended to diff lines,
|
||||
# see https://gitlab.com/gitlab-org/gitlab-ce/issues/707
|
||||
indent: 1
|
||||
|
||||
$.get(link, params, (response) =>
|
||||
target.parent().replaceWith(response)
|
||||
|
||||
@@ -49,12 +49,6 @@ class @MergeRequestTabs
|
||||
# Store the `location` object, allowing for easier stubbing in tests
|
||||
@_location = location
|
||||
|
||||
switch @opts.action
|
||||
when 'commits'
|
||||
@commitsLoaded = true
|
||||
when 'diffs'
|
||||
@diffsLoaded = true
|
||||
|
||||
@bindEvents()
|
||||
@activateTab(@opts.action)
|
||||
|
||||
@@ -102,7 +96,7 @@ class @MergeRequestTabs
|
||||
action = 'notes' if action == 'show'
|
||||
|
||||
# Remove a trailing '/commits' or '/diffs'
|
||||
new_state = @_location.pathname.replace(/\/(commits|diffs)\/?$/, '')
|
||||
new_state = @_location.pathname.replace(/\/(commits|diffs)(\.html)?\/?$/, '')
|
||||
|
||||
# Append the new action if we're on a tab other than 'notes'
|
||||
unless action == 'notes'
|
||||
@@ -133,7 +127,7 @@ class @MergeRequestTabs
|
||||
return if @diffsLoaded
|
||||
|
||||
@_get
|
||||
url: "#{source}.json"
|
||||
url: "#{source}.json" + @_location.search
|
||||
success: (data) =>
|
||||
document.getElementById('diffs').innerHTML = data.html
|
||||
@diffsLoaded = true
|
||||
|
||||
@@ -10,7 +10,6 @@ class @Notes
|
||||
|
||||
constructor: (notes_url, note_ids, last_fetched_at, view) ->
|
||||
@notes_url = notes_url
|
||||
@notes_url = gon.relative_url_root + @notes_url if gon.relative_url_root?
|
||||
@note_ids = note_ids
|
||||
@last_fetched_at = last_fetched_at
|
||||
@view = view
|
||||
|
||||
@@ -184,7 +184,7 @@ li.note {
|
||||
}
|
||||
}
|
||||
|
||||
.supp_diff_link,
|
||||
.show-suppressed-diff,
|
||||
.show-all-commits {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.suppressed-container {
|
||||
padding: ($padding-base-vertical + 5px) $padding-base-horizontal;
|
||||
text-align: center;
|
||||
|
||||
// "Changes suppressed. Click to show." link
|
||||
.show-suppressed-diff {
|
||||
font-size: 110%;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
font-family: $monospace_font;
|
||||
|
||||
@@ -37,7 +37,7 @@ ul.notes {
|
||||
font-size: 13px;
|
||||
|
||||
a {
|
||||
@extend .cgray;
|
||||
@extend .cgray;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
@@ -105,6 +105,8 @@ ul.notes {
|
||||
}
|
||||
|
||||
hr {
|
||||
// Darken 'whitesmoke' a bit to make it more visible in note bodies
|
||||
border-color: darken(#F5F5F5, 8%);
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,14 +305,14 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def github_import_enabled?
|
||||
OauthHelper.enabled_oauth_providers.include?(:github)
|
||||
Gitlab::OAuth::Provider.enabled?(:github)
|
||||
end
|
||||
|
||||
def gitlab_import_enabled?
|
||||
OauthHelper.enabled_oauth_providers.include?(:gitlab)
|
||||
Gitlab::OAuth::Provider.enabled?(:gitlab)
|
||||
end
|
||||
|
||||
def bitbucket_import_enabled?
|
||||
OauthHelper.enabled_oauth_providers.include?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
|
||||
Gitlab::OAuth::Provider.enabled?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,10 @@ class Groups::ApplicationController < ApplicationController
|
||||
|
||||
private
|
||||
|
||||
def group
|
||||
@group ||= Group.find_by(path: params[:group_id])
|
||||
end
|
||||
|
||||
def authorize_read_group!
|
||||
unless @group and can?(current_user, :read_group, @group)
|
||||
if current_user.nil?
|
||||
@@ -19,7 +23,9 @@ class Groups::ApplicationController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def group
|
||||
@group ||= Group.find_by(path: params[:group_id])
|
||||
def authorize_admin_group_member!
|
||||
unless can?(current_user, :admin_group_member, group)
|
||||
return render_403
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
||||
# Authorize
|
||||
before_action :authorize_read_group!
|
||||
before_action :authorize_admin_group!, except: [:index, :leave]
|
||||
before_action :authorize_admin_group_member!, only: [:create, :resend_invite]
|
||||
|
||||
def index
|
||||
@project = @group.projects.find(params[:project_id]) if params[:project_id]
|
||||
@@ -36,6 +37,9 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
||||
|
||||
def update
|
||||
@member = @group.group_members.find(params[:id])
|
||||
|
||||
return render_403 unless can?(current_user, :update_group_member, @member)
|
||||
|
||||
old_access_level = @member.human_access
|
||||
|
||||
if @member.update_attributes(member_params)
|
||||
|
||||
@@ -24,7 +24,7 @@ class GroupsController < Groups::ApplicationController
|
||||
|
||||
if @group.save
|
||||
@group.add_owner(current_user)
|
||||
redirect_to @group, notice: 'Group was successfully created.'
|
||||
redirect_to @group, notice: "Group '#{@group.name}' was successfully created."
|
||||
else
|
||||
render action: "new"
|
||||
end
|
||||
@@ -77,7 +77,7 @@ class GroupsController < Groups::ApplicationController
|
||||
|
||||
def update
|
||||
if @group.update_attributes(group_params)
|
||||
redirect_to edit_group_path(@group), notice: 'Group was successfully updated.'
|
||||
redirect_to edit_group_path(@group), notice: "Group '#{@group.name}' was successfully updated."
|
||||
else
|
||||
render action: "edit"
|
||||
end
|
||||
@@ -86,7 +86,7 @@ class GroupsController < Groups::ApplicationController
|
||||
def destroy
|
||||
DestroyGroupService.new(@group, current_user).execute
|
||||
|
||||
redirect_to root_path, notice: 'Group was removed.'
|
||||
redirect_to root_path, alert: "Group '#{@group.name} was deleted."
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
@@ -3,6 +3,7 @@ class Import::BitbucketController < Import::BaseController
|
||||
before_action :bitbucket_auth, except: :callback
|
||||
|
||||
rescue_from OAuth::Error, with: :bitbucket_unauthorized
|
||||
rescue_from Gitlab::BitbucketImport::Client::Unauthorized, with: :bitbucket_unauthorized
|
||||
|
||||
def callback
|
||||
request_token = session.delete(:oauth_request_token)
|
||||
|
||||
@@ -77,10 +77,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
end
|
||||
end
|
||||
rescue Gitlab::OAuth::SignupDisabledError => e
|
||||
message = "Signing in using your #{oauth['provider']} account without a pre-existing GitLab account is not allowed."
|
||||
label = Gitlab::OAuth::Provider.label_for(oauth['provider'])
|
||||
message = "Signing in using your #{label} account without a pre-existing GitLab account is not allowed."
|
||||
|
||||
if current_application_settings.signup_enabled?
|
||||
message << " Create a GitLab account first, and then connect it to your #{oauth['provider']} account."
|
||||
message << " Create a GitLab account first, and then connect it to your #{label} account."
|
||||
end
|
||||
|
||||
flash[:notice] = message
|
||||
|
||||
@@ -7,6 +7,10 @@ class Projects::NetworkController < Projects::ApplicationController
|
||||
before_action :authorize_download_code!
|
||||
|
||||
def show
|
||||
|
||||
@url = namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json))
|
||||
@commit_url = namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s")
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
class Projects::RefsController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
include TreeHelper
|
||||
|
||||
before_action :require_non_empty_project
|
||||
before_action :assign_ref_vars
|
||||
@@ -60,6 +61,11 @@ class Projects::RefsController < Projects::ApplicationController
|
||||
}
|
||||
end
|
||||
|
||||
if @logs.present?
|
||||
@log_url = namespace_project_tree_url(@project.namespace, @project, tree_join(@ref, @path || '/'))
|
||||
@more_log_url = logs_file_namespace_project_ref_path(@project.namespace, @project, @ref, @path || '', offset: (@offset + @limit))
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render_404 }
|
||||
format.js
|
||||
|
||||
@@ -24,7 +24,7 @@ class ProjectsController < ApplicationController
|
||||
if @project.saved?
|
||||
redirect_to(
|
||||
project_path(@project),
|
||||
notice: 'Project was successfully created.'
|
||||
notice: "Project '#{@project.name}' was successfully created."
|
||||
)
|
||||
else
|
||||
render 'new'
|
||||
@@ -36,11 +36,11 @@ class ProjectsController < ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
if status
|
||||
flash[:notice] = 'Project was successfully updated.'
|
||||
flash[:notice] = "Project '#{@project.name}' was successfully updated."
|
||||
format.html do
|
||||
redirect_to(
|
||||
edit_project_path(@project),
|
||||
notice: 'Project was successfully updated.'
|
||||
notice: "Project '#{@project.name}' was successfully updated."
|
||||
)
|
||||
end
|
||||
format.js
|
||||
@@ -100,7 +100,7 @@ class ProjectsController < ApplicationController
|
||||
return access_denied! unless can?(current_user, :remove_project, @project)
|
||||
|
||||
::Projects::DestroyService.new(@project, current_user, {}).execute
|
||||
flash[:alert] = 'Project deleted.'
|
||||
flash[:alert] = "Project '#{@project.name}' was deleted."
|
||||
|
||||
if request.referer.include?('/admin')
|
||||
redirect_to admin_namespaces_projects_path
|
||||
|
||||
@@ -90,7 +90,7 @@ class SessionsController < Devise::SessionsController
|
||||
# Prevent alert from popping up on the first page shown after authentication.
|
||||
flash[:alert] = nil
|
||||
|
||||
redirect_to omniauth_authorize_path(:user, provider.to_sym)
|
||||
redirect_to user_omniauth_authorize_path(provider.to_sym)
|
||||
end
|
||||
|
||||
def valid_otp_attempt?(user)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
module AuthHelper
|
||||
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
|
||||
FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos'].freeze
|
||||
|
||||
def ldap_enabled?
|
||||
Gitlab.config.ldap.enabled
|
||||
end
|
||||
|
||||
def kerberos_enabled?
|
||||
enabled_oauth_providers.include?(:kerberos)
|
||||
end
|
||||
|
||||
def provider_has_icon?(name)
|
||||
PROVIDERS_WITH_ICONS.include?(name.to_s)
|
||||
end
|
||||
|
||||
def auth_providers
|
||||
Gitlab::OAuth::Provider.providers
|
||||
end
|
||||
|
||||
def label_for_provider(name)
|
||||
Gitlab::OAuth::Provider.label_for(name)
|
||||
end
|
||||
|
||||
def form_based_provider?(name)
|
||||
FORM_BASED_PROVIDERS.any? { |pattern| pattern === name.to_s }
|
||||
end
|
||||
|
||||
def form_based_providers
|
||||
auth_providers.select { |provider| form_based_provider?(provider) }
|
||||
end
|
||||
|
||||
def button_based_providers
|
||||
auth_providers.reject { |provider| form_based_provider?(provider) }
|
||||
end
|
||||
|
||||
def provider_image_tag(provider, size = 64)
|
||||
label = label_for_provider(provider)
|
||||
|
||||
if provider_has_icon?(provider)
|
||||
file_name = "#{provider.to_s.split('_').first}_#{size}.png"
|
||||
|
||||
image_tag(image_path("auth_buttons/#{file_name}"), alt: label, title: "Sign in with #{label}")
|
||||
else
|
||||
label
|
||||
end
|
||||
end
|
||||
|
||||
def auth_active?(provider)
|
||||
current_user.identities.exists?(provider: provider.to_s)
|
||||
end
|
||||
|
||||
extend self
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
module BlobHelper
|
||||
def highlight(blob_name, blob_content, nowrap: false, continue: false)
|
||||
@formatter ||= Rugments::Formatters::HTML.new(
|
||||
@formatter ||= Rouge::Formatters::HTMLGitlab.new(
|
||||
nowrap: nowrap,
|
||||
cssclass: 'code highlight',
|
||||
lineanchors: true,
|
||||
@@ -8,11 +8,11 @@ module BlobHelper
|
||||
)
|
||||
|
||||
begin
|
||||
@lexer ||= Rugments::Lexer.guess(filename: blob_name, source: blob_content).new
|
||||
@lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new
|
||||
result = @formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe
|
||||
rescue
|
||||
lexer = Rugments::Lexers::PlainText
|
||||
result = @formatter.format(lexer.lex(blob_content)).html_safe
|
||||
@lexer = Rouge::Lexers::PlainText
|
||||
result = @formatter.format(@lexer.lex(blob_content)).html_safe
|
||||
end
|
||||
|
||||
result
|
||||
|
||||
@@ -31,8 +31,8 @@ module EmailsHelper
|
||||
end
|
||||
|
||||
def color_email_diff(diffcontent)
|
||||
formatter = Rugments::Formatters::HTML.new(cssclass: "highlight", inline_theme: :github)
|
||||
lexer = Rugments::Lexers::Diff.new
|
||||
formatter = Rouge::Formatters::HTML.new(css_class: 'highlight', inline_theme: 'github')
|
||||
lexer = Rouge::Lexers::Diff
|
||||
raw formatter.format(lexer.lex(diffcontent))
|
||||
end
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
module OauthHelper
|
||||
def ldap_enabled?
|
||||
Gitlab.config.ldap.enabled
|
||||
end
|
||||
|
||||
def kerberos_enabled?
|
||||
enabled_oauth_providers.include?(:kerberos)
|
||||
end
|
||||
|
||||
def standard_login_form_only?
|
||||
ldap_enabled? || kerberos_enabled?
|
||||
end
|
||||
|
||||
def default_providers
|
||||
[:twitter, :github, :gitlab, :bitbucket, :google_oauth2, :ldap]
|
||||
end
|
||||
|
||||
def enabled_oauth_providers
|
||||
Devise.omniauth_providers
|
||||
end
|
||||
|
||||
def enabled_social_providers
|
||||
enabled_oauth_providers.select do |name|
|
||||
[:saml, :twitter, :gitlab, :github, :bitbucket, :google_oauth2, :kerberos].include?(name.to_sym)
|
||||
end
|
||||
end
|
||||
|
||||
def additional_providers
|
||||
enabled_oauth_providers.reject do |provider|
|
||||
provider.to_s.starts_with?('ldap') || provider == :kerberos
|
||||
end
|
||||
end
|
||||
|
||||
def oauth_image_tag(provider, size = 64)
|
||||
file_name = "#{provider.to_s.split('_').first}_#{size}.png"
|
||||
image_tag(image_path("authbuttons/#{file_name}"), alt: "Sign in with #{provider.to_s.titleize}")
|
||||
end
|
||||
|
||||
def oauth_active?(provider)
|
||||
current_user.identities.exists?(provider: provider.to_s)
|
||||
end
|
||||
|
||||
extend self
|
||||
end
|
||||
@@ -1,13 +0,0 @@
|
||||
module ProfileHelper
|
||||
def show_profile_username_tab?
|
||||
current_user.can_change_username?
|
||||
end
|
||||
|
||||
def show_profile_social_tab?
|
||||
enabled_social_providers.any?
|
||||
end
|
||||
|
||||
def show_profile_remove_tab?
|
||||
signup_enabled?
|
||||
end
|
||||
end
|
||||
@@ -286,7 +286,8 @@ module ProjectsHelper
|
||||
end
|
||||
|
||||
def readme_cache_key
|
||||
[@project.id, @project.commit.sha, "readme"].join('-')
|
||||
sha = @project.commit.try(:sha) || 'nil'
|
||||
[@project.id, sha, "readme"].join('-')
|
||||
end
|
||||
|
||||
def round_commit_count(project)
|
||||
|
||||
@@ -156,12 +156,13 @@ class Ability
|
||||
:create_project_snippet,
|
||||
:update_issue,
|
||||
:admin_issue,
|
||||
:admin_label,
|
||||
:admin_label
|
||||
]
|
||||
end
|
||||
|
||||
def project_dev_rules
|
||||
project_report_rules + [
|
||||
:admin_merge_request,
|
||||
:create_merge_request,
|
||||
:create_wiki,
|
||||
:push_code
|
||||
@@ -248,7 +249,8 @@ class Ability
|
||||
if group.has_owner?(user) || user.admin?
|
||||
rules.push(*[
|
||||
:admin_group,
|
||||
:admin_namespace
|
||||
:admin_namespace,
|
||||
:admin_group_member
|
||||
])
|
||||
|
||||
unless group.ldap_synced?
|
||||
|
||||
@@ -159,6 +159,16 @@ module Issuable
|
||||
end
|
||||
end
|
||||
|
||||
# Convert this Issuable class name to a format usable by Ability definitions
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# issuable.class # => MergeRequest
|
||||
# issuable.to_ability_name # => "merge_request"
|
||||
def to_ability_name
|
||||
self.class.to_s.underscore
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def filter_superceded_votes(votes, notes)
|
||||
|
||||
@@ -60,6 +60,12 @@ class Group < Namespace
|
||||
name
|
||||
end
|
||||
|
||||
def avatar_url(size = nil)
|
||||
if avatar.present?
|
||||
[gitlab_config.url, avatar.url].join
|
||||
end
|
||||
end
|
||||
|
||||
def owners
|
||||
@owners ||= group_members.owners.map(&:user)
|
||||
end
|
||||
|
||||
@@ -36,7 +36,6 @@ class Project < ActiveRecord::Base
|
||||
include Gitlab::ConfigHelper
|
||||
include Gitlab::ShellAdapter
|
||||
include Gitlab::VisibilityLevel
|
||||
include Rails.application.routes.url_helpers
|
||||
include Referable
|
||||
include Sortable
|
||||
|
||||
@@ -323,7 +322,7 @@ class Project < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def web_url
|
||||
[gitlab_config.url, path_with_namespace].join('/')
|
||||
Rails.application.routes.url_helpers.namespace_project_url(self.namespace, self)
|
||||
end
|
||||
|
||||
def web_url_without_protocol
|
||||
@@ -448,7 +447,7 @@ class Project < ActiveRecord::Base
|
||||
if avatar.present?
|
||||
[gitlab_config.url, avatar.url].join
|
||||
elsif avatar_in_git
|
||||
[gitlab_config.url, namespace_project_avatar_path(namespace, self)].join
|
||||
Rails.application.routes.url_helpers.namespace_project_avatar_url(namespace, self)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -591,7 +590,7 @@ class Project < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def http_url_to_repo
|
||||
[gitlab_config.url, '/', path_with_namespace, '.git'].join('')
|
||||
"#{web_url}.git"
|
||||
end
|
||||
|
||||
# Check if current branch name is marked as protected in the system
|
||||
@@ -733,14 +732,14 @@ class Project < ActiveRecord::Base
|
||||
ensure_satellite_exists
|
||||
true
|
||||
else
|
||||
errors.add(:base, 'Failed to fork repository')
|
||||
errors.add(:base, 'Failed to fork repository via gitlab-shell')
|
||||
false
|
||||
end
|
||||
else
|
||||
if gitlab_shell.add_repository(path_with_namespace)
|
||||
true
|
||||
else
|
||||
errors.add(:base, 'Failed to create repository')
|
||||
errors.add(:base, 'Failed to create repository via gitlab-shell')
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -281,6 +281,10 @@ class User < ActiveRecord::Base
|
||||
value: login.to_s.downcase).first
|
||||
end
|
||||
|
||||
def find_by_username!(username)
|
||||
find_by!('lower(username) = ?', username.downcase)
|
||||
end
|
||||
|
||||
def by_username_or_id(name_or_id)
|
||||
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
|
||||
end
|
||||
|
||||
@@ -27,8 +27,10 @@ class IssuableBaseService < BaseService
|
||||
old_branch, new_branch)
|
||||
end
|
||||
|
||||
def filter_params
|
||||
unless can?(current_user, :admin_issue, project)
|
||||
def filter_params(issuable_ability_name = :issue)
|
||||
ability = :"admin_#{issuable_ability_name}"
|
||||
|
||||
unless can?(current_user, ability, project)
|
||||
params.delete(:milestone_id)
|
||||
params.delete(:label_ids)
|
||||
params.delete(:assignee_id)
|
||||
|
||||
@@ -10,6 +10,10 @@ module Issues
|
||||
|
||||
private
|
||||
|
||||
def filter_params
|
||||
super(:issue)
|
||||
end
|
||||
|
||||
def execute_hooks(issue, action = 'open')
|
||||
issue_data = hook_data(issue, action)
|
||||
issue.project.execute_hooks(issue_data, :issue_hooks)
|
||||
|
||||
@@ -20,5 +20,11 @@ module MergeRequests
|
||||
merge_request.project.execute_services(merge_data, :merge_request_hooks)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def filter_params
|
||||
super(:merge_request)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -85,6 +85,8 @@ module Projects
|
||||
|
||||
@project.create_wiki if @project.wiki_enabled?
|
||||
|
||||
@project.build_missing_services
|
||||
|
||||
event_service.create_project(@project, current_user)
|
||||
system_hook_service.execute_hooks_for(@project, :create)
|
||||
|
||||
|
||||
@@ -78,21 +78,22 @@
|
||||
%span.monospace= project.path_with_namespace + ".git"
|
||||
|
||||
.col-md-6
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
Add user(s) to the group:
|
||||
.panel-body.form-holder
|
||||
%p.light
|
||||
Read more about project permissions
|
||||
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
|
||||
- if can?(current_user, :admin_group_member, @group)
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
Add user(s) to the group:
|
||||
.panel-body.form-holder
|
||||
%p.light
|
||||
Read more about project permissions
|
||||
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
|
||||
|
||||
= form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do
|
||||
%div
|
||||
= users_select_tag(:user_ids, multiple: true, email_user: true, skip_ldap: @group.ldap_synced?, scope: :all)
|
||||
%div.prepend-top-10
|
||||
= select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2"
|
||||
%hr
|
||||
= button_tag 'Add users to group', class: "btn btn-create"
|
||||
= form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do
|
||||
%div
|
||||
= users_select_tag(:user_ids, multiple: true, email_user: true, skip_ldap: @group.ldap_synced?, scope: :all)
|
||||
%div.prepend-top-10
|
||||
= select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2"
|
||||
%hr
|
||||
= button_tag 'Add users to group', class: "btn btn-create"
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%h3.panel-title
|
||||
@@ -113,7 +114,8 @@
|
||||
(invited)
|
||||
%span.pull-right.light
|
||||
= member.human_access
|
||||
= link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
|
||||
%i.fa.fa-minus.fa-inverse
|
||||
- if can?(current_user, :destroy_group_member, member)
|
||||
= link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
|
||||
%i.fa.fa-minus.fa-inverse
|
||||
.panel-footer
|
||||
= paginate @members, param_name: 'members_page', theme: 'gitlab'
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
.form-group
|
||||
= f.label :provider, class: 'control-label'
|
||||
.col-sm-10
|
||||
= f.select :provider, Gitlab::OAuth::Provider.names, { allow_blank: false }, class: 'form-control'
|
||||
- values = Gitlab::OAuth::Provider.providers.map { |name| ["#{Gitlab::OAuth::Provider.label_for(name)} (#{name})", name] }
|
||||
= f.select :provider, values, { allow_blank: false }, class: 'form-control'
|
||||
.form-group
|
||||
= f.label :extern_uid, "Identifier", class: 'control-label'
|
||||
.col-sm-10
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%tr
|
||||
%td
|
||||
= identity.provider
|
||||
= "#{Gitlab::OAuth::Provider.label_for(identity.provider)} (#{identity.provider})"
|
||||
%td
|
||||
= identity.extern_uid
|
||||
%td
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
|
||||
= f.text_field :login, class: "form-control top", placeholder: "Username or Email", autofocus: "autofocus"
|
||||
= f.text_field :login, class: "form-control top", placeholder: "Username or Email", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off"
|
||||
= f.password_field :password, class: "form-control bottom", placeholder: "Password"
|
||||
- if devise_mapping.rememberable?
|
||||
.remember-me.checkbox
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
%label{for: "remember_me"}
|
||||
= check_box_tag :remember_me, '1', false, id: 'remember_me'
|
||||
%span Remember me
|
||||
= button_tag "#{server['label']} Sign in", class: "btn-save btn"
|
||||
= button_tag "Sign in", class: "btn-save btn"
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
%p
|
||||
%span.light
|
||||
Sign in with
|
||||
- providers = additional_providers
|
||||
- providers = button_based_providers
|
||||
- providers.each do |provider|
|
||||
%span.light
|
||||
- if default_providers.include?(provider)
|
||||
= link_to oauth_image_tag(provider), omniauth_authorize_path(resource_name, provider), method: :post, class: 'oauth-image-link'
|
||||
- else
|
||||
= link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), method: :post, class: "btn", "data-no-turbolink" => "true"
|
||||
- has_icon = provider_has_icon?(provider)
|
||||
= link_to provider_image_tag(provider), user_omniauth_authorize_path(provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn'), "data-no-turbolink" => "true"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
.login-heading
|
||||
%h3 Sign in
|
||||
.login-body
|
||||
- if ldap_enabled?
|
||||
- if form_based_providers.any?
|
||||
%ul.nav.nav-tabs
|
||||
- @ldap_servers.each_with_index do |server, i|
|
||||
%li{class: (:active if i.zero?)}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
= link_to member.created_by.name, user_path(member.created_by)
|
||||
= time_ago_with_tooltip(member.created_at)
|
||||
|
||||
- if show_controls && can?(current_user, :admin_group, @group)
|
||||
- if show_controls && can?(current_user, :admin_group_member, member)
|
||||
= link_to resend_invite_group_group_member_path(@group, member), method: :post, class: "btn-xs btn", title: 'Resend invite' do
|
||||
Resend invite
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
= search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control search-text-input' }
|
||||
= button_tag 'Search', class: 'btn'
|
||||
|
||||
- if current_user && current_user.can?(:admin_group, @group)
|
||||
- if current_user && current_user.can?(:admin_group_member, @group)
|
||||
.pull-right
|
||||
- if ldap_enabled? && @group.ldap_synced?
|
||||
= link_to reset_access_group_ldap_path(@group), class: 'btn btn-grouped', data: { confirm: "Force GitLab to do LDAP permission checks for all group members? All members besides yourself will be reduced to 'Guest' access until their next interaction with GitLab." }, method: :put do
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
= yield
|
||||
%div.footer{style: "margin-top: 10px;"}
|
||||
%p
|
||||
\—
|
||||
—
|
||||
%br
|
||||
- if @target_url
|
||||
#{link_to "View it on GitLab", @target_url}
|
||||
|
||||
@@ -58,22 +58,22 @@
|
||||
%div
|
||||
= link_to 'Enable Two-factor Authentication', new_profile_two_factor_auth_path, class: 'btn btn-success'
|
||||
|
||||
- if show_profile_social_tab?
|
||||
- if button_based_providers.any?
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
Connected Accounts
|
||||
.panel-body
|
||||
.oauth-buttons.append-bottom-10
|
||||
%p Click on icon to activate signin with one of the following services
|
||||
- enabled_social_providers.each do |provider|
|
||||
- button_based_providers.each do |provider|
|
||||
.btn-group
|
||||
= link_to oauth_image_tag(provider), omniauth_authorize_path(User, provider),
|
||||
method: :post, class: "btn btn-lg #{'active' if oauth_active?(provider)}"
|
||||
- if oauth_active?(provider)
|
||||
= link_to provider_image_tag(provider), user_omniauth_authorize_path(provider), method: :post, class: "btn btn-lg #{'active' if auth_active?(provider)}", "data-no-turbolink" => "true"
|
||||
|
||||
- if auth_active?(provider)
|
||||
= link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'btn btn-lg' do
|
||||
= icon('close')
|
||||
|
||||
- if show_profile_username_tab?
|
||||
- if current_user.can_change_username?
|
||||
.panel.panel-warning.update-username
|
||||
.panel-heading
|
||||
Change Username
|
||||
@@ -93,7 +93,7 @@
|
||||
%div
|
||||
= f.submit 'Save username', class: "btn btn-warning"
|
||||
|
||||
- if show_profile_remove_tab?
|
||||
- if signup_enabled?
|
||||
.panel.panel-danger.remove-account
|
||||
.panel-heading
|
||||
Remove account
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
- @key.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
|
||||
.form-group
|
||||
= f.label :title, class: 'control-label'
|
||||
.col-sm-10= f.text_field :title, class: "form-control"
|
||||
.form-group
|
||||
= f.label :key, class: 'control-label'
|
||||
.col-sm-10
|
||||
= f.text_area :key, class: "form-control", rows: 8
|
||||
|
||||
.form-group
|
||||
= f.label :title, class: 'control-label'
|
||||
.col-sm-10= f.text_field :title, class: "form-control"
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Add key', class: "btn btn-create"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
%td.old_line.diff-line-num{data: {linenumber: line_old}}
|
||||
= link_to raw(line_old), "#"
|
||||
%td.new_line= link_to raw(line_new) , "#"
|
||||
%td.line_content.noteable_line= line
|
||||
%td.line_content.noteable_line= ' ' * @form.indent + line
|
||||
|
||||
- if @form.unfold? && @form.bottom? && @form.to < @blob.loc
|
||||
%tr.line_holder{ id: @form.to }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
- too_big = diff_file.diff_lines.count > Commit::DIFF_SAFE_LINES
|
||||
- if too_big
|
||||
%a.supp_diff_link Changes suppressed. Click to show
|
||||
.suppressed-container
|
||||
%a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show.
|
||||
|
||||
%table.text-file{class: "#{'hide' if too_big}"}
|
||||
- last_line = 0
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Too many changes to show.
|
||||
.pull-right
|
||||
- unless diff_hard_limit_enabled?
|
||||
= link_to "Reload with full diff", url_for(params.merge(force_show_diff: true)), class: "btn btn-sm btn-warning"
|
||||
= link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: :html)), class: "btn btn-sm btn-warning"
|
||||
|
||||
- if current_controller?(:commit) or current_controller?(:merge_requests)
|
||||
- if current_controller?(:commit)
|
||||
|
||||
@@ -66,11 +66,9 @@
|
||||
#notes.notes.tab-pane.voting_notes
|
||||
= render "projects/merge_requests/discussion"
|
||||
#commits.commits.tab-pane
|
||||
- if current_page?(action: 'commits')
|
||||
= render "projects/merge_requests/show/commits"
|
||||
- # This tab is always loaded via AJAX
|
||||
#diffs.diffs.tab-pane
|
||||
- if current_page?(action: 'diffs')
|
||||
= render "projects/merge_requests/show/diffs"
|
||||
- # This tab is always loaded via AJAX
|
||||
|
||||
.mr-loading-status
|
||||
= spinner
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
:javascript
|
||||
network_graph = new Network({
|
||||
url: '#{namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json))}',
|
||||
commit_url: '#{namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s")}',
|
||||
ref: '#{@ref}',
|
||||
url: "#{escape_javascript(@url)}",
|
||||
commit_url: "#{escape_javascript(@commit_url)}",
|
||||
ref: "#{escape_javascript(@ref)}",
|
||||
commit_id: '#{@commit.id}'
|
||||
})
|
||||
new ShortcutsNetwork(network_graph.branch_graph)
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
= note_target_fields(note)
|
||||
= render layout: 'projects/md_preview', locals: { preview_class: 'note-text' } do
|
||||
= render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text js-task-list-field'
|
||||
|
||||
.comment-hints.clearfix
|
||||
.pull-left #{link_to 'Markdown ', help_page_path('markdown', 'markdown'),{ target: '_blank', tabindex: -1 }}
|
||||
.pull-right #{link_to 'Attach a file', '#', class: 'markdown-selector', tabindex: -1 }
|
||||
= render 'projects/notes/hints'
|
||||
|
||||
.note-form-actions
|
||||
.buttons
|
||||
|
||||
@@ -8,18 +8,8 @@
|
||||
= f.hidden_field :noteable_type
|
||||
|
||||
= render layout: 'projects/md_preview', locals: { preview_class: "note-text", referenced_users: true } do
|
||||
= render 'projects/zen', f: f, attr: :note,
|
||||
classes: 'note_text js-note-text'
|
||||
|
||||
.comment-hints.clearfix
|
||||
.pull-left
|
||||
= link_to "Markdown ", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }
|
||||
tip:
|
||||
= random_markdown_tip
|
||||
.pull-right
|
||||
= link_to '#', class: 'markdown-selector', tabindex: -1 do
|
||||
Attach a file
|
||||
= icon('paperclip')
|
||||
= render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text'
|
||||
= render 'projects/notes/hints'
|
||||
.error-alert
|
||||
|
||||
.note-form-actions
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
.comment-hints.clearfix
|
||||
.pull-left
|
||||
= link_to 'Markdown', help_page_path('markdown', 'markdown'), target: '_blank', tabindex: -1
|
||||
tip:
|
||||
= random_markdown_tip
|
||||
.pull-right
|
||||
= link_to '#', class: 'markdown-selector', tabindex: -1 do
|
||||
= icon('paperclip')
|
||||
Attach a file
|
||||
@@ -11,9 +11,11 @@
|
||||
- if @logs.present?
|
||||
:plain
|
||||
var current_url = location.href.replace(/\/?$/, '/');
|
||||
var log_url = '#{namespace_project_tree_url(@project.namespace, @project, tree_join(@ref, @path || '/'))}'.replace(/\/?$/, '/');
|
||||
var log_url = "#{escape_javascript(@log_url)}".replace(/\/?$/, '/');
|
||||
|
||||
if(current_url == log_url) {
|
||||
// Load 10 more commit log for each file in tree
|
||||
// Load more commit logs for each file in tree
|
||||
// if we still on the same page
|
||||
ajaxGet('#{logs_file_namespace_project_ref_path(@project.namespace, @project, @ref, @path || '', offset: (@offset + @limit))}');
|
||||
var url = "#{escape_javascript(@more_log_url)}";
|
||||
ajaxGet(url);
|
||||
}
|
||||
|
||||
@@ -49,5 +49,5 @@
|
||||
:javascript
|
||||
// Load last commit log for each file in tree
|
||||
$('#tree-slider').waitForImages(function() {
|
||||
ajaxGet('#{@logs_path}');
|
||||
ajaxGet("#{escape_javascript(@logs_path)}");
|
||||
});
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
%h3.page-title
|
||||
= @page.title
|
||||
= render 'main_links'
|
||||
|
||||
.wiki-last-edit-by
|
||||
Last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
|
||||
|
||||
- if @page.historical?
|
||||
.warning_message
|
||||
This is an old version of this page.
|
||||
@@ -16,6 +20,6 @@
|
||||
= render_wiki_content(@page)
|
||||
|
||||
%hr
|
||||
|
||||
.wiki-last-edit-by
|
||||
Last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
- else
|
||||
none
|
||||
.issuable-context-selectbox
|
||||
- if can?(current_user, :"admin_#{issuable.class.to_s.underscore}", @project)
|
||||
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
|
||||
= users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true)
|
||||
|
||||
%div.prepend-top-20.clearfix
|
||||
@@ -24,7 +24,7 @@
|
||||
- else
|
||||
none
|
||||
.issuable-context-selectbox
|
||||
- if can?(current_user, :"admin_#{issuable.class.to_s.underscore}", @project)
|
||||
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
|
||||
= f.select(:milestone_id, milestone_options(issuable), { include_blank: 'Select milestone' }, {class: 'select2 select2-compact js-select2 js-milestone'})
|
||||
= hidden_field_tag :issuable_context
|
||||
= f.submit class: 'btn hide'
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
.clearfix
|
||||
.error-alert
|
||||
%hr
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
|
||||
.form-group
|
||||
.issue-assignee
|
||||
= f.label :assignee_id, class: 'control-label' do
|
||||
|
||||
@@ -243,24 +243,30 @@ production: &base
|
||||
# arguments, followed by optional 'args' which can be either a hash or an array.
|
||||
# Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html
|
||||
providers:
|
||||
# - { name: 'google_oauth2', app_id: 'YOUR_APP_ID',
|
||||
# - { name: 'google_oauth2',
|
||||
# label: 'Google',
|
||||
# app_id: 'YOUR_APP_ID',
|
||||
# app_secret: 'YOUR_APP_SECRET',
|
||||
# args: { access_type: 'offline', approval_prompt: '' } }
|
||||
# - { name: 'twitter', app_id: 'YOUR_APP_ID',
|
||||
# app_secret: 'YOUR_APP_SECRET'}
|
||||
# - { name: 'gitlab', app_id: 'YOUR_APP_ID',
|
||||
# app_secret: 'YOUR_APP_SECRET',
|
||||
# args: { scope: 'api' } }
|
||||
# - { name: 'github', app_id: 'YOUR_APP_ID',
|
||||
# - { name: 'twitter',
|
||||
# app_id: 'YOUR_APP_ID',
|
||||
# app_secret: 'YOUR_APP_SECRET' }
|
||||
# - { name: 'github',
|
||||
# label: 'GitHub',
|
||||
# app_id: 'YOUR_APP_ID',
|
||||
# app_secret: 'YOUR_APP_SECRET',
|
||||
# url: "https://github.com/",
|
||||
# args: { scope: 'user:email' } }
|
||||
# - { name: 'gitlab', app_id: 'YOUR_APP_ID',
|
||||
# - { name: 'gitlab',
|
||||
# label: 'GitLab.com',
|
||||
# app_id: 'YOUR_APP_ID',
|
||||
# app_secret: 'YOUR_APP_SECRET',
|
||||
# args: { scope: 'api' } }
|
||||
# - { name: 'bitbucket', app_id: 'YOUR_APP_ID',
|
||||
# app_secret: 'YOUR_APP_SECRET'}
|
||||
# - { name: 'saml',
|
||||
# - { name: 'bitbucket',
|
||||
# app_id: 'YOUR_APP_ID',
|
||||
# app_secret: 'YOUR_APP_SECRET' }
|
||||
# - { name: 'saml',
|
||||
# label: 'Our SAML Provider',
|
||||
# args: {
|
||||
# assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
|
||||
# idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Step-by-step guides on the basics of working with Git and GitLab.
|
||||
|
||||
* [Start using Git on the commandline](start-using-git.md)
|
||||
* [Start using Git on the command line](start-using-git.md)
|
||||
|
||||
* [Create and add your SSH Keys](create-your-ssh-keys.md)
|
||||
|
||||
@@ -17,3 +17,5 @@ Step-by-step guides on the basics of working with Git and GitLab.
|
||||
* [Create a branch](create-branch.md)
|
||||
|
||||
* [Fork a project](fork-project.md)
|
||||
|
||||
* [Add a file](add-file.md)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# How to add a file
|
||||
|
||||
You can create a file in your [shell](command-line-commands.md) or in GitLab.
|
||||
|
||||
To create a file in GitLab, sign in to [GitLab.com](https://gitlab.com).
|
||||
|
||||
Select a project on the right side of your screen:
|
||||
|
||||

|
||||
|
||||
It's a good idea to [create a branch](create-branch.md), but it's not necessary.
|
||||
|
||||
Go to the directory where you'd like to add the file and click on the "+" sign next to the name of the project and directory:
|
||||
|
||||

|
||||
|
||||
Name your file (you can't add spaces, so you can use hyphens or underscores). Don't forget to include the markup language you'd like to use :
|
||||
|
||||

|
||||
|
||||
Add all the information that you'd like to include in your file:
|
||||
|
||||

|
||||
|
||||
Add a commit message based on what you just added and then click on "commit changes":
|
||||
|
||||

|
||||
|
||||
### Note
|
||||
Besides its regular files, every directory needs a README.md or README.html file which works like an index, telling
|
||||
what the directory is about. It's the first document you'll find when you open a directory.
|
||||
|
Before Width: | Height: | Size: 17 KiB |
@@ -1,28 +0,0 @@
|
||||
# GitLab buttons in Gmail
|
||||
|
||||
GitLab supports [Google actions in email](https://developers.google.com/gmail/markup/actions/actions-overview).
|
||||
|
||||
If correctly setup, emails that require an action will be marked in Gmail.
|
||||
|
||||

|
||||
|
||||
To get this functioning, you need to be registered with Google.
|
||||
[See how to register with Google in this document.](https://developers.google.com/gmail/markup/registering-with-google)
|
||||
|
||||
To aid the registering with Google, GitLab offers a rake task that will send an email to Google whitelisting email address from your GitLab server.
|
||||
|
||||
To check what would be sent to the Google email address, run the rake task:
|
||||
|
||||
```bash
|
||||
bundle exec rake gitlab:mail_google_schema_whitelisting RAILS_ENV=production
|
||||
```
|
||||
|
||||
**This will not send the email but give you the output of how the mail will look.**
|
||||
|
||||
Copy the output of the rake task to [Google email markup tester](https://www.google.com/webmasters/markup-tester/u/0/) and press "Validate".
|
||||
|
||||
If you receive "No errors detected" message from the tester you can send the email using:
|
||||
|
||||
```bash
|
||||
bundle exec rake gitlab:mail_google_schema_whitelisting RAILS_ENV=production SEND=true
|
||||
```
|
||||
@@ -84,7 +84,7 @@ Existing users can enable OmniAuth for specific providers after the account is c
|
||||
1. Sign in normally - whether standard sign in, LDAP, or another OmniAuth provider.
|
||||
1. Go to profile settings (the silhouette icon in the top right corner).
|
||||
1. Select the "Account" tab.
|
||||
1. Under "Social Accounts" select the desired OmniAuth provider, such as Twitter.
|
||||
1. Under "Connected Accounts" select the desired OmniAuth provider, such as Twitter.
|
||||
1. The user will be redirected to the provider. Once the user authorized GitLab they will be redirected back to GitLab.
|
||||
|
||||
The chosen OmniAuth provider is now active and can be used to sign in to GitLab from then on.
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
To enable the Twitter OmniAuth provider you must register your application with Twitter. Twitter will generate a client ID and secret key for you to use.
|
||||
|
||||
1. Sign in to [Twitter Developers](https://dev.twitter.com/) area.
|
||||
|
||||
1. Hover over the avatar in the top right corner and select "My applications."
|
||||
1. Sign in to [Twitter Application Management](https://apps.twitter.com/).
|
||||
|
||||
1. Select "Create new app"
|
||||
|
||||
@@ -14,18 +12,18 @@ To enable the Twitter OmniAuth provider you must register your application with
|
||||
- Description: Create a description.
|
||||
- Website: The URL to your GitLab installation. 'https://gitlab.example.com'
|
||||
- Callback URL: 'https://gitlab.example.com/users/auth/twitter/callback'
|
||||
- Agree to the "Rules of the Road."
|
||||
- Agree to the "Developer Agreement".
|
||||
|
||||

|
||||
1. Select "Create your Twitter application."
|
||||
|
||||
1. Select the "Settings" tab.
|
||||
|
||||
1. Underneath the Callback URL check the box next to "Allow this application to be used to Sign in the Twitter."
|
||||
1. Underneath the Callback URL check the box next to "Allow this application to be used to Sign in with Twitter."
|
||||
|
||||
1. Select "Update settings" at the bottom to save changes.
|
||||
|
||||
1. Select the "API Keys" tab.
|
||||
1. Select the "Keys and Access Tokens" tab.
|
||||
|
||||
1. You should now see an API key and API secret (see screenshot). Keep this page open as you continue configuration.
|
||||
|
||||
@@ -78,4 +76,4 @@ To enable the Twitter OmniAuth provider you must register your application with
|
||||
|
||||
1. Restart GitLab for the changes to take effect.
|
||||
|
||||
On the sign in page there should now be a Twitter icon below the regular sign in form. Click the icon to begin the authentication process. Twitter will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in.
|
||||
On the sign in page there should now be a Twitter icon below the regular sign in form. Click the icon to begin the authentication process. Twitter will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in.
|
||||
@@ -17,6 +17,7 @@ If a user is a GitLab administrator they receive all permissions.
|
||||
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
|
||||
| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
|
||||
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
|
||||
| Manage merge requests | | | ✓ | ✓ | ✓ |
|
||||
| Create new merge request | | | ✓ | ✓ | ✓ |
|
||||
| Create new branches | | | ✓ | ✓ | ✓ |
|
||||
| Push to non-protected branches | | | ✓ | ✓ | ✓ |
|
||||
|
||||
@@ -68,7 +68,7 @@ Xth: (2 working days before the 22nd)
|
||||
Xth: (1 working day before the 22nd)
|
||||
|
||||
- [ ] Merge CE stable into EE stable
|
||||
- [ ] Create (hopefully final) CE, EE, CI release candidates (#LINK)
|
||||
- [ ] Create CE, EE, CI release candidates (#LINK) (hopefully final ones with the same commit as the release tomorrow)
|
||||
- [ ] Create Omnibus tags and build packages for the latest release candidates
|
||||
- [ ] Update GitLab.com with the latest RC (#LINK)
|
||||
- [ ] Update ci.gitLab.com with the latest RC (#LINK)
|
||||
@@ -81,10 +81,10 @@ workday to quickly fix any issues.
|
||||
|
||||
- [ ] Merge CE stable into EE stable (#LINK)
|
||||
- [ ] Create the 'x.y.0' tag with the [release tools](https://dev.gitlab.org/gitlab/release-tools) (#LINK)
|
||||
- [ ] BEFORE 11AM CET Create and push omnibus tags for x.y.0 (will auto-release the packages) (#LINK)
|
||||
- [ ] BEFORE 12AM CET Publish the release blog post (#LINK)
|
||||
- [ ] Try to do before 11AM CET: Create and push omnibus tags for x.y.0 (will auto-release the packages) (#LINK)
|
||||
- [ ] Try to do before 12AM CET: Publish the release blog post (#LINK)
|
||||
- [ ] Tweet about the release (blog post) (#LINK)
|
||||
- [ ] Schedule a second tweet of the release announcement at 6PM CET / 9AM PST
|
||||
- [ ] Schedule a second tweet of the release announcement with the same text at 6PM CET / 9AM PST
|
||||
|
||||
```
|
||||
|
||||
@@ -220,4 +220,4 @@ Consider creating a post on Hacker News.
|
||||
|
||||
## Create a WIP blogpost for the next release
|
||||
|
||||
Create a WIP blogpost using [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md).
|
||||
Create a WIP blogpost using [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md).
|
||||
@@ -105,3 +105,6 @@ IdentityFile ~/my-ssh-key-directory/company-com-private-key-filename
|
||||
Note in the gitlab.com example above a username was specified to override the default chosen by OpenSSH (your local username). This is only required if your local and remote usernames differ.
|
||||
|
||||
Due to the wide variety of SSH clients and their very large number of configuration options, further explanation of these topics is beyond the scope of this document.
|
||||
|
||||
Public SSH keys need to be unique, as they will bind to your account. Your SSH key is the only identifier you'll
|
||||
have when pushing code via SSH. That's why it needs to uniquely map to a single user.
|
||||
|
||||
@@ -31,7 +31,7 @@ We think there is still room for improvement and will detail a set of practices
|
||||
|
||||
## Git flow and its problems
|
||||
|
||||
[
|
||||

|
||||
|
||||
Git flow was one of the first proposals to use git branches and it has gotten a lot of attention.
|
||||
It advocates a master branch and a separate develop branch as well as supporting branches for features, releases and hotfixes.
|
||||
@@ -54,7 +54,7 @@ And doing releases doesn't automatically mean also doing hotfixes.
|
||||
|
||||

|
||||
|
||||
In reaction to git flow a simpler alternative was detailed, [GitHub flow](https://guides.github.com/introduction/flow/index.html).
|
||||
In reaction to git flow a simpler alternative was detailed, [GitHub flow](https://guides.github.com/introduction/flow/index.html).
|
||||
This flow has only feature branches and a master branch.
|
||||
This is very simple and clean, many organizations have adopted it with great success.
|
||||
Atlassian recommends [a similar strategy](http://blogs.atlassian.com/2014/01/simple-git-workflow-simple/) although they rebase feature branches.
|
||||
@@ -131,7 +131,7 @@ When you feel comfortable with it to be merged you assign it to the person that
|
||||
There is room for more feedback and after the assigned person feels comfortable with the result the branch is merged.
|
||||
If the assigned person does not feel comfortable they can close the merge request without merging.
|
||||
|
||||
In GitLab it is common to protect the long-lived branches (e.g. the master branch) so that normal developers [can't modify these protected branches](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/permissions/permissions.md).
|
||||
In GitLab it is common to protect the long-lived branches (e.g. the master branch) so that normal developers [can't modify these protected branches](http://doc.gitlab.com/ce/permissions/permissions.html).
|
||||
So if you want to merge it into a protected branch you assign it to someone with master authorizations.
|
||||
|
||||
## Issues with GitLab flow
|
||||
@@ -216,7 +216,7 @@ This prevents creating a merge commit when merging master into your feature bran
|
||||
However, just like with squashing you should never rebase commits you have pushed to a remote server.
|
||||
This makes it impossible to rebase work in progress that you already shared with your team which is something we recommend.
|
||||
When using rebase to keep your feature branch updated you [need to resolve similar conflicts again and again](http://blogs.atlassian.com/2013/10/git-team-workflows-merge-or-rebase/).
|
||||
You can reuse recorded resolutions (rerere) sometimes, but with without rebasing you only have to solve the conflicts one time and you’re set.
|
||||
You can reuse recorded resolutions (rerere) sometimes, but without rebasing you only have to solve the conflicts one time and you’re set.
|
||||
There has to be a better way to avoid many merge commits.
|
||||
|
||||
The way to prevent creating many merge commits is to not frequently merge master into the feature branch.
|
||||
|
||||
@@ -6,4 +6,7 @@
|
||||
4. [SVN](migrating_from_svn.md)
|
||||
|
||||
### Note
|
||||
* If you'd like to migrate from a self-hosted GitLab instance to GitLab.com, you can copy your repos by changing the remote and pushing to the new server; but issues and merge requests can't be imported.
|
||||
* If you'd like to migrate from a self-hosted GitLab instance to GitLab.com, you can copy your repos by changing the remote and pushing to the new server; but issues and merge requests can't be imported.
|
||||
|
||||
* Repositories are imported to GitLab via HTTP.
|
||||
If the repository is too large, it can timeout. We have a soft limit of 10GB.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Labels
|
||||
|
||||
In GitLab, you can easily tag issues and merge requests. If you have permission level `Developer` or higher, you can manage labels. To create, edit or delete a label, go to a project and then to `Issues` and then `Labels`.
|
||||
In GitLab, you can easily tag issues and Merge Requests. If you have permission level `Developer` or higher, you can manage labels. To create, edit or delete a label, go to a project and then to `Issues` and then `Labels`.
|
||||
|
||||
Here you can create a new label.
|
||||
|
||||
@@ -14,3 +14,5 @@ If you want to change an existing label, press edit next to the listed label.
|
||||
You will be presented with the same form as when creating a new label.
|
||||
|
||||

|
||||
|
||||
You can add labels to Merge Requests when you create or edit them.
|
||||
|
||||
@@ -10,6 +10,11 @@ Feature: Project Network Graph
|
||||
And page should select "master" in select box
|
||||
And page should have "master" on graph
|
||||
|
||||
@javascript
|
||||
Scenario: I should see project network with 'test' branch
|
||||
When I visit project network page on branch 'test'
|
||||
Then page should have 'test' on graph
|
||||
|
||||
@javascript
|
||||
Scenario: I should switch "branch" and "tag"
|
||||
When I switch ref to "feature"
|
||||
|
||||
@@ -158,3 +158,10 @@ Feature: Project Source Browse Files
|
||||
Given I visit project source page for "6d394385cf567f80a8fd85055db1ab4c5295806f"
|
||||
And I click on ".gitignore" file in repo
|
||||
Then I don't see the permalink link
|
||||
|
||||
@javascript
|
||||
Scenario: I browse code with single quotes in the ref
|
||||
Given I switch ref to 'test'
|
||||
And I see the ref 'test' has been selected
|
||||
And I visit the 'test' tree
|
||||
Then I see the commit data
|
||||
|
||||
@@ -3,6 +3,14 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps
|
||||
include SharedPaths
|
||||
include SharedAdmin
|
||||
|
||||
before do
|
||||
allow(Devise).to receive(:omniauth_providers).and_return([:twitter, :twitter_updated])
|
||||
end
|
||||
|
||||
after do
|
||||
allow(Devise).to receive(:omniauth_providers).and_call_original
|
||||
end
|
||||
|
||||
step 'I should see all users' do
|
||||
User.all.each do |user|
|
||||
expect(page).to have_content user.name
|
||||
@@ -121,7 +129,6 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps
|
||||
end
|
||||
|
||||
step 'I visit "Pete" identities page in admin' do
|
||||
allow(Gitlab::OAuth::Provider).to receive(:names).and_return(%w(twitter twitter_updated))
|
||||
visit admin_user_identities_path(@user)
|
||||
end
|
||||
|
||||
|
||||
@@ -11,8 +11,12 @@ class Spinach::Features::ProjectNetworkGraph < Spinach::FeatureSteps
|
||||
# Stub Graph max_size to speed up test (10 commits vs. 650)
|
||||
allow(Network::Graph).to receive(:max_count).and_return(10)
|
||||
|
||||
project = Project.find_by(name: "Shop")
|
||||
visit namespace_project_network_path(project.namespace, project, "master")
|
||||
@project = Project.find_by(name: "Shop")
|
||||
visit namespace_project_network_path(@project.namespace, @project, "master")
|
||||
end
|
||||
|
||||
step "I visit project network page on branch 'test'" do
|
||||
visit namespace_project_network_path(@project.namespace, @project, "'test'")
|
||||
end
|
||||
|
||||
step 'page should select "master" in select box' do
|
||||
@@ -29,6 +33,12 @@ class Spinach::Features::ProjectNetworkGraph < Spinach::FeatureSteps
|
||||
end
|
||||
end
|
||||
|
||||
step "page should have 'test' on graph" do
|
||||
page.within '.network-graph' do
|
||||
expect(page).to have_content "'test'"
|
||||
end
|
||||
end
|
||||
|
||||
When 'I switch ref to "feature"' do
|
||||
select 'feature', from: 'ref'
|
||||
sleep 2
|
||||
|
||||
@@ -193,6 +193,23 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
|
||||
FileUtils.rm_f(File.join(@project.repository.path, 'hooks', 'pre-receive'))
|
||||
end
|
||||
|
||||
step "I switch ref to 'test'" do
|
||||
select "'test'", from: 'ref'
|
||||
end
|
||||
|
||||
step "I see the ref 'test' has been selected" do
|
||||
expect(page).to have_selector '.select2-chosen', text: "'test'"
|
||||
end
|
||||
|
||||
step "I visit the 'test' tree" do
|
||||
visit namespace_project_tree_path(@project.namespace, @project, "'test'")
|
||||
end
|
||||
|
||||
step 'I see the commit data' do
|
||||
expect(page).to have_css('.tree-commit-link', visible: true)
|
||||
expect(page).not_to have_content('Loading commit data...')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_new_content
|
||||
|
||||
@@ -6,6 +6,10 @@ module API
|
||||
|
||||
class UserBasic < UserSafe
|
||||
expose :id, :state, :avatar_url
|
||||
|
||||
expose :web_url do |user, options|
|
||||
Rails.application.routes.url_helpers.user_url(user)
|
||||
end
|
||||
end
|
||||
|
||||
class User < UserBasic
|
||||
@@ -64,6 +68,7 @@ module API
|
||||
expose :namespace
|
||||
expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? }
|
||||
expose :avatar_url
|
||||
expose :star_count, :forks_count
|
||||
end
|
||||
|
||||
class ProjectMember < UserBasic
|
||||
@@ -79,6 +84,11 @@ module API
|
||||
class Group < Grape::Entity
|
||||
expose :id, :name, :path, :ldap_cn, :ldap_access, :description
|
||||
expose :ldap_group_links, using: Entities::LdapGroupLink, if: lambda{ | group, options | group.ldap_group_links.any? }
|
||||
expose :avatar_url
|
||||
|
||||
expose :web_url do |group, options|
|
||||
Rails.application.routes.url_helpers.group_url(group)
|
||||
end
|
||||
end
|
||||
|
||||
class GroupDetail < Group
|
||||
|
||||
@@ -229,7 +229,7 @@ module API
|
||||
|
||||
authorize! :read_merge_request, merge_request
|
||||
|
||||
present paginate(merge_request.notes), with: Entities::MRNote
|
||||
present paginate(merge_request.notes.fresh), with: Entities::MRNote
|
||||
end
|
||||
|
||||
# Post comment to merge request
|
||||
|
||||
@@ -7,7 +7,11 @@ module Backup
|
||||
def initialize
|
||||
@config = YAML.load_file(File.join(Rails.root,'config','database.yml'))[Rails.env]
|
||||
@db_dir = File.join(Gitlab.config.backup.path, 'db')
|
||||
FileUtils.mkdir_p(@db_dir) unless Dir.exists?(@db_dir)
|
||||
FileUtils.rm_rf(@db_dir)
|
||||
# Ensure the parent dir of @db_dir exists
|
||||
FileUtils.mkdir_p(Gitlab.config.backup.path)
|
||||
# Fail if somebody raced to create @db_dir before us
|
||||
FileUtils.mkdir(@db_dir, mode: 0700)
|
||||
end
|
||||
|
||||
def dump
|
||||
@@ -25,7 +29,6 @@ module Backup
|
||||
abort 'Backup failed' unless success
|
||||
|
||||
$progress.print 'Compressing database ... '
|
||||
FileUtils.rm_f db_file_name_gz
|
||||
success = system('gzip', db_file_name)
|
||||
report_success(success)
|
||||
abort 'Backup failed: compress error' unless success
|
||||
|
||||
@@ -16,8 +16,6 @@ module Backup
|
||||
file << s.to_yaml.gsub(/^---\n/,'')
|
||||
end
|
||||
|
||||
FileUtils.chmod(0700, folders_to_backup)
|
||||
|
||||
# create archive
|
||||
$progress.print "Creating backup archive: #{tar_file} ... "
|
||||
orig_umask = File.umask(0077)
|
||||
|
||||
@@ -130,7 +130,10 @@ module Backup
|
||||
|
||||
def prepare
|
||||
FileUtils.rm_rf(backup_repos_path)
|
||||
FileUtils.mkdir_p(backup_repos_path)
|
||||
# Ensure the parent dir of backup_repos_path exists
|
||||
FileUtils.mkdir_p(Gitlab.config.backup.path)
|
||||
# Fail if somebody raced to create backup_repos_path before us
|
||||
FileUtils.mkdir(backup_repos_path, mode: 0700)
|
||||
end
|
||||
|
||||
def silent
|
||||
|
||||
@@ -10,7 +10,11 @@ module Backup
|
||||
|
||||
# Copy uploads from public/uploads to backup/uploads
|
||||
def dump
|
||||
FileUtils.mkdir_p(backup_uploads_dir)
|
||||
FileUtils.rm_rf(backup_uploads_dir)
|
||||
# Ensure the parent dir of backup_uploads_dir exists
|
||||
FileUtils.mkdir_p(Gitlab.config.backup.path)
|
||||
# Fail if somebody raced to create backup_uploads_dir before us
|
||||
FileUtils.mkdir(backup_uploads_dir, mode: 0700)
|
||||
FileUtils.cp_r(app_uploads_dir, backup_dir)
|
||||
end
|
||||
|
||||
|
||||
@@ -26,7 +26,12 @@ module Grack
|
||||
auth!
|
||||
|
||||
if project && authorized_request?
|
||||
@app.call(env)
|
||||
if ENV['GITLAB_GRACK_AUTH_ONLY'] == '1'
|
||||
# Tell gitlab-git-http-server the request is OK, and what the GL_ID is
|
||||
render_grack_auth_ok
|
||||
else
|
||||
@app.call(env)
|
||||
end
|
||||
elsif @user.nil? && !@gitlab_ci
|
||||
unauthorized
|
||||
else
|
||||
@@ -174,6 +179,10 @@ module Grack
|
||||
end
|
||||
end
|
||||
|
||||
def render_grack_auth_ok
|
||||
[200, { "Content-Type" => "application/json" }, [JSON.dump({ 'GL_ID' => Gitlab::ShellEnv.gl_id(@user) })]]
|
||||
end
|
||||
|
||||
def render_not_found
|
||||
[404, { "Content-Type" => "text/plain" }, ["Not Found"]]
|
||||
end
|
||||
|
||||
@@ -7,7 +7,7 @@ module Gitlab
|
||||
def set_env(user)
|
||||
# Set GL_ID env variable
|
||||
if user
|
||||
ENV['GL_ID'] = "user-#{user.id}"
|
||||
ENV['GL_ID'] = gl_id(user)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,5 +15,14 @@ module Gitlab
|
||||
# Reset GL_ID env variable
|
||||
ENV['GL_ID'] = nil
|
||||
end
|
||||
|
||||
def gl_id(user)
|
||||
if user.present?
|
||||
"user-#{user.id}"
|
||||
else
|
||||
# This empty string is used in the render_grack_auth_ok method
|
||||
""
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module Gitlab
|
||||
module BitbucketImport
|
||||
class Client
|
||||
class Unauthorized < StandardError; end
|
||||
|
||||
attr_reader :consumer, :api
|
||||
|
||||
def initialize(access_token = nil, access_token_secret = nil)
|
||||
@@ -46,23 +48,23 @@ module Gitlab
|
||||
end
|
||||
|
||||
def user
|
||||
JSON.parse(api.get("/api/1.0/user").body)
|
||||
JSON.parse(get("/api/1.0/user").body)
|
||||
end
|
||||
|
||||
def issues(project_identifier)
|
||||
JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/issues").body)
|
||||
JSON.parse(get("/api/1.0/repositories/#{project_identifier}/issues").body)
|
||||
end
|
||||
|
||||
def issue_comments(project_identifier, issue_id)
|
||||
JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/issues/#{issue_id}/comments").body)
|
||||
JSON.parse(get("/api/1.0/repositories/#{project_identifier}/issues/#{issue_id}/comments").body)
|
||||
end
|
||||
|
||||
def project(project_identifier)
|
||||
JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}").body)
|
||||
JSON.parse(get("/api/1.0/repositories/#{project_identifier}").body)
|
||||
end
|
||||
|
||||
def find_deploy_key(project_identifier, key)
|
||||
JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/deploy-keys").body).find do |deploy_key|
|
||||
JSON.parse(get("/api/1.0/repositories/#{project_identifier}/deploy-keys").body).find do |deploy_key|
|
||||
deploy_key["key"].chomp == key.chomp
|
||||
end
|
||||
end
|
||||
@@ -82,11 +84,18 @@ module Gitlab
|
||||
end
|
||||
|
||||
def projects
|
||||
JSON.parse(api.get("/api/1.0/user/repositories").body).select { |repo| repo["scm"] == "git" }
|
||||
JSON.parse(get("/api/1.0/user/repositories").body).select { |repo| repo["scm"] == "git" }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get(url)
|
||||
response = api.get(url)
|
||||
raise Unauthorized if (400..499).include?(response.code.to_i)
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
def config
|
||||
Gitlab.config.omniauth.providers.find { |provider| provider.name == "bitbucket"}
|
||||
end
|
||||
|
||||
@@ -98,15 +98,25 @@ module Gitlab
|
||||
#
|
||||
# Returns a String
|
||||
def path_type(path)
|
||||
if repository.tree(current_sha, path).entries.any?
|
||||
unescaped_path = Addressable::URI.unescape(path)
|
||||
|
||||
if tree?(unescaped_path)
|
||||
'tree'
|
||||
elsif repository.blob_at(current_sha, path).try(:image?)
|
||||
elsif image?(unescaped_path)
|
||||
'raw'
|
||||
else
|
||||
'blob'
|
||||
end
|
||||
end
|
||||
|
||||
def tree?(path)
|
||||
repository.tree(current_sha, path).entries.any?
|
||||
end
|
||||
|
||||
def image?(path)
|
||||
repository.blob_at(current_sha, path).try(:image?)
|
||||
end
|
||||
|
||||
def current_sha
|
||||
context[:commit].try(:id) ||
|
||||
ref ? repository.commit(ref).try(:sha) : repository.head_commit.sha
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
module Gitlab
|
||||
module OAuth
|
||||
class Provider
|
||||
def self.names
|
||||
providers = []
|
||||
def self.providers
|
||||
Devise.omniauth_providers
|
||||
end
|
||||
|
||||
Gitlab.config.ldap.servers.values.each do |server|
|
||||
providers << server['provider_name']
|
||||
def self.enabled?(name)
|
||||
providers.include?(name.to_sym)
|
||||
end
|
||||
|
||||
def self.ldap_provider?(name)
|
||||
name.to_s.start_with?('ldap')
|
||||
end
|
||||
|
||||
def self.config_for(name)
|
||||
name = name.to_s
|
||||
if ldap_provider?(name)
|
||||
Gitlab::LDAP::Config.new(name).options
|
||||
else
|
||||
Gitlab.config.omniauth.providers.find { |provider| provider.name == name }
|
||||
end
|
||||
end
|
||||
|
||||
Gitlab.config.omniauth.providers.each do |provider|
|
||||
providers << provider['name']
|
||||
end
|
||||
|
||||
providers
|
||||
def self.label_for(name)
|
||||
config = config_for(name)
|
||||
(config && config['label']) || name.to_s.titleize
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,10 +22,10 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
|
||||
ERB::Util.html_escape_once(text)
|
||||
end
|
||||
|
||||
# Stolen from Rugments::Plugins::Redcarpet as this module is not required
|
||||
# from Rugments's gem root.
|
||||
# Stolen from Rouge::Plugins::Redcarpet as this module is not required
|
||||
# from Rouge's gem root.
|
||||
def block_code(code, language)
|
||||
lexer = Rugments::Lexer.find_fancy(language, code) || Rugments::Lexers::PlainText
|
||||
lexer = Rouge::Lexer.find_fancy(language, code) || Rouge::Lexers::PlainText
|
||||
|
||||
# XXX HACK: Redcarpet strips hard tabs out of code blocks,
|
||||
# so we assume you're not using leading spaces that aren't tabs,
|
||||
@@ -34,7 +34,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
|
||||
code.gsub!(/^ /, "\t")
|
||||
end
|
||||
|
||||
formatter = Rugments::Formatters::HTML.new(
|
||||
formatter = Rouge::Formatters::HTMLGitlab.new(
|
||||
cssclass: "code highlight #{@color_scheme} #{lexer.tag}"
|
||||
)
|
||||
formatter.format(lexer.lex(code))
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
require 'cgi'
|
||||
|
||||
module Rouge
|
||||
module Formatters
|
||||
class HTMLGitlab < Rouge::Formatter
|
||||
tag 'html_gitlab'
|
||||
|
||||
# Creates a new <tt>Rouge::Formatter::HTMLGitlab</tt> instance.
|
||||
#
|
||||
# [+nowrap+] If set to True, don't wrap the output at all, not
|
||||
# even inside a <tt><pre></tt> tag (default: false).
|
||||
# [+cssclass+] CSS class for the wrapping <tt><div></tt> tag
|
||||
# (default: 'highlight').
|
||||
# [+linenos+] If set to 'table', output line numbers as a table
|
||||
# with two cells, one containing the line numbers,
|
||||
# the other the whole code. This is copy paste friendly,
|
||||
# but may cause alignment problems with some browsers
|
||||
# or fonts. If set to 'inline', the line numbers will
|
||||
# be integrated in the <tt><pre></tt> tag that contains
|
||||
# the code (default: nil).
|
||||
# [+linenostart+] The line number for the first line (default: 1).
|
||||
# [+lineanchors+] If set to true the formatter will wrap each output
|
||||
# line in an anchor tag with a name of L-linenumber.
|
||||
# This allows easy linking to certain lines
|
||||
# (default: false).
|
||||
# [+lineanchorsid+] If lineanchors is true the name of the anchors can
|
||||
# be changed with lineanchorsid to e.g. foo-linenumber
|
||||
# (default: 'L').
|
||||
# [+anchorlinenos+] If set to true, will wrap line numbers in <tt><a></tt>
|
||||
# tags. Used in combination with linenos and lineanchors
|
||||
# (default: false).
|
||||
# [+inline_theme+] Inline CSS styles for the <pre> tag (default: false).
|
||||
def initialize(
|
||||
nowrap: false,
|
||||
cssclass: 'highlight',
|
||||
linenos: nil,
|
||||
linenostart: 1,
|
||||
lineanchors: false,
|
||||
lineanchorsid: 'L',
|
||||
anchorlinenos: false,
|
||||
inline_theme: nil
|
||||
)
|
||||
@nowrap = nowrap
|
||||
@cssclass = cssclass
|
||||
@linenos = linenos
|
||||
@linenostart = linenostart
|
||||
@lineanchors = lineanchors
|
||||
@lineanchorsid = lineanchorsid
|
||||
@anchorlinenos = anchorlinenos
|
||||
@inline_theme = Theme.find(@inline_theme).new if @inline_theme.is_a?(String)
|
||||
end
|
||||
|
||||
def render(tokens)
|
||||
case @linenos
|
||||
when 'table'
|
||||
render_tableized(tokens)
|
||||
when 'inline'
|
||||
render_untableized(tokens)
|
||||
else
|
||||
render_untableized(tokens)
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :format, :render
|
||||
|
||||
private
|
||||
|
||||
def render_untableized(tokens)
|
||||
data = process_tokens(tokens)
|
||||
|
||||
html = ''
|
||||
html << "<pre class=\"#{@cssclass}\"><code>" unless @nowrap
|
||||
html << wrap_lines(data[:code])
|
||||
html << "</code></pre>\n" unless @nowrap
|
||||
html
|
||||
end
|
||||
|
||||
def render_tableized(tokens)
|
||||
data = process_tokens(tokens)
|
||||
|
||||
html = ''
|
||||
html << "<div class=\"#{@cssclass}\">" unless @nowrap
|
||||
html << '<table><tbody>'
|
||||
html << "<td class=\"linenos\"><pre>"
|
||||
html << wrap_linenos(data[:numbers])
|
||||
html << '</pre></td>'
|
||||
html << "<td class=\"lines\"><pre><code>"
|
||||
html << wrap_lines(data[:code])
|
||||
html << '</code></pre></td>'
|
||||
html << '</tbody></table>'
|
||||
html << '</div>' unless @nowrap
|
||||
html
|
||||
end
|
||||
|
||||
def process_tokens(tokens)
|
||||
num_lines = 0
|
||||
last_val = ''
|
||||
rendered = ''
|
||||
|
||||
tokens.each do |tok, val|
|
||||
last_val = val
|
||||
num_lines += val.scan(/\n/).size
|
||||
rendered << span(tok, val)
|
||||
end
|
||||
|
||||
numbers = (@linenostart..num_lines + @linenostart - 1).to_a
|
||||
|
||||
{ numbers: numbers, code: rendered }
|
||||
end
|
||||
|
||||
def wrap_linenos(numbers)
|
||||
if @anchorlinenos
|
||||
numbers.map! do |number|
|
||||
"<a href=\"##{@lineanchorsid}#{number}\">#{number}</a>"
|
||||
end
|
||||
end
|
||||
numbers.join("\n")
|
||||
end
|
||||
|
||||
def wrap_lines(rendered)
|
||||
if @lineanchors
|
||||
lines = rendered.split("\n")
|
||||
lines = lines.each_with_index.map do |line, index|
|
||||
number = index + @linenostart
|
||||
|
||||
if @linenos == 'inline'
|
||||
"<a name=\"L#{number}\"></a>" \
|
||||
"<span class=\"linenos\">#{number}</span>" \
|
||||
"<span id=\"#{@lineanchorsid}#{number}\" class=\"line\">#{line}" \
|
||||
'</span>'
|
||||
else
|
||||
"<span id=\"#{@lineanchorsid}#{number}\" class=\"line\">#{line}" \
|
||||
'</span>'
|
||||
end
|
||||
end
|
||||
lines.join("\n")
|
||||
else
|
||||
if @linenos == 'inline'
|
||||
lines = rendered.split("\n")
|
||||
lines = lines.each_with_index.map do |line, index|
|
||||
number = index + @linenostart
|
||||
"<span class=\"linenos\">#{number}</span>#{line}"
|
||||
end
|
||||
lines.join("\n")
|
||||
else
|
||||
rendered
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def wrap_values(val, element)
|
||||
lines = val.split("\n")
|
||||
lines = lines.map{ |x| "<span #{element}>#{x}</span>" }
|
||||
lines.join("\n")
|
||||
end
|
||||
|
||||
def span(tok, val)
|
||||
# http://stackoverflow.com/a/1600584/2587286
|
||||
val = CGI.escapeHTML(val)
|
||||
|
||||
if tok.shortname.empty?
|
||||
val
|
||||
else
|
||||
# In the case of multi-line values (e.g. comments), we need to apply
|
||||
# styling to each line since span elements are inline.
|
||||
if @inline_theme
|
||||
rules = @inline_theme.style_for(tok).rendered_rules
|
||||
wrap_values(val, "style=\"#{rules.to_a.join(';')}\"")
|
||||
else
|
||||
wrap_values(val, "class=\"#{tok.shortname}\"")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -38,6 +38,11 @@ upstream gitlab {
|
||||
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
|
||||
}
|
||||
|
||||
## Experimental: gitlab-git-http-server
|
||||
# upstream gitlab-git-http-server {
|
||||
# server localhost:8181;
|
||||
# }
|
||||
|
||||
## Normal HTTP host
|
||||
server {
|
||||
## Either remove "default_server" from the listen line below,
|
||||
@@ -109,6 +114,26 @@ server {
|
||||
proxy_pass http://gitlab;
|
||||
}
|
||||
|
||||
## Experimental: send Git HTTP traffic to gitlab-git-http-server instead of Unicorn
|
||||
# location ~ [-\/\w\.]+\.git\/ {
|
||||
# ## If you use HTTPS make sure you disable gzip compression
|
||||
# ## to be safe against BREACH attack.
|
||||
# # gzip off;
|
||||
|
||||
# ## https://github.com/gitlabhq/gitlabhq/issues/694
|
||||
# ## Some requests take more than 30 seconds.
|
||||
# proxy_read_timeout 300;
|
||||
# proxy_connect_timeout 300;
|
||||
# proxy_redirect off;
|
||||
|
||||
# proxy_set_header Host $http_host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# proxy_pass http://gitlab-git-http-server;
|
||||
# }
|
||||
|
||||
## Enable gzip compression as per rails guide:
|
||||
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
|
||||
## WARNING: If you are using relative urls remove the block below
|
||||
|
||||
@@ -42,6 +42,11 @@ upstream gitlab {
|
||||
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
|
||||
}
|
||||
|
||||
## Experimental: gitlab-git-http-server
|
||||
# upstream gitlab-git-http-server {
|
||||
# server localhost:8181;
|
||||
# }
|
||||
|
||||
## Redirects all HTTP traffic to the HTTPS host
|
||||
server {
|
||||
## Either remove "default_server" from the listen line below,
|
||||
@@ -156,6 +161,26 @@ server {
|
||||
proxy_pass http://gitlab;
|
||||
}
|
||||
|
||||
## Experimental: send Git HTTP traffic to gitlab-git-http-server instead of Unicorn
|
||||
# location ~ [-\/\w\.]+\.git\/ {
|
||||
# ## If you use HTTPS make sure you disable gzip compression
|
||||
# ## to be safe against BREACH attack.
|
||||
# gzip off;
|
||||
|
||||
# ## https://github.com/gitlabhq/gitlabhq/issues/694
|
||||
# ## Some requests take more than 30 seconds.
|
||||
# proxy_read_timeout 300;
|
||||
# proxy_connect_timeout 300;
|
||||
# proxy_redirect off;
|
||||
|
||||
# proxy_set_header Host $http_host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
# proxy_set_header X-Forwarded-Ssl on;
|
||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||
# proxy_pass http://gitlab-git-http-server;
|
||||
# }
|
||||
|
||||
## Enable gzip compression as per rails guide:
|
||||
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
|
||||
## WARNING: If you are using relative urls remove the block below
|
||||
|
||||