Commit ea6d4565 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-02-23

# Conflicts:
#	app/controllers/groups/application_controller.rb
#	app/finders/issuable_finder.rb
#	app/policies/base_policy.rb
#	app/policies/merge_request_policy.rb
#	app/views/layouts/nav/sidebar/_group.html.haml
#	locale/gitlab.pot

[ci skip]
parents abd17639 58a312f5
...@@ -418,6 +418,16 @@ export const convertObjectPropsToCamelCase = (obj = {}) => { ...@@ -418,6 +418,16 @@ export const convertObjectPropsToCamelCase = (obj = {}) => {
export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`; export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`;
export const addSelectOnFocusBehaviour = (selector = '.js-select-on-focus') => {
// Click a .js-select-on-focus field, select the contents
// Prevent a mouseup event from deselecting the input
$(selector).on('focusin', function selectOnFocusCallback() {
$(this).select().one('mouseup', (e) => {
e.preventDefault();
});
});
};
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gl.utils = { window.gl.utils = {
...(window.gl.utils || {}), ...(window.gl.utils || {}),
......
...@@ -10,7 +10,7 @@ window.jQuery = jQuery; ...@@ -10,7 +10,7 @@ window.jQuery = jQuery;
window.$ = jQuery; window.$ = jQuery;
// lib/utils // lib/utils
import { handleLocationHash } from './lib/utils/common_utils'; import { handleLocationHash, addSelectOnFocusBehaviour } from './lib/utils/common_utils';
import { localTimeAgo } from './lib/utils/datetime_utility'; import { localTimeAgo } from './lib/utils/datetime_utility';
import { getLocationHash, visitUrl } from './lib/utils/url_utility'; import { getLocationHash, visitUrl } from './lib/utils/url_utility';
...@@ -107,13 +107,7 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -107,13 +107,7 @@ document.addEventListener('DOMContentLoaded', () => {
return true; return true;
}); });
// Click a .js-select-on-focus field, select the contents addSelectOnFocusBehaviour('.js-select-on-focus');
// Prevent a mouseup event from deselecting the input
$('.js-select-on-focus').on('focusin', function selectOnFocusCallback() {
$(this).select().one('mouseup', (e) => {
e.preventDefault();
});
});
$('.remove-row').on('ajax:success', function removeRowAjaxSuccessCallback() { $('.remove-row').on('ajax:success', function removeRowAjaxSuccessCallback() {
$(this).tooltip('destroy') $(this).tooltip('destroy')
......
import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils';
let hasUserDefinedProjectPath = false; let hasUserDefinedProjectPath = false;
const deriveProjectPathFromUrl = ($projectImportUrl) => { const deriveProjectPathFromUrl = ($projectImportUrl) => {
...@@ -36,6 +38,7 @@ const bindEvents = () => { ...@@ -36,6 +38,7 @@ const bindEvents = () => {
const $changeTemplateBtn = $('.change-template'); const $changeTemplateBtn = $('.change-template');
const $selectedIcon = $('.selected-icon svg'); const $selectedIcon = $('.selected-icon svg');
const $templateProjectNameInput = $('#template-project-name #project_path'); const $templateProjectNameInput = $('#template-project-name #project_path');
const $pushNewProjectTipTrigger = $('.push-new-project-tip');
if ($newProjectForm.length !== 1) { if ($newProjectForm.length !== 1) {
return; return;
...@@ -55,6 +58,34 @@ const bindEvents = () => { ...@@ -55,6 +58,34 @@ const bindEvents = () => {
$('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`); $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`);
}); });
if ($pushNewProjectTipTrigger) {
$pushNewProjectTipTrigger
.removeAttr('rel')
.removeAttr('target')
.on('click', (e) => { e.preventDefault(); })
.popover({
title: $pushNewProjectTipTrigger.data('title'),
placement: 'auto bottom',
html: 'true',
content: $('.push-new-project-tip-template').html(),
})
.on('shown.bs.popover', () => {
$(document).on('click.popover touchstart.popover', (event) => {
if ($(event.target).closest('.popover').length === 0) {
$pushNewProjectTipTrigger.trigger('click');
}
});
const target = $(`#${$pushNewProjectTipTrigger.attr('aria-describedby')}`).find('.js-select-on-focus');
addSelectOnFocusBehaviour(target);
target.focus();
})
.on('hide.bs.popover', () => {
$(document).off('click.popover touchstart.popover');
});
}
function chooseTemplate() { function chooseTemplate() {
$('.template-option').hide(); $('.template-option').hide();
$projectFieldsForm.addClass('selected'); $projectFieldsForm.addClass('selected');
......
...@@ -333,6 +333,10 @@ a > code { ...@@ -333,6 +333,10 @@ a > code {
font-family: $monospace_font; font-family: $monospace_font;
} }
.weight-normal {
font-weight: $gl-font-weight-normal;
}
.commit-sha, .commit-sha,
.ref-name { .ref-name {
@extend .monospace; @extend .monospace;
......
...@@ -908,6 +908,12 @@ a.allowed-to-push { ...@@ -908,6 +908,12 @@ a.allowed-to-push {
} }
} }
.project-tip-command {
> .input-group-btn:first-child {
width: auto;
}
}
.protected-branches-list, .protected-branches-list,
.protected-tags-list { .protected-tags-list {
margin-bottom: 30px; margin-bottom: 30px;
......
class Groups::ApplicationController < ApplicationController class Groups::ApplicationController < ApplicationController
include RoutableActions include RoutableActions
<<<<<<< HEAD
prepend EE::Groups::ApplicationController prepend EE::Groups::ApplicationController
=======
>>>>>>> upstream/master
include ControllerWithCrossProjectAccessCheck include ControllerWithCrossProjectAccessCheck
layout 'group' layout 'group'
......
...@@ -9,6 +9,10 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -9,6 +9,10 @@ class Groups::GroupMembersController < Groups::ApplicationController
before_action :authorize_admin_group_member!, except: [:index, :leave, :request_access, :update, :override] before_action :authorize_admin_group_member!, except: [:index, :leave, :request_access, :update, :override]
before_action :authorize_update_group_member!, only: [:update, :override] before_action :authorize_update_group_member!, only: [:update, :override]
skip_cross_project_access_check :index, :create, :update, :destroy, :request_access,
:approve_access_request, :leave, :resend_invite,
:override
skip_cross_project_access_check :index, :create, :update, :destroy, :request_access, skip_cross_project_access_check :index, :create, :update, :destroy, :request_access,
:approve_access_request, :leave, :resend_invite, :approve_access_request, :leave, :resend_invite,
:override :override
......
...@@ -47,7 +47,7 @@ class ProjectsController < Projects::ApplicationController ...@@ -47,7 +47,7 @@ class ProjectsController < Projects::ApplicationController
notice: _("Project '%{project_name}' was successfully created.") % { project_name: @project.name } notice: _("Project '%{project_name}' was successfully created.") % { project_name: @project.name }
) )
else else
render 'new' render 'new', locals: { active_tab: ('import' if project_params[:import_url].present?) }
end end
end end
......
...@@ -117,7 +117,11 @@ class IssuableFinder ...@@ -117,7 +117,11 @@ class IssuableFinder
counts[:all] = counts.values.sum counts[:all] = counts.values.sum
<<<<<<< HEAD
counts.with_indifferent_access counts.with_indifferent_access
=======
counts
>>>>>>> upstream/master
end end
def group def group
......
...@@ -263,6 +263,17 @@ module ProjectsHelper ...@@ -263,6 +263,17 @@ module ProjectsHelper
!!(params[:personal] || params[:name] || any_projects?(projects)) !!(params[:personal] || params[:name] || any_projects?(projects))
end end
def push_to_create_project_command(user = current_user)
repository_url =
if Gitlab::CurrentSettings.current_application_settings.enabled_git_access_protocol == 'http'
user_url(user)
else
Gitlab.config.gitlab_shell.ssh_path_prefix + user.username
end
"git push --set-upstream #{repository_url}/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)"
end
private private
def repo_children_classes(field) def repo_children_classes(field)
......
...@@ -20,6 +20,7 @@ class BasePolicy < DeclarativePolicy::Base ...@@ -20,6 +20,7 @@ class BasePolicy < DeclarativePolicy::Base
# This is prevented in some cases in `gitlab-ee` # This is prevented in some cases in `gitlab-ee`
rule { default }.enable :read_cross_project rule { default }.enable :read_cross_project
<<<<<<< HEAD
# EE Extensions # EE Extensions
with_scope :user with_scope :user
...@@ -30,4 +31,6 @@ class BasePolicy < DeclarativePolicy::Base ...@@ -30,4 +31,6 @@ class BasePolicy < DeclarativePolicy::Base
with_scope :global with_scope :global
condition(:license_block) { License.block_changes? } condition(:license_block) { License.block_changes? }
=======
>>>>>>> upstream/master
end end
class MergeRequestPolicy < IssuablePolicy class MergeRequestPolicy < IssuablePolicy
<<<<<<< HEAD
prepend EE::MergeRequestPolicy prepend EE::MergeRequestPolicy
=======
>>>>>>> upstream/master
rule { can?(:read_merge_request) | visible_to_user }.enable :read_merge_request_iid rule { can?(:read_merge_request) | visible_to_user }.enable :read_merge_request_iid
end end
...@@ -2,8 +2,11 @@ ...@@ -2,8 +2,11 @@
- merge_requests_count = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute.count - merge_requests_count = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute.count
- issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index'] - issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index']
<<<<<<< HEAD
- if @group.feature_available?(:group_issue_boards) - if @group.feature_available?(:group_issue_boards)
- issues_sub_menu_items.push('boards#index', 'boards#show') - issues_sub_menu_items.push('boards#index', 'boards#show')
=======
>>>>>>> upstream/master
.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) } .nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
.nav-sidebar-inner-scroll .nav-sidebar-inner-scroll
...@@ -39,6 +42,7 @@ ...@@ -39,6 +42,7 @@
%span %span
Activity Activity
<<<<<<< HEAD
- if group_sidebar_link?(:contribution_analytics) - if group_sidebar_link?(:contribution_analytics)
= nav_link(path: 'analytics#show') do = nav_link(path: 'analytics#show') do
= link_to group_analytics_path(@group), title: 'Contribution Analytics', data: {placement: 'right'} do = link_to group_analytics_path(@group), title: 'Contribution Analytics', data: {placement: 'right'} do
...@@ -47,6 +51,8 @@ ...@@ -47,6 +51,8 @@
= render "layouts/nav/ee/epic_link", group: @group = render "layouts/nav/ee/epic_link", group: @group
=======
>>>>>>> upstream/master
- if group_sidebar_link?(:issues) - if group_sidebar_link?(:issues)
= nav_link(path: issues_sub_menu_items) do = nav_link(path: issues_sub_menu_items) do
= link_to issues_group_path(@group) do = link_to issues_group_path(@group) do
...@@ -68,12 +74,15 @@ ...@@ -68,12 +74,15 @@
%span %span
List List
<<<<<<< HEAD
- if group_sidebar_link?(:boards) - if group_sidebar_link?(:boards)
= nav_link(path: ['boards#index', 'boards#show']) do = nav_link(path: ['boards#index', 'boards#show']) do
= link_to group_boards_path(@group), title: 'Boards' do = link_to group_boards_path(@group), title: 'Boards' do
%span %span
Boards Boards
=======
>>>>>>> upstream/master
- if group_sidebar_link?(:labels) - if group_sidebar_link?(:labels)
= nav_link(path: 'labels#index') do = nav_link(path: 'labels#index') do
= link_to group_labels_path(@group), title: 'Labels' do = link_to group_labels_path(@group), title: 'Labels' do
......
.push-to-create-popover
%p
= label_tag(:push_to_create_tip, _("Private projects can be created in your personal namespace with:"), class: "weight-normal")
%p.input-group.project-tip-command
%span.input-group-btn
= text_field_tag :push_to_create_tip, push_to_create_project_command, class: "js-select-on-focus form-control monospace", readonly: true, aria: { label: _("Push project from command line") }
%span.input-group-btn
= clipboard_button(text: push_to_create_project_command, title: _("Copy command to clipboard"), placement: "right")
%p
= link_to("What does this command do?", help_page_path("gitlab-basics/create-project", anchor: "push-to-create-a-new-project"), target: "_blank")
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
- page_title 'New Project' - page_title 'New Project'
- header_title "Projects", dashboard_projects_path - header_title "Projects", dashboard_projects_path
- visibility_level = params.dig(:project, :visibility_level) || default_project_visibility - visibility_level = params.dig(:project, :visibility_level) || default_project_visibility
- active_tab = local_assigns.fetch(:active_tab, 'blank')
.project-edit-container .project-edit-container
.project-edit-errors .project-edit-errors
...@@ -18,34 +19,41 @@ ...@@ -18,34 +19,41 @@
All features are enabled when you create a project, but you can disable the ones you don’t need in the project settings. All features are enabled when you create a project, but you can disable the ones you don’t need in the project settings.
.md .md
= brand_new_project_guidelines = brand_new_project_guidelines
%p
%strong= _("Tip:")
= _("You can also create a project from the command line.")
%a.push-new-project-tip{ data: { title: _("Push to create a project") }, href: help_page_path('gitlab-basics/create-project', anchor: 'push-to-create-a-new-project'), target: "_blank", rel: "noopener noreferrer" }
= _("Show command")
%template.push-new-project-tip-template= render partial: "new_project_push_tip"
.col-lg-9.js-toggle-container .col-lg-9.js-toggle-container
%ul.nav-links.gitlab-tabs{ role: 'tablist' } %ul.nav-links.gitlab-tabs{ role: 'tablist' }
%li.active{ role: 'presentation' } %li{ class: ('active' if active_tab == 'blank'), role: 'presentation' }
%a{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Blank project %span.hidden-xs Blank project
%span.visible-xs Blank %span.visible-xs Blank
%li{ role: 'presentation' } %li{ class: ('active' if active_tab == 'template'), role: 'presentation' }
%a{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' } %a{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Create from template %span.hidden-xs Create from template
%span.visible-xs Template %span.visible-xs Template
%li{ role: 'presentation' } %li{ class: ('active' if active_tab == 'import'), role: 'presentation' }
%a{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Import project %span.hidden-xs Import project
%span.visible-xs Import %span.visible-xs Import
.tab-content.gitlab-tab-content .tab-content.gitlab-tab-content
.tab-pane.active{ id: 'blank-project-pane', role: 'tabpanel' } .tab-pane{ id: 'blank-project-pane', class: ('active' if active_tab == 'blank'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f| = form_for @project, html: { class: 'new_project' } do |f|
= render 'new_project_fields', f: f, project_name_id: "blank-project-name" = render 'new_project_fields', f: f, project_name_id: "blank-project-name"
.tab-pane.no-padding{ id: 'create-from-template-pane', role: 'tabpanel' } .tab-pane.no-padding{ id: 'create-from-template-pane', class: ('active' if active_tab == 'template'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f| = form_for @project, html: { class: 'new_project' } do |f|
.project-template .project-template
.form-group .form-group
%div %div
= render 'project_templates', f: f = render 'project_templates', f: f
.tab-pane.import-project-pane{ id: 'import-project-pane', role: 'tabpanel' } .tab-pane.import-project-pane{ id: 'import-project-pane', class: ('active' if active_tab == 'import'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f| = form_for @project, html: { class: 'new_project' } do |f|
- if import_sources_enabled? - if import_sources_enabled?
.project-import.row .project-import.row
...@@ -92,7 +100,7 @@ ...@@ -92,7 +100,7 @@
%button.btn.js-toggle-button.import_git{ type: "button" } %button.btn.js-toggle-button.import_git{ type: "button" }
= icon('git', text: 'Repo by URL') = icon('git', text: 'Repo by URL')
.col-lg-12 .col-lg-12
.js-toggle-content.hide.toggle-import-form .js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') }
%hr %hr
= render "shared/import_form", f: f = render "shared/import_form", f: f
= render 'new_project_fields', f: f, project_name_id: "import-url-name" = render 'new_project_fields', f: f, project_name_id: "import-url-name"
......
---
title: Keep "Import project" tab/form active when validation fails trying to import
"Repo by URL"
merge_request: 17136
author:
type: fixed
---
title: Allow token authentication on go-get request
merge_request:
author:
type: changed
...@@ -47,10 +47,10 @@ This can be done by using either SSH or HTTP: ...@@ -47,10 +47,10 @@ This can be done by using either SSH or HTTP:
``` ```
## Git push using SSH ## Git push using SSH
git push git@gitlab.example.com:namespace/nonexistent-project.git git push --set-upstream git@gitlab.example.com:namespace/nonexistent-project.git master
## Git push using HTTP ## Git push using HTTP
git push https://gitlab.example.com/namespace/nonexistent-project.git git push --set-upstream https://gitlab.example.com/namespace/nonexistent-project.git master
``` ```
Once the push finishes successfully, a remote message will indicate Once the push finishes successfully, a remote message will indicate
......
...@@ -19,8 +19,9 @@ module Banzai ...@@ -19,8 +19,9 @@ module Banzai
# #
# Returns the documents passed as the first argument. # Returns the documents passed as the first argument.
def redact(documents) def redact(documents)
all_document_nodes = document_nodes(documents) redact_cross_project_references(documents) unless can_read_cross_project?
all_document_nodes = document_nodes(documents)
redact_document_nodes(all_document_nodes) redact_document_nodes(all_document_nodes)
end end
...@@ -51,6 +52,18 @@ module Banzai ...@@ -51,6 +52,18 @@ module Banzai
metadata metadata
end end
def redact_cross_project_references(documents)
extractor = Banzai::IssuableExtractor.new(project, user)
issuables = extractor.extract(documents)
issuables.each do |node, issuable|
next if issuable.project == project
node['class'] = node['class'].gsub('has-tooltip', '')
node['title'] = nil
end
end
# Returns the nodes visible to the current user. # Returns the nodes visible to the current user.
# #
# nodes - The input nodes to check. # nodes - The input nodes to check.
...@@ -78,5 +91,11 @@ module Banzai ...@@ -78,5 +91,11 @@ module Banzai
{ document: document, nodes: Querying.css(document, 'a.gfm[data-reference-type]') } { document: document, nodes: Querying.css(document, 'a.gfm[data-reference-type]') }
end end
end end
private
def can_read_cross_project?
Ability.allowed?(user, :read_cross_project)
end
end end
end end
...@@ -20,6 +20,14 @@ module Gitlab ...@@ -20,6 +20,14 @@ module Gitlab
rescue Gitlab::Auth::AuthenticationError rescue Gitlab::Auth::AuthenticationError
nil nil
end end
def valid_access_token?(scopes: [])
validate_access_token!(scopes: scopes)
true
rescue Gitlab::Auth::AuthenticationError
false
end
end end
end end
end end
...@@ -114,7 +114,15 @@ module Gitlab ...@@ -114,7 +114,15 @@ module Gitlab
end end
def current_user(request) def current_user(request)
request.env['warden']&.authenticate authenticator = Gitlab::Auth::RequestAuthenticator.new(request)
user = authenticator.find_user_from_access_token || authenticator.find_user_from_warden
return unless user&.can?(:access_api)
# Right now, the `api` scope is the only one that should be able to determine private project existence.
return unless authenticator.valid_access_token?(scopes: [:api])
user
end end
end end
end end
......
...@@ -8,8 +8,13 @@ msgid "" ...@@ -8,8 +8,13 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gitlab 1.0.0\n" "Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
<<<<<<< HEAD
"POT-Creation-Date: 2018-02-22 17:55+0100\n" "POT-Creation-Date: 2018-02-22 17:55+0100\n"
"PO-Revision-Date: 2018-02-22 17:55+0100\n" "PO-Revision-Date: 2018-02-22 17:55+0100\n"
=======
"POT-Creation-Date: 2018-02-20 10:26+0100\n"
"PO-Revision-Date: 2018-02-20 10:26+0100\n"
>>>>>>> upstream/master
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n" "Language: \n"
...@@ -195,9 +200,12 @@ msgstr "" ...@@ -195,9 +200,12 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{username}" msgid "AdminUsers|To confirm, type %{username}"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Advanced" msgid "Advanced"
msgstr "" msgstr ""
=======
>>>>>>> upstream/master
msgid "Advanced settings" msgid "Advanced settings"
msgstr "" msgstr ""
...@@ -243,9 +251,12 @@ msgstr "" ...@@ -243,9 +251,12 @@ msgstr ""
msgid "An error occurred while importing project" msgid "An error occurred while importing project"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "An error occurred while initializing path locks" msgid "An error occurred while initializing path locks"
msgstr "" msgstr ""
=======
>>>>>>> upstream/master
msgid "An error occurred while loading commits" msgid "An error occurred while loading commits"
msgstr "" msgstr ""
...@@ -258,12 +269,15 @@ msgstr "" ...@@ -258,12 +269,15 @@ msgstr ""
msgid "An error occurred while loading the file" msgid "An error occurred while loading the file"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "An error occurred while making the request." msgid "An error occurred while making the request."
msgstr "" msgstr ""
msgid "An error occurred while removing approver" msgid "An error occurred while removing approver"
msgstr "" msgstr ""
=======
>>>>>>> upstream/master
msgid "An error occurred while rendering KaTeX" msgid "An error occurred while rendering KaTeX"
msgstr "" msgstr ""
...@@ -276,9 +290,12 @@ msgstr "" ...@@ -276,9 +290,12 @@ msgstr ""
msgid "An error occurred while retrieving diff" msgid "An error occurred while retrieving diff"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "An error occurred while saving LDAP override status. Please try again." msgid "An error occurred while saving LDAP override status. Please try again."
msgstr "" msgstr ""
=======
>>>>>>> upstream/master
msgid "An error occurred while saving assignees" msgid "An error occurred while saving assignees"
msgstr "" msgstr ""
...@@ -2990,9 +3007,12 @@ msgstr "" ...@@ -2990,9 +3007,12 @@ msgstr ""
msgid "Something went wrong while closing the issue. Please try again later" msgid "Something went wrong while closing the issue. Please try again later"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Something went wrong while fetching SAST." msgid "Something went wrong while fetching SAST."
msgstr "" msgstr ""
=======
>>>>>>> upstream/master
msgid "Something went wrong while fetching the projects." msgid "Something went wrong while fetching the projects."
msgstr "" msgstr ""
...@@ -3593,9 +3613,12 @@ msgstr "" ...@@ -3593,9 +3613,12 @@ msgstr ""
msgid "Trigger this manual action" msgid "Trigger this manual action"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Turn on Service Desk" msgid "Turn on Service Desk"
msgstr "" msgstr ""
=======
>>>>>>> upstream/master
msgid "Unable to reset project cache." msgid "Unable to reset project cache."
msgstr "" msgstr ""
...@@ -4008,6 +4031,7 @@ msgstr[1] "" ...@@ -4008,6 +4031,7 @@ msgstr[1] ""
msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch" msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "mrWidget|An error occured while removing your approval." msgid "mrWidget|An error occured while removing your approval."
msgstr "" msgstr ""
...@@ -4026,6 +4050,8 @@ msgstr "" ...@@ -4026,6 +4050,8 @@ msgstr ""
msgid "mrWidget|Approved by" msgid "mrWidget|Approved by"
msgstr "" msgstr ""
=======
>>>>>>> upstream/master
msgid "mrWidget|Cancel automatic merge" msgid "mrWidget|Cancel automatic merge"
msgstr "" msgstr ""
......
...@@ -140,7 +140,7 @@ feature 'New project' do ...@@ -140,7 +140,7 @@ feature 'New project' do
find('#import-project-tab').click find('#import-project-tab').click
end end
context 'from git repository url' do context 'from git repository url, "Repo by URL"' do
before do before do
first('.import_git').click first('.import_git').click
end end
...@@ -157,6 +157,18 @@ feature 'New project' do ...@@ -157,6 +157,18 @@ feature 'New project' do
expect(git_import_instructions).to be_visible expect(git_import_instructions).to be_visible
expect(git_import_instructions).to have_content 'Git repository URL' expect(git_import_instructions).to have_content 'Git repository URL'
end end
it 'keeps "Import project" tab open after form validation error' do
collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace)
fill_in 'project_import_url', with: collision_project.http_url_to_repo
fill_in 'project_path', with: collision_project.path
click_on 'Create project'
expect(page).to have_css('#import-project-pane.active')
expect(page).not_to have_css('.toggle-import-form.hide')
end
end end
context 'from GitHub' do context 'from GitHub' do
......
...@@ -25,6 +25,24 @@ feature 'Project' do ...@@ -25,6 +25,24 @@ feature 'Project' do
end end
end end
describe 'shows tip about push to create git command' do
let(:user) { create(:user) }
before do
sign_in user
visit new_project_path
end
it 'shows the command in a popover', :js do
page.within '.profile-settings-sidebar' do
click_link 'Show command'
end
expect(page).to have_css('.popover .push-to-create-popover #push_to_create_tip')
expect(page).to have_content 'Private projects can be created in your personal namespace with:'
end
end
describe 'description' do describe 'description' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:path) { project_path(project) } let(:path) { project_path(project) }
......
...@@ -178,9 +178,27 @@ describe SnippetsFinder do ...@@ -178,9 +178,27 @@ describe SnippetsFinder do
end end
end end
describe "#execute" do describe '#execute' do
# Snippet visibility scenarios are included in more details in spec/support/snippet_visibility.rb let(:project) { create(:project, :public) }
include_examples 'snippet visibility', described_class let!(:project_snippet) { create(:project_snippet, :public, project: project) }
let!(:personal_snippet) { create(:personal_snippet, :public) }
let(:user) { create(:user) }
subject(:finder) { described_class.new(user) }
it 'returns project- and personal snippets' do
expect(finder.execute).to contain_exactly(project_snippet, personal_snippet)
end
context 'when the user cannot read cross project' do
before do
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
end
it 'returns only personal snippets when the user cannot read cross project' do
expect(finder.execute).to contain_exactly(personal_snippet)
end
end
end end
describe '#execute' do describe '#execute' do
......
...@@ -455,6 +455,22 @@ describe ProjectsHelper do ...@@ -455,6 +455,22 @@ describe ProjectsHelper do
end end
end end
describe('#push_to_create_project_command') do
let(:user) { create(:user, username: 'john') }
it 'returns the command to push to create project over HTTP' do
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'http' }
expect(helper.push_to_create_project_command(user)).to eq('git push --set-upstream http://test.host/john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)')
end
it 'returns the command to push to create project over SSH' do
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'ssh' }
expect(helper.push_to_create_project_command(user)).to eq('git push --set-upstream git@localhost:john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)')
end
end
describe '#any_projects?' do describe '#any_projects?' do
let!(:project) { create(:project) } let!(:project) { create(:project) }
......
...@@ -6,7 +6,7 @@ describe Banzai::Filter::RedactorFilter do ...@@ -6,7 +6,7 @@ describe Banzai::Filter::RedactorFilter do
it 'ignores non-GFM links' do it 'ignores non-GFM links' do
html = %(See <a href="https://google.com/">Google</a>) html = %(See <a href="https://google.com/">Google</a>)
doc = filter(html, current_user: double) doc = filter(html, current_user: build(:user))
expect(doc.css('a').length).to eq 1 expect(doc.css('a').length).to eq 1
end end
......
...@@ -88,6 +88,55 @@ describe Banzai::Redactor do ...@@ -88,6 +88,55 @@ describe Banzai::Redactor do
end end
end end
context 'when the user cannot read cross project' do
include ActionView::Helpers::UrlHelper
let(:project) { create(:project) }
let(:other_project) { create(:project, :public) }
def create_link(issuable)
type = issuable.class.name.underscore.downcase
link_to(issuable.to_reference, '',
class: 'gfm has-tooltip',
title: issuable.title,
data: {
reference_type: type,
"#{type}": issuable.id
})
end
before do
project.add_developer(user)
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global) { false }
allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
end
it 'skips links to issues within the same project' do
issue = create(:issue, project: project)
link = create_link(issue)
doc = Nokogiri::HTML.fragment(link)
redactor.redact([doc])
result = doc.css('a').last
expect(result['class']).to include('has-tooltip')
expect(result['title']).to eq(issue.title)
end
it 'removes info from a cross project reference' do
issue = create(:issue, project: other_project)
link = create_link(issue)
doc = Nokogiri::HTML.fragment(link)
redactor.redact([doc])
result = doc.css('a').last
expect(result['class']).not_to include('has-tooltip')
expect(result['title']).to be_empty
end
end
describe '#redact_nodes' do describe '#redact_nodes' do
it 'redacts an Array of nodes' do it 'redacts an Array of nodes' do
doc = Nokogiri::HTML.fragment('<a href="foo">foo</a>') doc = Nokogiri::HTML.fragment('<a href="foo">foo</a>')
......
...@@ -3,19 +3,30 @@ require 'spec_helper' ...@@ -3,19 +3,30 @@ require 'spec_helper'
describe Gitlab::Middleware::Go do describe Gitlab::Middleware::Go do
let(:app) { double(:app) } let(:app) { double(:app) }
let(:middleware) { described_class.new(app) } let(:middleware) { described_class.new(app) }
let(:env) do
{
'rack.input' => '',
'REQUEST_METHOD' => 'GET'
}
end
describe '#call' do describe '#call' do
describe 'when go-get=0' do describe 'when go-get=0' do
before do
env['QUERY_STRING'] = 'go-get=0'
end
it 'skips go-import generation' do it 'skips go-import generation' do
env = { 'rack.input' => '',
'QUERY_STRING' => 'go-get=0' }
expect(app).to receive(:call).with(env).and_return('no-go') expect(app).to receive(:call).with(env).and_return('no-go')
middleware.call(env) middleware.call(env)
end end
end end
describe 'when go-get=1' do describe 'when go-get=1' do
let(:current_user) { nil } before do
env['QUERY_STRING'] = 'go-get=1'
env['PATH_INFO'] = "/#{path}"
end
shared_examples 'go-get=1' do |enabled_protocol:| shared_examples 'go-get=1' do |enabled_protocol:|
context 'with simple 2-segment project path' do context 'with simple 2-segment project path' do
...@@ -54,21 +65,75 @@ describe Gitlab::Middleware::Go do ...@@ -54,21 +65,75 @@ describe Gitlab::Middleware::Go do
project.update_attribute(:visibility_level, Project::PRIVATE) project.update_attribute(:visibility_level, Project::PRIVATE)
end end
context 'with access to the project' do shared_examples 'unauthorized' do
it 'returns the 2-segment group path' do
expect_response_with_path(go, enabled_protocol, group.full_path)
end
end
context 'when not authenticated' do
it_behaves_like 'unauthorized'
end
context 'when authenticated' do
let(:current_user) { project.creator } let(:current_user) { project.creator }
before do before do
project.team.add_master(current_user) project.team.add_master(current_user)
end end
it 'returns the full project path' do shared_examples 'authenticated' do
expect_response_with_path(go, enabled_protocol, project.full_path) context 'with access to the project' do
it 'returns the full project path' do
expect_response_with_path(go, enabled_protocol, project.full_path)
end
end
context 'without access to the project' do
before do
project.team.find_member(current_user).destroy
end
it_behaves_like 'unauthorized'
end
end end
end
context 'without access to the project' do context 'using warden' do
it 'returns the 2-segment group path' do before do
expect_response_with_path(go, enabled_protocol, group.full_path) env['warden'] = double(authenticate: current_user)
end
context 'when active' do
it_behaves_like 'authenticated'
end
context 'when blocked' do
before do
current_user.block!
end
it_behaves_like 'unauthorized'
end
end
context 'using a personal access token' do
let(:personal_access_token) { create(:personal_access_token, user: current_user) }
before do
env['HTTP_PRIVATE_TOKEN'] = personal_access_token.token
end
context 'with api scope' do
it_behaves_like 'authenticated'
end
context 'with read_user scope' do
before do
personal_access_token.update_attribute(:scopes, [:read_user])
end
it_behaves_like 'unauthorized'
end
end end
end end
end end
...@@ -138,12 +203,6 @@ describe Gitlab::Middleware::Go do ...@@ -138,12 +203,6 @@ describe Gitlab::Middleware::Go do
end end
def go def go
env = {
'rack.input' => '',
'QUERY_STRING' => 'go-get=1',
'PATH_INFO' => "/#{path}",
'warden' => double(authenticate: current_user)
}
middleware.call(env) middleware.call(env)
end end
......
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