Commit fd062a94 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 94559972834f
<script>
import { GlToggle, GlFormGroup, GlFormTextarea, GlButton } from '@gitlab/ui';
export default {
name: 'MaintenanceModeSettingsApp',
components: {
GlToggle,
GlFormGroup,
GlFormTextarea,
GlButton,
},
data() {
return {
inMaintenanceMode: false,
bannerMessage: '',
};
},
};
</script>
<template>
<article>
<div class="d-flex align-items-center mb-3">
<gl-toggle v-model="inMaintenanceMode" class="mb-0" />
<div class="ml-2">
<p class="mb-0">{{ __('Enable maintenance mode') }}</p>
<p class="mb-0 text-secondary-500">
{{
__('Non-admin users can sign in with read-only access and make read-only API requests.')
}}
</p>
</div>
</div>
<gl-form-group label="Banner Message" label-for="maintenanceBannerMessage">
<gl-form-textarea
id="maintenanceBannerMessage"
v-model="bannerMessage"
:placeholder="__(`GitLab is undergoing maintenance and is operating in a read-only mode.`)"
/>
</gl-form-group>
<div class="mt-4">
<gl-button variant="success">{{ __('Save changes') }}</gl-button>
</div>
</article>
</template>
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import MaintenanceModeSettingsApp from './components/app.vue';
Vue.use(Translate);
export default () => {
const el = document.getElementById('js-maintenance-mode-settings');
return new Vue({
el,
components: {
MaintenanceModeSettingsApp,
},
render(createElement) {
return createElement('maintenance-mode-settings-app');
},
});
};
import initSettingsPanels from '~/settings_panels';
import projectSelect from '~/project_select';
import selfMonitor from '~/self_monitor';
import maintenanceModeSettings from '~/maintenance_mode_settings';
document.addEventListener('DOMContentLoaded', () => {
selfMonitor();
maintenanceModeSettings();
// Initialize expandable settings panels
initSettingsPanels();
projectSelect();
......
......@@ -37,7 +37,8 @@ export default {
text() {
return sprintf(
s__(`Labels|Promoting %{labelTitle} will make it available for all projects inside %{groupName}.
Existing project labels with the same title will be merged. This action cannot be reversed.`),
Existing project labels with the same title will be merged. If a group label with the same title exists,
it will also be merged. This action cannot be reversed.`),
{
labelTitle: this.labelTitle,
groupName: this.groupName,
......
......@@ -483,6 +483,34 @@ img.emoji {
}
/** COMMON SPACING CLASSES **/
/**
🚨 Do not use these classes — they are deprecated and being removed. 🚨
See https://gitlab.com/gitlab-org/gitlab/issues/36857 for more details.
Instead, if you need a spacing class, add it below using the following values.
$gl-spacing-scale-0: 0;
$gl-spacing-scale-1: 2px;
$gl-spacing-scale-2: 4px;
$gl-spacing-scale-3: 8px;
$gl-spacing-scale-4: 12px;
$gl-spacing-scale-5: 16px;
$gl-spacing-scale-6: 24px;
$gl-spacing-scale-7: 32px;
$gl-spacing-scale-8: 40px;
$gl-spacing-scale-9: 48px;
$gl-spacing-scale-10: 56px;
$gl-spacing-scale-11: 64px;
$gl-spacing-scale-12: 80px;
$gl-spacing-scale-13: 96px;
E.g., a padding top of 96px can be added using:
.gl-shim-pt-13 {
padding-top: 96px;
}
Please use -shim- so it can be differentiated from the old scale classes.
These will be replaced when the Gitlab UI utilities are included.
**/
@each $index, $padding in $spacing-scale {
#{'.gl-p-#{$index}'} { padding: $padding; }
#{'.gl-pl-#{$index}'} { padding-left: $padding; }
......@@ -583,13 +611,11 @@ img.emoji {
.gl-font-size-large { font-size: $gl-font-size-large; }
.gl-line-height-24 { line-height: $gl-line-height-24; }
.gl-line-height-14 { line-height: $gl-line-height-14; }
.gl-font-size-0 { font-size: 0; }
.gl-font-size-12 { font-size: $gl-font-size-12; }
.gl-font-size-14 { font-size: $gl-font-size-14; }
.gl-font-size-16 { font-size: $gl-font-size-16; }
.gl-font-size-20 { font-size: $gl-font-size-20; }
.gl-font-size-28 { font-size: $gl-font-size-28; }
.gl-font-size-42 { font-size: $gl-font-size-42; }
......@@ -599,3 +625,10 @@ img.emoji {
border-top: 1px solid $border-color;
}
/**
🚨 Do not use these classes — they clash with the Gitlab UI design system and will be removed. 🚨
See https://gitlab.com/gitlab-org/gitlab/issues/36857 for more details.
**/
.gl-line-height-14 { line-height: $gl-line-height-14; }
.gl-font-size-20 { font-size: $gl-font-size-20; }
......@@ -11,6 +11,38 @@ $default-transition-duration: 0.15s;
$contextual-sidebar-width: 220px;
$contextual-sidebar-collapsed-width: 50px;
$toggle-sidebar-height: 48px;
/**
🚨 Do not use this spacing scale — it is deprecated and being removed. 🚨
See https://gitlab.com/gitlab-org/gitlab/issues/36857 for more details.
Instead, if you need a spacing class, add it to app/assets/stylesheets/framework/common.scss,
using the following values.
$gl-spacing-scale-0: 0;
$gl-spacing-scale-1: 2px;
$gl-spacing-scale-2: 4px;
$gl-spacing-scale-3: 8px;
$gl-spacing-scale-4: 12px;
$gl-spacing-scale-5: 16px;
$gl-spacing-scale-6: 24px;
$gl-spacing-scale-7: 32px;
$gl-spacing-scale-8: 40px;
$gl-spacing-scale-9: 48px;
$gl-spacing-scale-10: 56px;
$gl-spacing-scale-11: 64px;
$gl-spacing-scale-12: 80px;
$gl-spacing-scale-13: 96px;
E.g., a padding top of 96px can be added using:
.gl-shim-pt-13 {
padding-top: 96px;
}
Please use -shim- so it can be differentiated from the old scale classes.
These will be replaced when the Gitlab UI utilities are included.
**/
$spacing-scale: (
0: 0,
1: #{0.5 * $grid-size},
......
......@@ -67,7 +67,8 @@
.gl-bg-purple-light { background-color: $purple-light; }
// Classes using mixins coming from @gitlab-ui
// can be removed once https://gitlab.com/gitlab-org/gitlab/merge_requests/19021 has been merged
// can be removed once the mixins are added.
// See https://gitlab.com/gitlab-org/gitlab/issues/36857 for more details.
.gl-bg-blue-50 { @include gl-bg-blue-50; }
.gl-bg-red-100 { @include gl-bg-red-100; }
.gl-bg-orange-100 { @include gl-bg-orange-100; }
......
......@@ -8,16 +8,16 @@ module SendsBlob
include SendFileUpload
end
def send_blob(repository, blob, params = {})
def send_blob(repository, blob, inline: true, allow_caching: false)
if blob
headers['X-Content-Type-Options'] = 'nosniff'
return if cached_blob?(blob)
return if cached_blob?(blob, allow_caching: allow_caching)
if blob.stored_externally?
send_lfs_object(blob)
send_lfs_object(blob, repository.project)
else
send_git_blob(repository, blob, params)
send_git_blob(repository, blob, inline: inline)
end
else
render_404
......@@ -26,11 +26,11 @@ def send_blob(repository, blob, params = {})
private
def cached_blob?(blob)
def cached_blob?(blob, allow_caching: false)
stale = stale?(etag: blob.id) # The #stale? method sets cache headers.
# Because we are opinionated we set the cache headers ourselves.
response.cache_control[:public] = project.public?
response.cache_control[:public] = allow_caching
response.cache_control[:max_age] =
if @ref && @commit && @ref == @commit.id # rubocop:disable Gitlab/ModuleWithInstanceVariables
......@@ -48,7 +48,7 @@ def cached_blob?(blob)
!stale
end
def send_lfs_object(blob)
def send_lfs_object(blob, project)
lfs_object = find_lfs_object(blob)
if lfs_object && lfs_object.project_allowed_access?(project)
......
......@@ -2,6 +2,7 @@
module SnippetsActions
extend ActiveSupport::Concern
include SendsBlob
def edit
# We need to load some info from the existing blob
......@@ -12,16 +13,26 @@ def edit
end
def raw
disposition = params[:inline] == 'false' ? 'attachment' : 'inline'
workhorse_set_content_type!
send_data(
convert_line_endings(blob.data),
type: 'text/plain; charset=utf-8',
disposition: disposition,
filename: Snippet.sanitized_file_name(blob.name)
)
# Until we don't migrate all snippets to version
# snippets we need to support old `SnippetBlob`
# blobs
if defined?(blob.snippet)
send_data(
convert_line_endings(blob.data),
type: 'text/plain; charset=utf-8',
disposition: content_disposition,
filename: Snippet.sanitized_file_name(blob.name)
)
else
send_blob(
snippet.repository,
blob,
inline: content_disposition == 'inline',
allow_caching: snippet.public?
)
end
end
def js_request?
......@@ -30,6 +41,10 @@ def js_request?
private
def content_disposition
@disposition ||= params[:inline] == 'false' ? 'attachment' : 'inline'
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def blob
return unless snippet
......
......@@ -8,7 +8,7 @@ class Projects::AvatarsController < Projects::ApplicationController
def show
@blob = @repository.blob_at_branch(@repository.root_ref, @project.avatar_in_git)
send_blob(@repository, @blob)
send_blob(@repository, @blob, allow_caching: @project.public?)
end
def destroy
......
......@@ -16,9 +16,8 @@ def show
end
def import
import_state = @project.import_state || @project.create_import_state
schedule_import(jira_import_params) unless import_state.in_progress?
response = ::JiraImport::StartImportService.new(current_user, @project, jira_import_params[:jira_project_key]).execute
flash[:notice] = response.message if response.message.present?
redirect_to project_import_jira_path(@project)
end
......@@ -39,21 +38,6 @@ def jira_integration_configured?
redirect_to project_issues_path(@project)
end
def schedule_import(params)
import_data = @project.create_or_update_import_data(data: {}).becomes(JiraImportData)
jira_project_details = JiraImportData::JiraProjectDetails.new(
params[:jira_project_key],
Time.now.strftime('%Y-%m-%d %H:%M:%S'),
{ user_id: current_user.id, name: current_user.name }
)
import_data << jira_project_details
import_data.force_import!
@project.import_type = 'jira'
@project.import_state.schedule if @project.save
end
def jira_import_params
params.permit(:jira_project_key)
end
......
......@@ -17,7 +17,7 @@ class Projects::RawController < Projects::ApplicationController
def show
@blob = @repository.blob_at(@commit.id, @path)
send_blob(@repository, @blob, inline: (params[:inline] != 'false'))
send_blob(@repository, @blob, inline: (params[:inline] != 'false'), allow_caching: @project.public?)
end
private
......
......@@ -45,7 +45,7 @@ def show
render 'show'
elsif file_blob
send_blob(@project_wiki.repository, file_blob)
send_blob(@project_wiki.repository, file_blob, allow_caching: @project.public?)
elsif show_create_form?
# Assign a title to the WikiPage unless `id` is a randomly generated slug from #new
title = params[:id] unless params[:random_title].present?
......
......@@ -51,6 +51,9 @@ class NoteType < BaseObject
description: "Timestamp of the note's resolution"
field :position, Types::Notes::DiffPositionType, null: true,
description: 'The position of this note on a diff'
field :confidential, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates if this note is confidential',
method: :confidential?
end
end
end
......@@ -70,6 +70,16 @@ class Runner < ApplicationRecord
joins(:runner_projects).where(ci_runner_projects: { project_id: project_id })
}
scope :belonging_to_group, -> (group_id, include_ancestors: false) {
groups = ::Group.where(id: group_id)
if include_ancestors
groups = Gitlab::ObjectHierarchy.new(groups).base_and_ancestors
end
joins(:runner_namespaces).where(ci_runner_namespaces: { namespace_id: groups })
}
scope :belonging_to_parent_group_of_project, -> (project_id) {
project_groups = ::Group.joins(:projects).where(projects: { id: project_id })
hierarchy_groups = Gitlab::ObjectHierarchy.new(project_groups).base_and_ancestors
......
......@@ -48,6 +48,7 @@ class DiscussionEntity < Grape::Entity
expose :for_commit?, as: :for_commit
expose :commit_id
expose :confidential?, as: :confidential
private
......
# frozen_string_literal: true
module JiraImport
class StartImportService
attr_reader :user, :project, :jira_project_key
def initialize(user, project, jira_project_key)
@user = user
@project = project
@jira_project_key = jira_project_key
end
def execute
validation_response = validate
return validation_response if validation_response&.error?
create_and_schedule_import
end
private
def create_and_schedule_import
import_data = project.create_or_update_import_data(data: {}).becomes(JiraImportData)
jira_project_details = JiraImportData::JiraProjectDetails.new(
jira_project_key,
Time.now.strftime('%Y-%m-%d %H:%M:%S'),
{ user_id: user.id, name: user.name }
)
import_data << jira_project_details
import_data.force_import!
project.import_type = 'jira'
project.import_state.schedule if project.save!
ServiceResponse.success(payload: { import_data: import_data } )
rescue => ex
# in case project.save! raises an erorr
Gitlab::ErrorTracking.track_exception(ex, project_id: project.id)
build_error_response(ex.message)
end
def validate
return build_error_response(_('Jira import feature is disabled.')) unless Feature.enabled?(:jira_issue_import, project)
return build_error_response(_('You do not have permissions to run the import.')) unless user.can?(:admin_project, project)
return build_error_response(_('Jira integration not configured.')) unless project.jira_service&.active?
return build_error_response(_('Unable to find Jira project to import data from.')) if jira_project_key.blank?
return build_error_response(_('Jira import is already running.')) if import_in_progress?
end
def build_error_response(message)
import_data = JiraImportData.new(project: project)
import_data.errors.add(:base, message)
ServiceResponse.error(
message: import_data.errors.full_messages.to_sentence,
http_status: 400,
payload: { import_data: import_data }
)
end
def import_in_progress?
import_state = project.import_state || project.create_import_state
import_state.in_progress?
end
end
end
......@@ -36,8 +36,8 @@ def execute
when 'valid'
save_certificate(acme_order.private_key, api_order)
acme_order.destroy!
# when 'invalid'
# TODO: implement error handling
when 'invalid'
save_order_error(acme_order, api_order)
end
end
......@@ -47,5 +47,28 @@ def save_certificate(private_key, api_order)
certificate = api_order.certificate
pages_domain.update!(gitlab_provided_key: private_key, gitlab_provided_certificate: certificate)
end
def save_order_error(acme_order, api_order)
log_error(api_order)
return unless Feature.enabled?(:pages_letsencrypt_errors, pages_domain.project)
pages_domain.assign_attributes(auto_ssl_failed: true)
pages_domain.save!(validate: false)
acme_order.destroy!
end
def log_error(api_order)
Gitlab::AppLogger.error(
message: "Failed to obtain Let's Encrypt certificate",
acme_error: api_order.challenge_error,
project_id: pages_domain.project_id,
pages_domain: pages_domain.domain
)
rescue => e
# getting authorizations is an additional network request which can raise errors
Gitlab::ErrorTracking.track_exception(e)
end
end
end
......@@ -104,6 +104,18 @@
= f.submit _('Save changes'), class: "btn btn-success"
- if Feature.enabled?(:maintenance_mode)
%section.settings.no-animate#js-maintenance-mode-toggle{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Maintenance mode')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Prevent users from performing write operations on GitLab while performing maintenance.')
.settings-content
#js-maintenance-mode-settings
- if Feature.enabled?(:instance_level_integrations)
= render_if_exists 'admin/application_settings/elasticsearch_form'
= render 'admin/application_settings/plantuml'
......
......@@ -10,6 +10,11 @@ def perform
return unless ::Gitlab::LetsEncrypt.enabled?
PagesDomain.need_auto_ssl_renewal.with_logging_info.find_each do |domain|
# Ideally that should be handled in PagesDomain.need_auto_ssl_renewal scope
# but it's hard to make scope work with feature flags
# once we remove feature flag we can modify scope to implement this behaviour
next if Feature.enabled?(:pages_letsencrypt_errors, domain.project) && domain.auto_ssl_failed
with_context(project: domain.project) do
PagesDomainSslRenewalWorker.perform_async(domain.id)
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