BigW Consortium Gitlab

Commit 2838ae28 by Felipe Artur

Merge branch '10-1-stable-patch-2' into '10-1-stable'

Prepare 10.1.3 release See merge request gitlab-org/gitlab-ce!15209
parents 8fef7a47 f9dd9e1a
/* globals Flash */
import Visibility from 'visibilityjs';
import axios from 'axios';
import setAxiosCsrfToken from './lib/utils/axios_utils';
import Poll from './lib/utils/poll';
import { s__ } from './locale';
import './flash';
......@@ -16,6 +17,7 @@ import './flash';
class ClusterService {
constructor(options = {}) {
this.options = options;
setAxiosCsrfToken();
}
fetchData() {
return axios.get(this.options.endpoint);
......
......@@ -127,11 +127,9 @@ window.DropzoneInput = (function() {
// removeAllFiles(true) stops uploading files (if any)
// and remove them from dropzone files queue.
$cancelButton.on('click', (e) => {
const target = e.target.closest('.js-main-target-form').querySelector('.div-dropzone');
e.preventDefault();
e.stopPropagation();
Dropzone.forElement(target).removeAllFiles(true);
Dropzone.forElement($formDropzone.get(0)).removeAllFiles(true);
});
// If 'error' event is fired, we store a failed files,
......
import axios from 'axios';
import csrf from './csrf';
export default function setAxiosCsrfToken() {
axios.defaults.headers.common[csrf.headerKey] = csrf.token;
}
function expandSectionParent($section, $content) {
$section.addClass('expanded');
$content.off('animationend.expandSectionParent');
}
function expandSection($section) {
$section.find('.js-settings-toggle').text('Collapse');
const $content = $section.find('.settings-content');
$content.addClass('expanded').off('scroll.expandSection').scrollTop(0);
if ($content.hasClass('no-animate')) {
expandSectionParent($section, $content);
} else {
$content.on('animationend.expandSectionParent', () => expandSectionParent($section, $content));
$section.find('.settings-content').off('scroll.expandSection').scrollTop(0);
$section.addClass('expanded');
if (!$section.hasClass('no-animate')) {
$section.addClass('animating')
.one('animationend.animateSection', () => $section.removeClass('animating'));
}
}
function closeSection($section) {
$section.find('.js-settings-toggle').text('Expand');
const $content = $section.find('.settings-content');
$content.removeClass('expanded').on('scroll.expandSection', () => expandSection($section));
$section.find('.settings-content').on('scroll.expandSection', () => expandSection($section));
$section.removeClass('expanded');
if (!$section.hasClass('no-animate')) {
$section.addClass('animating')
.one('animationend.animateSection', () => $section.removeClass('animating'));
}
}
function toggleSection($section) {
const $content = $section.find('.settings-content');
$content.removeClass('no-animate');
if ($content.hasClass('expanded')) {
$section.removeClass('no-animate');
if ($section.hasClass('expanded')) {
closeSection($section);
} else {
expandSection($section);
......@@ -39,10 +31,19 @@ export default function initSettingsPanels() {
$('.settings').each((i, elm) => {
const $section = $(elm);
$section.on('click.toggleSection', '.js-settings-toggle', () => toggleSection($section));
$section.find('.settings-content:not(.expanded)').on('scroll.expandSection', () => expandSection($section));
if (!$section.hasClass('expanded')) {
$section.find('.settings-content').on('scroll.expandSection', () => {
$section.removeClass('no-animate');
expandSection($section);
});
}
});
if (location.hash) {
expandSection($(location.hash));
const $target = $(location.hash);
if ($target.length && $target.hasClass('.settings')) {
expandSection($target);
}
}
}
......@@ -23,15 +23,14 @@
}
.settings {
overflow: hidden;
border-bottom: 1px solid $gray-darker;
&:first-of-type {
margin-top: 10px;
}
&.expanded {
overflow: visible;
&.animating {
overflow: hidden;
}
}
......@@ -56,14 +55,18 @@
overflow-y: scroll;
padding-right: 110px;
animation: collapseMaxHeight 300ms ease-out;
// Keep the section from expanding when we scroll over it
pointer-events: none;
&.expanded {
.settings.expanded & {
max-height: none;
overflow-y: visible;
animation: expandMaxHeight 300ms ease-in;
// Reset and allow clicks again when expanded
pointer-events: auto;
}
&.no-animate {
.settings.no-animate & {
animation: none;
}
......
......@@ -94,10 +94,9 @@ module LfsRequest
@storage_project ||= begin
result = project
loop do
break unless result.forked?
result = result.forked_from_project
end
# TODO: Make this go to the fork_network root immeadiatly
# dependant on the discussion in: https://gitlab.com/gitlab-org/gitlab-ce/issues/39769
result = result.fork_source while result.forked?
result
end
......
......@@ -4,6 +4,7 @@ module NotesActions
included do
before_action :set_polling_interval_header, only: [:index]
before_action :noteable, only: :index
before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :note_project, only: [:create]
end
......@@ -188,7 +189,7 @@ module NotesActions
end
def noteable
@noteable ||= notes_finder.target
@noteable ||= notes_finder.target || render_404
end
def last_fetched_at
......
......@@ -97,7 +97,15 @@ module ProjectsHelper
def remove_fork_project_message(project)
_("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") %
{ forked_from_project: @project.forked_from_project.name_with_namespace }
{ forked_from_project: fork_source_name(project) }
end
def fork_source_name(project)
if @project.fork_source
@project.fork_source.full_name
else
@project.fork_network&.deleted_root_project_name
end
end
def project_nav_tabs
......@@ -127,8 +135,8 @@ module ProjectsHelper
def can_change_visibility_level?(project, current_user)
return false unless can?(current_user, :change_visibility_level, project)
if project.forked?
project.forked_from_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE
if project.fork_source
project.fork_source.visibility_level > Gitlab::VisibilityLevel::PRIVATE
else
true
end
......
......@@ -110,7 +110,7 @@ class Environment < ActiveRecord::Base
end
def ref_path
"refs/#{Repository::REF_ENVIRONMENTS}/#{generate_slug}"
"refs/#{Repository::REF_ENVIRONMENTS}/#{slug}"
end
def formatted_external_url
......@@ -164,6 +164,10 @@ class Environment < ActiveRecord::Base
end
end
def slug
super.presence || generate_slug
end
# An environment name is not necessarily suitable for use in URLs, DNS
# or other third-party contexts, so provide a slugified version. A slug has
# the following properties:
......
......@@ -12,4 +12,8 @@ class ForkNetwork < ActiveRecord::Base
def find_forks_in(other_projects)
projects.where(id: other_projects)
end
def merge_requests
MergeRequest.where(target_project: projects)
end
end
......@@ -1017,6 +1017,10 @@ class Project < ActiveRecord::Base
!(forked_project_link.nil? || forked_project_link.forked_from_project.nil?)
end
def fork_source
forked_from_project || fork_network&.root_project
end
def personal?
!group
end
......
......@@ -164,7 +164,7 @@ class User < ActiveRecord::Base
before_validation :set_notification_email, if: :email_changed?
before_validation :set_public_email, if: :public_email_changed?
before_save :ensure_authentication_token, :ensure_incoming_email_token
before_save :ensure_user_rights_and_limits, if: :external_changed?
before_save :ensure_user_rights_and_limits, if: ->(user) { user.new_record? || user.external_changed? }
before_save :skip_reconfirmation!, if: ->(user) { user.email_changed? && user.read_only_attribute?(:email) }
before_save :check_for_verified_email, if: ->(user) { user.email_changed? && !user.new_record? }
after_save :ensure_namespace_correct
......@@ -1141,8 +1141,9 @@ class User < ActiveRecord::Base
self.can_create_group = false
self.projects_limit = 0
else
self.can_create_group = gitlab_config.default_can_create_group
self.projects_limit = current_application_settings.default_projects_limit
# Only revert these back to the default if they weren't specifically changed in this update.
self.can_create_group = gitlab_config.default_can_create_group unless can_create_group_changed?
self.projects_limit = current_application_settings.default_projects_limit unless projects_limit_changed?
end
end
......
......@@ -18,15 +18,7 @@ module MergeRequests
@merge_request = merge_request
unless @merge_request.mergeable?
return handle_merge_error(log_message: 'Merge request is not mergeable', save_message_on_model: true)
end
@source = find_merge_source
unless @source
return handle_merge_error(log_message: 'No source for merge', save_message_on_model: true)
end
error_check!
merge_request.in_locked_state do
if commit
......@@ -41,6 +33,19 @@ module MergeRequests
private
def error_check!
error =
if @merge_request.should_be_rebased?
'Only fast-forward merge is allowed for your project. Please update your source branch'
elsif !@merge_request.mergeable?
'Merge request is not mergeable'
elsif !source
'No source for merge'
end
raise MergeError, error if error
end
def commit
message = params[:commit_message] || merge_request.merge_commit_message
......@@ -95,8 +100,8 @@ module MergeRequests
merge_request.to_reference(full: true)
end
def find_merge_source
merge_request.diff_head_sha
def source
@source ||= @merge_request.diff_head_sha
end
end
end
......@@ -6,8 +6,7 @@ class MetricsService
Gitlab::HealthChecks::Redis::RedisCheck,
Gitlab::HealthChecks::Redis::CacheCheck,
Gitlab::HealthChecks::Redis::QueuesCheck,
Gitlab::HealthChecks::Redis::SharedStateCheck,
Gitlab::HealthChecks::FsShardsCheck
Gitlab::HealthChecks::Redis::SharedStateCheck
].freeze
def prometheus_metrics_text
......
......@@ -3,18 +3,24 @@ module Projects
def execute
return unless @project.forked?
@project.forked_from_project.lfs_objects.find_each do |lfs_object|
lfs_object.projects << @project
if fork_source = @project.fork_source
fork_source.lfs_objects.find_each do |lfs_object|
lfs_object.projects << @project
end
refresh_forks_count(fork_source)
end
merge_requests = @project.forked_from_project.merge_requests.opened.from_project(@project)
merge_requests = @project.fork_network
.merge_requests
.opened
.where.not(target_project: @project)
.from_project(@project)
merge_requests.each do |mr|
::MergeRequests::CloseService.new(@project, @current_user).execute(mr)
end
refresh_forks_count(@project.forked_from_project)
@project.fork_network_member.destroy
@project.forked_project_link.destroy
end
......
......@@ -24,7 +24,7 @@
%td
= truncate(hook_log.url, length: 50)
%td.light
#{number_with_precision(hook_log.execution_duration, precision: 2)} ms
#{number_with_precision(hook_log.execution_duration, precision: 2)} sec
%td.light
= time_ago_with_tooltip(hook_log.created_at)
%td
......
......@@ -3,7 +3,7 @@
- project = local_assigns.fetch(:project)
- expanded = Rails.env.test?
%section.settings
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Export project
......@@ -11,7 +11,7 @@
= expanded ? 'Collapse' : 'Expand'
%p
Export this project with all its related data in order to move your project to a new GitLab instance. Once the export is finished, you can import the file from the "New Project" page.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
.bs-callout.bs-callout-info
%p.append-bottom-0
%p
......
- empty_repo = @project.empty_repo?
- fork_network = @project.fork_network
- forked_from_project = @project.forked_from_project || fork_network&.root_project
.project-home-panel.text-center{ class: ("empty-project" if empty_repo) }
.limit-container-width{ class: container_class }
.avatar-container.s70.project-avatar
......@@ -16,13 +15,13 @@
- if @project.forked?
%p
- if forked_from_project
- if @project.fork_source
#{ s_('ForkedFromProjectPath|Forked from') }
= link_to project_path(forked_from_project) do
= forked_from_project.full_name
= link_to project_path(@project.fork_source) do
= fork_source_name(@project)
- else
- deleted_message = s_('ForkedFromProjectPath|Forked from %{project_name} (deleted)')
= deleted_message % { project_name: fork_network.deleted_root_project_name }
= deleted_message % { project_name: fork_source_name(@project) }
.project-repo-buttons
.count-buttons
......
......@@ -11,4 +11,4 @@
= s_('ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters').html_safe % { link_to_requirements: link_to_requirements }
%li
- link_to_container_project = link_to(s_('ClusterIntegration|Google Container Engine project'), target: '_blank', rel: 'noopener noreferrer')
= s_('ClusterIntegration|A %{link_to_container_project} must have been created under this account').html_safe % { link_to_container_project: link_to_container_project }
= s_('ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below').html_safe % { link_to_container_project: link_to_container_project }
- if commit.has_signature?
%button{ class: commit_signature_badge_classes('js-loading-gpg-badge'), data: { toggle: 'tooltip', placement: 'auto top', title: 'GPG signature (loading...)', 'commit-sha' => commit.sha } }
%a{ href: '#', tabindex: 0, class: commit_signature_badge_classes('js-loading-gpg-badge'), data: { toggle: 'tooltip', placement: 'auto top', title: 'GPG signature (loading...)', 'commit-sha' => commit.sha } }
......@@ -24,5 +24,5 @@
= link_to('Learn more about signing commits', help_page_path('user/project/repository/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link')
%button{ class: css_classes, data: { toggle: 'popover', html: 'true', placement: 'auto top', title: title, content: content } }
%a{ href: '#', tabindex: 0, class: css_classes, data: { toggle: 'popover', html: 'true', placement: 'auto top', title: title, content: content } }
= label
- expanded = Rails.env.test?
%section.settings
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Deploy Keys
......@@ -7,7 +7,7 @@
= expanded ? 'Collapse' : 'Expand'
%p
Deploy keys allow read-only or read-write (if enabled) access to your repository. Deploy keys can be used for CI, staging or production servers. You can create a deploy key or add an existing one.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
%h5.prepend-top-0
Create a new deploy key for this project
= render @deploy_keys.form_partial_path
......
......@@ -4,7 +4,7 @@
- expanded = Rails.env.test?
.project-edit-container
%section.settings.general-settings
%section.settings.general-settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
General project settings
......@@ -12,7 +12,7 @@
= expanded ? 'Collapse' : 'Expand'
%p
Update your project name, description, avatar, and other general settings.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
.project-edit-errors
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f|
%fieldset
......@@ -61,7 +61,7 @@
= link_to 'Remove avatar', project_avatar_path(@project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
= f.submit 'Save changes', class: "btn btn-save"
%section.settings.sharing-permissions
%section.settings.sharing-permissions.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Permissions
......@@ -69,13 +69,13 @@
= expanded ? 'Collapse' : 'Expand'
%p
Enable or disable certain project features and choose access levels.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "sharing-permissions-form" }, authenticity_token: true do |f|
%script.js-project-permissions-form-data{ type: "application/json" }= project_permissions_panel_data(@project)
.js-project-permissions-form
= f.submit 'Save changes', class: "btn btn-save"
%section.settings.merge-requests-feature{ class: ("hidden" if @project.project_feature.send(:merge_requests_access_level) == 0) }
%section.settings.merge-requests-feature.no-animate{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)] }
.settings-header
%h4
Merge request settings
......@@ -83,14 +83,14 @@
= expanded ? 'Collapse' : 'Expand'
%p
Customize your merge request restrictions.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "merge-request-settings-form" }, authenticity_token: true do |f|
= render 'merge_request_settings', form: f
= f.submit 'Save changes', class: "btn btn-save"
= render 'export', project: @project
%section.settings.advanced-settings
%section.settings.advanced-settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Advanced settings
......@@ -98,7 +98,7 @@
= expanded ? 'Collapse' : 'Expand'
%p
Perform advanced options such as housekeeping, archiving, renaming, transferring, or removing your project.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
.sub-section
%h4 Housekeeping
%p
......@@ -173,7 +173,10 @@
%p
This will remove the fork relationship to source project
= succeed "." do
= link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)
- if @project.fork_source
= link_to(fork_source_name(@project), project_path(@project.fork_source))
- else
= fork_source_name(@project)
= form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_project_path(@project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f|
%p
%strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
......
......@@ -24,7 +24,7 @@
%td
= truncate(hook_log.url, length: 50)
%td.light
#{number_with_precision(hook_log.execution_duration, precision: 2)} ms
#{number_with_precision(hook_log.execution_duration, precision: 2)} sec
%td.light
= time_ago_with_tooltip(hook_log.created_at)
%td
......
- expanded = Rails.env.test?
%section.settings
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Protected Branches
......@@ -8,7 +8,7 @@
= expanded ? 'Collapse' : 'Expand'
%p
Keep stable branches secure and force developers to use merge requests.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
%p
By default, protected branches are designed to:
%ul
......
- expanded = Rails.env.test?
%section.settings
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Protected Tags
......@@ -8,7 +8,7 @@
= expanded ? 'Collapse' : 'Expand'
%p
Limit access to creating and updating tags.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
%p
By default, protected tags are designed to:
%ul
......
......@@ -4,7 +4,7 @@
- expanded = Rails.env.test?
%section.settings#js-general-pipeline-settings
%section.settings#js-general-pipeline-settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
General pipelines settings
......@@ -12,10 +12,10 @@
= expanded ? 'Collapse' : 'Expand'
%p
Update your CI/CD configuration, like job timeout or Auto DevOps.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
= render 'projects/pipelines_settings/show'
%section.settings
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Runners settings
......@@ -23,10 +23,10 @@
= expanded ? 'Collapse' : 'Expand'
%p
Register and see your runners for this project.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
= render 'projects/runners/index'
%section.settings
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Secret variables
......@@ -35,10 +35,10 @@
= expanded ? 'Collapse' : 'Expand'
%p
= render "ci/variables/content"
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
= render 'ci/variables/index'
%section.settings
%section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
Pipeline triggers
......@@ -48,5 +48,5 @@
Triggers can force a specific branch or tag to get rebuilt with an API call. These tokens will
impersonate their associated user including their access to projects and their project
permissions.
.settings-content.no-animate{ class: ('expanded' if expanded) }
.settings-content
= render 'projects/triggers/index'
......@@ -11,7 +11,7 @@
= hook_log.trigger.singularize.titleize
%p
%strong Elapsed time:
#{number_with_precision(hook_log.execution_duration, precision: 2)} ms
#{number_with_precision(hook_log.execution_duration, precision: 2)} sec
%p
%strong Request time:
= time_ago_with_tooltip(hook_log.created_at)
......
---
title: Fix GPG signature popup info in Safari and Firefox
merge_request: 15228
author:
type: fixed
---
title: Fix webhooks recent deliveries
merge_request: 15146
author: Alexander Randa (@randaalex)
type: fixed
---
title: Fix issues with forked projects of which the source was deleted
merge_request: 15150
author:
type: fixed
---
title: Make sure group and project creation is blocked for new users that are external
by default
merge_request:
author:
type: fixed
---
title: Fix arguments Import/Export error importing project merge requests
merge_request:
author:
type: fixed
---
title: Fix diff parser so it tolerates to diff special markers in the content
merge_request:
author:
type: fixed
---
title: Fix a migration that adds merge_requests_ff_only_enabled column to MR table
merge_request:
author:
type: fixed
---
title: Render 404 when polling commit notes without having permissions
merge_request:
author:
type: fixed
---
title: Show error message when fast-forward merge is not possible
merge_request:
author:
type: fixed
---
title: Fix cancel button not working while uploading on the new issue page
merge_request: 15137
author:
type: fixed
---
title: Remove Filesystem check metrics that use too much CPU to handle requests
merge_request:
author:
type: performance
---
title: Avoid regenerating the ref path for the environment
merge_request:
author:
type: fixed
......@@ -58,8 +58,8 @@ en:
expired: "The access token expired"
unknown: "The access token is invalid"
scopes:
api: Access your API
read_user: Read user information
api: Access the authenticated user's API
read_user: Read the authenticated user's personal information
openid: Authenticate using OpenID Connect
sudo: Perform API actions as any user in the system (if the authenticated user is an admin)
scope_desc:
......
......@@ -8,7 +8,11 @@ class AddFastForwardOptionToProject < ActiveRecord::Migration
disable_ddl_transaction!
def up
add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false)
# We put condition here because of a mistake we made a couple of years ago
# see https://gitlab.com/gitlab-org/gitlab-ce/issues/39382#note_45716103
unless column_exists?(:projects, :merge_requests_ff_only_enabled)
add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false)
end
end
def down
......
......@@ -43,7 +43,7 @@ future GitLab releases.**
| **CI_COMMIT_TAG** | 9.0 | 0.5 | The commit tag name. Present only when building tags. |
| **CI_CONFIG_PATH** | 9.4 | 0.5 | The path to CI config file. Defaults to `.gitlab-ci.yml` |
| **CI_DEBUG_TRACE** | all | 1.7 | Whether [debug tracing](#debug-tracing) is enabled |
| **CI_DISPOSABLE_ENVIRONMENT** | all | 10.1 | Mark that job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except `shell` and `ssh`). If the environment is disposable, it is set to true, otherwise it is not defined at all. |
| **CI_DISPOSABLE_ENVIRONMENT** | all | 10.1 | Marks that the job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except `shell` and `ssh`). If the environment is disposable, it is set to true, otherwise it is not defined at all. |
| **CI_ENVIRONMENT_NAME** | 8.15 | all | The name of the environment for this job |
| **CI_ENVIRONMENT_SLUG** | 8.15 | all | A simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, etc. |
| **CI_ENVIRONMENT_URL** | 9.3 | all | The URL of the environment for this job |
......@@ -74,7 +74,7 @@ future GitLab releases.**
| **CI_SERVER_NAME** | all | all | The name of CI server that is used to coordinate jobs |
| **CI_SERVER_REVISION** | all | all | GitLab revision that is used to schedule jobs |
| **CI_SERVER_VERSION** | all | all | GitLab version that is used to schedule jobs |
| **CI_SHARED_ENVIRONMENT** | all | 10.1 | Mark that job is executed in a shared environment (something that is persisted across CI invocations like `shell` or `ssh` executor). If the environment is shared, it is set to true, otherwise it is not defined at all. |
| **CI_SHARED_ENVIRONMENT** | all | 10.1 | Marks that the job is executed in a shared environment (something that is persisted across CI invocations like `shell` or `ssh` executor). If the environment is shared, it is set to true, otherwise it is not defined at all. |
| **ARTIFACT_DOWNLOAD_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to download artifacts running a job |
| **GET_SOURCES_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to fetch sources running a job |
| **GITLAB_CI** | all | all | Mark that job is executed in GitLab CI environment |
......
......@@ -52,7 +52,8 @@ directly in the job artifacts browser without the need to download them.
>**Note:**
With [GitLab 10.1][ce-14399], HTML files in a public project can be previewed
directly in a new tab without the need to download them.
directly in a new tab without the need to download them when
[GitLab Pages](../../../administration/pages/index.md) is enabled
After a job finishes, if you visit the job's specific page, there are three
buttons. You can download the artifacts archive or browse its contents, whereas
......@@ -69,7 +70,8 @@ browse inside them.
Below you can see how browsing looks like. In this case we have browsed inside
the archive and at this point there is one directory, a couple files, and
one HTML file that you can view directly online (opens in a new tab).
one HTML file that you can view directly online when
[GitLab Pages](../../../administration/pages/index.md) is enabled (opens in a new tab).
![Job artifacts browser](img/job_artifacts_browser.png)
......
......@@ -17,7 +17,9 @@ module Gitlab
# without having to instantiate all the others that come after it.
Enumerator.new do |yielder|
@lines.each do |line|
next if filename?(line)
# We're expecting a filename parameter only in a meta-part of the diff content
# when type is defined then we're already in a content-part
next if filename?(line) && type.nil?
full_line = line.delete("\n")
......
......@@ -8,7 +8,7 @@ module Gitlab
def execute(pusher, repository, oldrev, newrev, ref)
@repository = repository
@gl_id = pusher.gl_id
@gl_username = pusher.name
@gl_username = pusher.username
@oldrev = oldrev
@newrev = newrev
@ref = ref
......
......@@ -26,7 +26,7 @@ module Gitlab
end
def fetch_ref
@project.repository.fetch_ref(@project.repository.path, @diff_head_sha, @merge_request.source_branch)
@project.repository.fetch_ref(@project.repository, source_ref: @diff_head_sha, target_ref: @merge_request.source_branch)
end
def branch_exists?(branch_name)
......
......@@ -375,7 +375,7 @@ msgstr ""
msgid "Clone repository"
msgstr ""
msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account"
msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below"
msgstr ""
msgid "ClusterIntegration|Cluster integration"
......@@ -447,7 +447,7 @@ msgstr ""
msgid "ClusterIntegration|Remove integration"
msgstr ""
msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project."
msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Container Engine."
msgstr ""
msgid "ClusterIntegration|Save changes"
......
require 'spec_helper'
describe LfsRequest do
include ProjectForksHelper
controller(Projects::GitHttpClientController) do
# `described_class` is not available in this context
include LfsRequest # rubocop:disable RSpec/DescribedClass
def show
storage_project
render nothing: true
end
def project
@project ||= Project.find(params[:id])
end
def download_request?
true
end
def ci?
false
end
end
let(:project) { create(:project, :public) }
before do
stub_lfs_setting(enabled: true)
end
describe '#storage_project' do
it 'assigns the project as storage project' do
get :show, id: project.id
expect(assigns(:storage_project)).to eq(project)
end
it 'assigns the source of a forked project' do
forked_project = fork_project(project)
get :show, id: forked_project.id
expect(assigns(:storage_project)).to eq(project)
end
end
end
......@@ -59,17 +59,6 @@ describe MetricsController do
expect(response.body).to match(/^redis_shared_state_ping_latency_seconds [0-9\.]+$/)
end
it 'returns file system check metrics' do
get :index
expect(response.body).to match(/^filesystem_access_latency_seconds{shard="default"} [0-9\.]+$/)
expect(response.body).to match(/^filesystem_accessible{shard="default"} 1$/)
expect(response.body).to match(/^filesystem_write_latency_seconds{shard="default"} [0-9\.]+$/)
expect(response.body).to match(/^filesystem_writable{shard="default"} 1$/)
expect(response.body).to match(/^filesystem_read_latency_seconds{shard="default"} [0-9\.]+$/)
expect(response.body).to match(/^filesystem_readable{shard="default"} 1$/)
end
context 'prometheus metrics are disabled' do
before do
allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(false)
......
......@@ -105,6 +105,19 @@ describe Projects::NotesController do
expect(note_json[:discussion_html]).to be_nil
expect(note_json[:diff_discussion_html]).to be_nil
end
context 'when user cannot read commit' do
before do
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user, :download_code, project).and_return(false)
end
it 'renders 404' do
get :index, params
expect(response).to have_gitlab_http_status(404)
end
end
end
end
......
......@@ -583,6 +583,16 @@ describe 'Issues' do
expect(page.find_field("issue_description").value).not_to match /\n\n$/
end
it "cancels a file upload correctly" do
dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false)
click_button 'Cancel'
expect(page).to have_button('Attach a file')
expect(page).not_to have_button('Cancel')
expect(page).not_to have_selector('.uploading-progress-container', visible: true)
end
end
context 'form filled by URL parameters' do
......
require 'spec_helper'
feature 'Settings for a forked project', :js do
include ProjectForksHelper
let(:user) { create(:user) }
let(:original_project) { create(:project) }
let(:forked_project) { fork_project(original_project, user) }
before do
original_project.add_master(user)
forked_project.add_master(user)
sign_in(user)
end
shared_examples 'project settings for a forked projects' do
it 'allows deleting the link to the forked project' do
visit edit_project_path(forked_project)
click_button 'Remove fork relationship'
wait_for_requests
fill_in('confirm_name_input', with: forked_project.name)
click_button('Confirm')
expect(page).to have_content('The fork relationship has been removed.')
expect(forked_project.reload.forked?).to be_falsy
end
end
it_behaves_like 'project settings for a forked projects'
context 'when the original project is deleted' do
before do
original_project.destroy!
end
it_behaves_like 'project settings for a forked projects'
end
end
......@@ -143,4 +143,21 @@ eos
it { expect(parser.parse([])).to eq([]) }
it { expect(parser.parse(nil)).to eq([]) }
end
describe 'tolerates special diff markers in a content' do
it "counts lines correctly" do
diff = <<~END
--- a/test
+++ b/test
@@ -1,2 +1,2 @@
+ipsum
+++ b
-ipsum
END
lines = parser.parse(diff.lines).to_a
expect(lines.size).to eq(3)
end
end
end
require 'spec_helper'
describe Gitlab::Git::HooksService, seed_helper: true do
let(:user) { Gitlab::Git::User.new('janedoe', 'Jane Doe', 'janedoe@example.com', 'user-456') }
let(:gl_id) { 'user-456' }
let(:gl_username) { 'janedoe' }
let(:user) { Gitlab::Git::User.new(gl_username, 'Jane Doe', 'janedoe@example.com', gl_id) }
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, 'project-123') }
let(:service) { described_class.new }
before do
@blankrev = Gitlab::Git::BLANK_SHA
@oldrev = SeedRepo::Commit::PARENT_ID
@newrev = SeedRepo::Commit::ID
@ref = 'refs/heads/feature'
end
let(:blankrev) { Gitlab::Git::BLANK_SHA }
let(:oldrev) { SeedRepo::Commit::PARENT_ID }
let(:newrev) { SeedRepo::Commit::ID }
let(:ref) { 'refs/heads/feature' }
describe '#execute' do
context 'when receive hooks were successful' do
it 'calls post-receive hook' do
hook = double(trigger: [true, nil])
let(:hook) { double(:hook) }
it 'calls all three hooks' do
expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
expect(hook).to receive(:trigger).with(gl_id, gl_username, blankrev, newrev, ref)
.exactly(3).times.and_return([true, nil])
service.execute(user, repository, @blankrev, @newrev, @ref) { }
service.execute(user, repository, blankrev, newrev, ref) { }
end
end
......@@ -28,7 +30,7 @@ describe Gitlab::Git::HooksService, seed_helper: true do
expect(service).not_to receive(:run_hook).with('post-receive')
expect do
service.execute(user, repository, @blankrev, @newrev, @ref)
service.execute(user, repository, blankrev, newrev, ref)
end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
end
end
......@@ -40,7 +42,7 @@ describe Gitlab::Git::HooksService, seed_helper: true do
expect(service).not_to receive(:run_hook).with('post-receive')
expect do
service.execute(user, repository, @blankrev, @newrev, @ref)
service.execute(user, repository, blankrev, newrev, ref)
end.to raise_error(Gitlab::Git::HooksService::PreReceiveError)
end
end
......
......@@ -13,7 +13,7 @@ describe Gitlab::ImportExport::MergeRequestParser do
let(:parsed_merge_request) do
described_class.new(project,
merge_request.diff_head_sha,
'abcd',
merge_request,
merge_request.as_json).parse!
end
......@@ -29,4 +29,14 @@ describe Gitlab::ImportExport::MergeRequestParser do
it 'has a target branch' do
expect(project.repository.branch_exists?(parsed_merge_request.target_branch)).to be true
end
it 'parses a MR that has no source branch' do
allow_any_instance_of(described_class).to receive(:branch_exists?).and_call_original
allow_any_instance_of(described_class).to receive(:branch_exists?).with(merge_request.source_branch).and_return(false)
allow_any_instance_of(described_class).to receive(:fork_merge_request?).and_return(true)
allow(Gitlab::GitalyClient).to receive(:migrate).and_call_original
allow(Gitlab::GitalyClient).to receive(:migrate).with(:fetch_ref).and_return([nil, 0])
expect(parsed_merge_request).to eq(merge_request)
end
end
......@@ -547,6 +547,15 @@ describe Environment do
expect(environment.slug).to eq(original_slug)
end
it "regenerates the slug if nil" do
environment = build(:environment, slug: nil)
new_slug = environment.slug
expect(new_slug).not_to be_nil
expect(environment.slug).to eq(new_slug)
end
end
describe '#generate_slug' do
......@@ -583,6 +592,12 @@ describe Environment do
it 'returns a path that uses the slug and does not have spaces' do
expect(environment.ref_path).to start_with('refs/environments/staging-review-1-')
end
it "doesn't change when the slug is nil initially" do
environment.slug = nil
expect(environment.ref_path).to eq(environment.ref_path)
end
end
describe '#external_url_for' do
......
......@@ -24,6 +24,16 @@ describe ForkNetwork do
end
end
describe '#merge_requests' do
it 'finds merge requests within the fork network' do
project = create(:project)
forked_project = fork_project(project)
merge_request = create(:merge_request, source_project: forked_project, target_project: project)
expect(project.fork_network.merge_requests).to include(merge_request)
end
end
context 'for a deleted project' do
it 'keeps the fork network' do
project = create(:project, :public)
......
......@@ -1907,6 +1907,20 @@ describe Project do
expect(forked_project.in_fork_network_of?(other_project)).to be_falsy
end
end
describe '#fork_source' do
let!(:second_fork) { fork_project(forked_project) }
it 'returns the direct source if it exists' do
expect(second_fork.fork_source).to eq(forked_project)
end
it 'returns the root of the fork network when the directs source was deleted' do
forked_project.destroy
expect(second_fork.fork_source).to eq(project)
end
end
end
describe '#pushes_since_gc' do
......
......@@ -797,14 +797,16 @@ describe User do
end
it "creates external user by default" do
user = build(:user)
user = create(:user)
expect(user.external).to be_truthy
expect(user.can_create_group).to be_falsey
expect(user.projects_limit).to be 0
end
describe 'with default overrides' do
it "creates a non-external user" do
user = build(:user, external: false)
user = create(:user, external: false)
expect(user.external).to be_falsey
end
......
......@@ -239,6 +239,28 @@ describe MergeRequests::MergeService do
expect(merge_request.merge_error).to include(error_message)
expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message))
end
context "when fast-forward merge is not allowed" do
before do
allow_any_instance_of(Repository).to receive(:ancestor?).and_return(nil)
end
%w(semi-linear ff).each do |merge_method|
it "logs and saves error if merge is #{merge_method} only" do
merge_method = 'rebase_merge' if merge_method == 'semi-linear'
merge_request.project.update(merge_method: merge_method)
error_message = 'Only fast-forward merge is allowed for your project. Please update your source branch'
allow(service).to receive(:execute_hooks)
service.execute(merge_request)
expect(merge_request).to be_open
expect(merge_request.merge_commit_sha).to be_nil
expect(merge_request.merge_error).to include(error_message)
expect(Rails.logger).to have_received(:error).with(a_string_matching(error_message))
end
end
end
end
end
end
......@@ -12,6 +12,9 @@ describe Projects::UnlinkForkService do
context 'with opened merge request on the source project' do
let(:merge_request) { create(:merge_request, source_project: forked_project, target_project: fork_link.forked_from_project) }
let(:merge_request2) { create(:merge_request, source_project: forked_project, target_project: fork_project(project)) }
let(:merge_request_in_fork) { create(:merge_request, source_project: forked_project, target_project: forked_project) }
let(:mr_close_service) { MergeRequests::CloseService.new(forked_project, user) }
before do
......@@ -22,9 +25,14 @@ describe Projects::UnlinkForkService do
it 'close all pending merge requests' do
expect(mr_close_service).to receive(:execute).with(merge_request)
expect(mr_close_service).to receive(:execute).with(merge_request2)
subject.execute
end
it 'does not close merge requests for the project being unlinked' do
expect(mr_close_service).not_to receive(:execute).with(merge_request_in_fork)
end
end
it 'remove fork relation' do
......@@ -53,4 +61,14 @@ describe Projects::UnlinkForkService do
expect(source.forks_count).to be_zero
end
context 'when the original project was deleted' do
it 'does not fail when the original project is deleted' do
source = forked_project.forked_from_project
source.destroy
forked_project.reload
expect { subject.execute }.not_to raise_error
end
end
end
......@@ -38,6 +38,10 @@ module StubConfiguration
allow(Gitlab.config.backup).to receive_messages(to_settings(messages))
end
def stub_lfs_setting(messages)
allow(Gitlab.config.lfs).to receive_messages(to_settings(messages))
end
def stub_storage_settings(messages)
# Default storage is always required
messages['default'] ||= Gitlab.config.repositories.storages.default
......
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