Commit 72e1b55a authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 286d52531115
......@@ -113,13 +113,21 @@ schedule:review-build-cng:
- install_api_client_dependencies_with_apk
- source scripts/review_apps/review-apps.sh
script:
- date
- check_kube_domain
- date
- ensure_namespace
- date
- install_tiller
- date
- install_external_dns
- date
- download_chart
- date
- deploy || (display_deployment_debug && exit 1)
- date
- add_license
- date
artifacts:
paths: [review_app_url.txt]
expire_in: 2 days
......
......@@ -95,7 +95,7 @@ GEM
babosa (1.0.2)
base32 (0.3.2)
batch-loader (1.4.0)
bcrypt (3.1.12)
bcrypt (3.1.13)
bcrypt_pbkdf (1.0.0)
benchmark-ips (2.3.0)
benchmark-memory (0.1.2)
......@@ -209,10 +209,10 @@ GEM
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
device_detector (1.0.0)
devise (4.6.2)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 6.0)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise-two-factor (3.0.0)
......@@ -488,7 +488,7 @@ GEM
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.6.0)
i18n (1.7.0)
concurrent-ruby (~> 1.0)
i18n_data (0.8.0)
icalendar (2.4.1)
......@@ -770,8 +770,8 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.2.0)
loofah (~> 2.2, >= 2.2.2)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
rails-i18n (5.1.1)
i18n (>= 0.7, < 2)
railties (>= 5.0, < 6)
......@@ -824,9 +824,9 @@ GEM
declarative-option (< 0.2.0)
uber (< 0.2.0)
request_store (1.3.1)
responders (2.4.0)
actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3)
responders (2.4.1)
actionpack (>= 4.2.0, < 6.0)
railties (>= 4.2.0, < 6.0)
rest-client (2.0.2)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
......@@ -1058,8 +1058,8 @@ GEM
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
vmstat (2.3.0)
warden (1.2.7)
rack (>= 1.0)
warden (1.2.8)
rack (>= 2.0.6)
webfinger (1.1.0)
activesupport
httpclient (>= 2.4)
......
......@@ -7,10 +7,10 @@ import { __ } from '~/locale';
export default {
fields: [
{ key: 'error', label: __('Open errors') },
{ key: 'error', label: __('Open errors'), thClass: 'w-70p' },
{ key: 'events', label: __('Events') },
{ key: 'users', label: __('Users') },
{ key: 'lastSeen', label: __('Last seen') },
{ key: 'lastSeen', label: __('Last seen'), thClass: 'w-15p' },
],
components: {
GlEmptyState,
......@@ -67,40 +67,39 @@ export default {
<div class="d-flex justify-content-end">
<gl-button class="my-3 ml-auto" variant="primary" :href="externalUrl" target="_blank">
{{ __('View in Sentry') }}
<icon name="external-link" />
<icon name="external-link" class="flex-shrink-0" />
</gl-button>
</div>
<gl-table :items="errors" :fields="$options.fields" :show-empty="true">
<gl-table :items="errors" :fields="$options.fields" :show-empty="true" fixed stacked="sm">
<template slot="HEAD_events" slot-scope="data">
<div class="text-right">{{ data.label }}</div>
<div class="text-md-right">{{ data.label }}</div>
</template>
<template slot="HEAD_users" slot-scope="data">
<div class="text-right">{{ data.label }}</div>
<div class="text-md-right">{{ data.label }}</div>
</template>
<template slot="error" slot-scope="errors">
<div class="d-flex flex-column">
<div class="d-flex">
<gl-link :href="errors.item.externalUrl" class="d-flex text-dark" target="_blank">
<strong>{{ errors.item.title.trim() }}</strong>
<icon name="external-link" class="ml-1" />
</gl-link>
<span class="text-secondary ml-2">{{ errors.item.culprit }}</span>
</div>
{{ errors.item.message || __('No details available') }}
<gl-link :href="errors.item.externalUrl" class="d-flex text-dark" target="_blank">
<strong class="text-truncate">{{ errors.item.title.trim() }}</strong>
<icon name="external-link" class="ml-1 flex-shrink-0" />
</gl-link>
<span class="text-secondary text-truncate">
{{ errors.item.culprit }}
</span>
</div>
</template>
<template slot="events" slot-scope="errors">
<div class="text-right">{{ errors.item.count }}</div>
<div class="text-md-right">{{ errors.item.count }}</div>
</template>
<template slot="users" slot-scope="errors">
<div class="text-right">{{ errors.item.userCount }}</div>
<div class="text-md-right">{{ errors.item.userCount }}</div>
</template>
<template slot="lastSeen" slot-scope="errors">
<div class="d-flex align-items-center">
<icon name="calendar" class="text-secondary mr-1" />
<time-ago :time="errors.item.lastSeen" class="text-secondary" />
</div>
</template>
......
......@@ -32,6 +32,7 @@ export default class LabelsSelect {
$selectbox,
$sidebarCollapsedValue,
$value,
$dropdownMenu,
abilityName,
defaultLabel,
issueUpdateURL,
......@@ -67,6 +68,7 @@ export default class LabelsSelect {
$sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span');
$sidebarLabelTooltip = $block.find('.js-sidebar-labels-tooltip');
$value = $block.find('.value');
$dropdownMenu = $dropdown.parent().find('.dropdown-menu');
$loading = $block.find('.block-loading').fadeOut();
fieldName = $dropdown.data('fieldName');
initialSelected = $selectbox
......@@ -454,9 +456,21 @@ export default class LabelsSelect {
}
$loading.fadeIn();
const oldLabels = boardsStore.detail.issue.labels;
boardsStore.detail.issue
.update($dropdown.attr('data-issue-update'))
.then(() => {
if (isScopedLabel(label)) {
const prevIds = oldLabels.map(label => label.id);
const newIds = boardsStore.detail.issue.labels.map(label => label.id);
const differentIds = _.difference(prevIds, newIds);
$dropdown.data('marked', newIds);
$dropdownMenu
.find(differentIds.map(id => `[data-label-id="${id}"]`).join(','))
.removeClass('is-active');
}
})
.then(fadeOutLoader)
.catch(fadeOutLoader);
} else if (handleClick) {
......
import { __ } from '~/locale';
export default () => {
const { protocol, host, pathname } = window.location;
const shareBtn = document.querySelector('.js-share-btn');
const embedBtn = document.querySelector('.js-embed-btn');
const snippetUrlArea = document.querySelector('.js-snippet-url-area');
const embedAction = document.querySelector('.js-embed-action');
const url = `${protocol}//${host + pathname}`;
shareBtn.addEventListener('click', () => {
shareBtn.classList.add('is-active');
embedBtn.classList.remove('is-active');
snippetUrlArea.value = url;
embedAction.innerText = __('Share');
});
if (shareBtn) {
const { protocol, host, pathname } = window.location;
embedBtn.addEventListener('click', () => {
embedBtn.classList.add('is-active');
shareBtn.classList.remove('is-active');
const scriptTag = `<script src="${url}.js"></script>`;
snippetUrlArea.value = scriptTag;
embedAction.innerText = __('Embed');
});
const embedBtn = document.querySelector('.js-embed-btn');
const snippetUrlArea = document.querySelector('.js-snippet-url-area');
const embedAction = document.querySelector('.js-embed-action');
const url = `${protocol}//${host + pathname}`;
shareBtn.addEventListener('click', () => {
shareBtn.classList.add('is-active');
embedBtn.classList.remove('is-active');
snippetUrlArea.value = url;
embedAction.innerText = __('Share');
});
embedBtn.addEventListener('click', () => {
embedBtn.classList.add('is-active');
shareBtn.classList.remove('is-active');
const scriptTag = `<script src="${url}.js"></script>`;
snippetUrlArea.value = scriptTag;
embedAction.innerText = __('Embed');
});
}
};
......@@ -452,6 +452,8 @@ img.emoji {
.w-0 { width: 0; }
.w-8em { width: 8em; }
.w-3rem { width: 3rem; }
.w-15p { width: 15%; }
.w-70p { width: 70%; }
.h-12em { height: 12em; }
.h-32-px { height: 32px;}
......
......@@ -29,13 +29,15 @@ def create
def show
return render_404 unless uploader&.exists?
if cache_publicly?
# We need to reset caching from the applications controller to get rid of the no-store value
headers['Cache-Control'] = ''
expires_in 5.minutes, public: true, must_revalidate: false
else
expires_in 0.seconds, must_revalidate: true, private: true
end
# We need to reset caching from the applications controller to get rid of the no-store value
headers['Cache-Control'] = ''
headers['Pragma'] = ''
ttl, directives = *cache_settings
ttl ||= 6.months
directives ||= { private: true, must_revalidate: true }
expires_in ttl, directives
disposition = uploader.embeddable? ? 'inline' : 'attachment'
......@@ -120,8 +122,8 @@ def find_model
nil
end
def cache_publicly?
false
def cache_settings
[]
end
def model
......
......@@ -5,11 +5,22 @@ module Settings
class CiCdController < Groups::ApplicationController
skip_cross_project_access_check :show
before_action :authorize_admin_group!
before_action :authorize_update_max_artifacts_size!, only: [:update]
def show
define_ci_variables
end
def update
if update_group_service.execute
flash[:notice] = s_('GroupSettings|Pipeline settings was updated for the group')
else
flash[:alert] = s_("GroupSettings|There was a problem updating the pipeline settings: %{error_messages}." % { error_messages: group.errors.full_messages })
end
redirect_to group_settings_ci_cd_path
end
def reset_registration_token
@group.reset_runners_token!
......@@ -40,6 +51,10 @@ def authorize_admin_group!
return render_404 unless can?(current_user, :admin_group, group)
end
def authorize_update_max_artifacts_size!
return render_404 unless can?(current_user, :update_max_artifacts_size, group)
end
def auto_devops_params
params.require(:group).permit(:auto_devops_enabled)
end
......@@ -47,6 +62,14 @@ def auto_devops_params
def auto_devops_service
Groups::AutoDevopsService.new(group, current_user, auto_devops_params)
end
def update_group_service
Groups::UpdateService.new(group, current_user, update_group_params)
end
def update_group_params
params.require(:group).permit(:max_artifacts_size)
end
end
end
end
......@@ -46,13 +46,19 @@ def reset_registration_token
private
def update_params
params.require(:project).permit(
params.require(:project).permit(*permitted_project_params)
end
def permitted_project_params
[
:runners_token, :builds_enabled, :build_allow_git_fetch,
:build_timeout_human_readable, :build_coverage_regex, :public_builds,
:auto_cancel_pending_pipelines, :ci_config_path,
auto_devops_attributes: [:id, :domain, :enabled, :deploy_strategy],
ci_cd_settings_attributes: [:default_git_depth]
)
].tap do |list|
list << :max_artifacts_size if can?(current_user, :update_max_artifacts_size, project)
end
end
def run_autodevops_pipeline(service)
......
......@@ -81,8 +81,13 @@ def render_unauthorized
end
end
def cache_publicly?
User === model || Appearance === model
def cache_settings
case model
when User, Appearance
[5.minutes, { public: true, must_revalidate: false }]
when Project, Group
[5.minutes, { private: true, must_revalidate: true }]
end
end
def secret?
......
......@@ -53,7 +53,10 @@ class GroupPolicy < BasePolicy
enable :upload_file
end
rule { admin }.enable :read_group
rule { admin }.policy do
enable :read_group
enable :update_max_artifacts_size
end
rule { has_projects }.policy do
enable :read_group
......
......@@ -137,6 +137,8 @@ class ProjectPolicy < BasePolicy
# not.
rule { guest | admin }.enable :read_project_for_iids
rule { admin }.enable :update_max_artifacts_size
rule { guest }.enable :guest_access
rule { reporter }.enable :reporter_access
rule { developer }.enable :developer_access
......
......@@ -34,7 +34,7 @@
= f.number_field :max_artifacts_size, class: 'form-control'
.form-text.text-muted
= _("Set the maximum file size for each job's artifacts")
= link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size')
= link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size-core-only')
.form-group
= f.label :default_artifacts_expire_in, _('Default artifacts expiration'), class: 'label-bold'
= f.text_field :default_artifacts_expire_in, class: 'form-control'
......
......@@ -30,6 +30,6 @@
= f.check_box :lets_encrypt_terms_of_service_accepted, class: 'form-check-input'
= f.label :lets_encrypt_terms_of_service_accepted, class: 'form-check-label' do
- terms_of_service_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: lets_encrypt_terms_of_service_admin_application_settings_path }
= _("I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end}").html_safe % { link_start: terms_of_service_link_start, link_end: '</a>'.html_safe }
= _("I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)").html_safe % { link_start: terms_of_service_link_start, link_end: '</a>'.html_safe }
= f.submit _('Save changes'), class: "btn btn-success"
.row.prepend-top-default
.col-lg-12
= form_for group, url: group_settings_ci_cd_path(group, anchor: 'js-general-pipeline-settings') do |f|
= form_errors(group)
%fieldset.builds-feature
.form-group
= f.label :max_artifacts_size, _('Maximum artifacts size (MB)'), class: 'label-bold'
= f.number_field :max_artifacts_size, class: 'form-control'
%p.form-text.text-muted
= _("Set the maximum file size for each job's artifacts")
= link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size-core-only'), target: '_blank'
= f.submit _('Save changes'), class: "btn btn-success"
......@@ -2,6 +2,21 @@
- page_title "CI / CD"
- expanded = expanded_by_default?
- general_expanded = @group.errors.empty? ? expanded : true
-# Given we only have one field in this form which is also admin-only,
-# we don't want to show an empty section to non-admin users,
- if can?(current_user, :update_max_artifacts_size, @group)
%section.settings#js-general-pipeline-settings.no-animate{ class: ('expanded' if general_expanded) }
.settings-header
%h4
= _("General pipelines")
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= _("Customize your pipeline configuration.")
.settings-content
= render 'groups/settings/ci_cd/form', group: @group
%section.settings#ci-variables.no-animate{ class: ('expanded' if expanded) }
.settings-header
......
......@@ -40,6 +40,15 @@
= _('If any job surpasses this timeout threshold, it will be marked as failed. Human readable time input language is accepted like "1 hour". Values without specification represent seconds.')
= link_to icon('question-circle'), help_page_path('user/project/pipelines/settings', anchor: 'timeout'), target: '_blank'
- if can?(current_user, :update_max_artifacts_size, @project)
%hr
.form-group
= f.label :max_artifacts_size, _('Maximum artifacts size (MB)'), class: 'label-bold'
= f.number_field :max_artifacts_size, class: 'form-control'
%p.form-text.text-muted
= _("Set the maximum file size for each job's artifacts")
= link_to icon('question-circle'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size-core-only'), target: '_blank'
%hr
.form-group
= f.label :ci_config_path, _('Custom CI config path'), class: 'label-bold'
......
# frozen_string_literal: false
# frozen_string_literal: true
class MigrateExternalDiffsWorker
include ApplicationWorker
......
# frozen_string_literal: false
# frozen_string_literal: true
class ScheduleMigrateExternalDiffsWorker
include ApplicationWorker
......
# frozen_string_literal: true
# Worker for updating project statistics.
......
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