This instance will be upgraded to Heptapod 0.26.0rc1 on 2021-10-26 at 14:30 UTC+2 (a few minutes of down time)

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

Add latest changes from gitlab-org/gitlab@master

parent 066a351ee5e2
......@@ -24,7 +24,8 @@
- apk add --update openssl
- wget $CI_PROJECT_URL/raw/$CI_COMMIT_SHA/scripts/trigger-build-docs
- chmod 755 trigger-build-docs
- gem install gitlab --no-document
- gem install httparty --no-document --version 0.17.3
- gem install gitlab --no-document --version 4.13.0
# Always trigger a docs build in gitlab-docs only on docs-only branches.
# Useful to preview the docs changes live.
......
......@@ -244,7 +244,9 @@ webpack-dev-server:
dependencies: ["setup-test-env", "compile-assets pull-cache"]
variables:
WEBPACK_MEMORY_TEST: "true"
WEBPACK_VENDOR_DLL: "true"
script:
- yarn webpack-vendor
- node --expose-gc node_modules/.bin/webpack-dev-server --config config/webpack.config.js
artifacts:
name: webpack-dev-server
......
......@@ -102,7 +102,7 @@ gem 'hashie-forbidden_attributes'
gem 'kaminari', '~> 1.0'
# HAML
gem 'hamlit', '~> 2.10.0'
gem 'hamlit', '~> 2.11.0'
# Files attachments
gem 'carrierwave', '~> 1.3'
......
......@@ -471,7 +471,7 @@ GEM
rainbow
rubocop (>= 0.50.0)
sysexits (~> 1.1)
hamlit (2.10.0)
hamlit (2.11.0)
temple (>= 0.8.2)
thor
tilt
......@@ -1029,10 +1029,10 @@ GEM
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
thor (0.19.4)
thor (0.20.3)
thread_safe (0.3.6)
thrift (0.11.0.0)
tilt (2.0.9)
tilt (2.0.10)
timecop (0.8.1)
timfel-krb5-auth (0.8.3)
toml (0.2.0)
......@@ -1224,7 +1224,7 @@ DEPENDENCIES
gssapi
guard-rspec
haml_lint (~> 0.34.0)
hamlit (~> 2.10.0)
hamlit (~> 2.11.0)
hangouts-chat (~> 0.0.5)
hashie-forbidden_attributes
health_check (~> 2.6.0)
......
......@@ -12,6 +12,7 @@ import { APPLICATION_STATUS, INGRESS, INGRESS_DOMAIN_SUFFIX, CROSSPLANE } from '
import ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue';
import RemoveClusterConfirmation from './components/remove_cluster_confirmation.vue';
import setupToggleButtons from '../toggle_buttons';
import initProjectSelectDropdown from '~/project_select';
......@@ -144,6 +145,8 @@ export default class Clusters {
() => this.handlePollError(),
);
}
this.initRemoveClusterActions();
}
initApplications(type) {
......@@ -205,6 +208,25 @@ export default class Clusters {
});
}
initRemoveClusterActions() {
const el = document.querySelector('#js-cluster-remove-actions');
if (el && el.dataset) {
const { clusterName, clusterPath } = el.dataset;
this.removeClusterAction = new Vue({
el,
render(createElement) {
return createElement(RemoveClusterConfirmation, {
props: {
clusterName,
clusterPath,
},
});
},
});
}
}
handleClusterEnvironmentsSuccess(data) {
this.store.toggleFetchEnvironments(false);
this.store.updateEnvironments(data.data);
......
<script>
import _ from 'underscore';
import SplitButton from '~/vue_shared/components/split_button.vue';
import { GlModal, GlButton, GlFormInput } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import csrf from '~/lib/utils/csrf';
const splitButtonActionItems = [
{
title: s__('ClusterIntegration|Remove integration and resources'),
description: s__(
'ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal',
),
eventName: 'remove-cluster-and-cleanup',
},
{
title: s__('ClusterIntegration|Remove integration'),
description: s__(
'ClusterIntegration|Removes cluster from project but keeps associated resources',
),
eventName: 'remove-cluster',
},
];
export default {
splitButtonActionItems,
components: {
SplitButton,
GlModal,
GlButton,
GlFormInput,
},
props: {
clusterPath: {
type: String,
required: true,
},
clusterName: {
type: String,
required: true,
},
},
data() {
return {
enteredClusterName: '',
confirmCleanup: false,
};
},
computed: {
csrfToken() {
return csrf.token;
},
modalTitle() {
return this.confirmCleanup
? s__('ClusterIntegration|Remove integration and resources?')
: s__('ClusterIntegration|Remove integration?');
},
warningMessage() {
return this.confirmCleanup
? s__(
'ClusterIntegration|You are about to remove your cluster integration and all GitLab-created resources associated with this cluster.',
)
: s__('ClusterIntegration|You are about to remove your cluster integration.');
},
warningToBeRemoved() {
return s__(`ClusterIntegration|
This will permanently delete the following resources:
<ul>
<li>All installed applications and related resources</li>
<li>The <code>gitlab-managed-apps</code> namespace</li>
<li>Any project namespaces</li>
<li><code>clusterroles</code></li>
<li><code>clusterrolebindings</code></li>
</ul>
`);
},
confirmationTextLabel() {
return sprintf(
this.confirmCleanup
? s__(
'ClusterIntegration|To remove your integration and resources, type %{clusterName} to confirm:',
)
: s__('ClusterIntegration|To remove your integration, type %{clusterName} to confirm:'),
{
clusterName: `<code>${_.escape(this.clusterName)}</code>`,
},
false,
);
},
canSubmit() {
return this.enteredClusterName === this.clusterName;
},
},
methods: {
handleClickRemoveCluster(cleanup = false) {
this.confirmCleanup = cleanup;
this.$refs.modal.show();
},
handleCancel() {
this.$refs.modal.hide();
this.enteredClusterName = '';
},
handleSubmit(cleanup = false) {
this.$refs.cleanup.name = cleanup === true ? 'cleanup' : 'no_cleanup';
this.$refs.form.submit();
this.enteredClusterName = '';
},
},
};
</script>
<template>
<div>
<split-button
:action-items="$options.splitButtonActionItems"
menu-class="dropdown-menu-large"
variant="danger"
@remove-cluster="handleClickRemoveCluster(false)"
@remove-cluster-and-cleanup="handleClickRemoveCluster(true)"
/>
<gl-modal
ref="modal"
size="lg"
modal-id="delete-cluster-modal"
:title="modalTitle"
kind="danger"
>
<template>
<p>{{ warningMessage }}</p>
<div v-if="confirmCleanup" v-html="warningToBeRemoved"></div>
<strong v-html="confirmationTextLabel"></strong>
<form ref="form" :action="clusterPath" method="post" class="append-bottom-20">
<input ref="method" type="hidden" name="_method" value="delete" />
<input :value="csrfToken" type="hidden" name="authenticity_token" />
<input ref="cleanup" type="hidden" name="cleanup" value="true" />
<gl-form-input
v-model="enteredClusterName"
autofocus
type="text"
name="confirm_cluster_name_input"
autocomplete="off"
/>
</form>
<span v-if="confirmCleanup">{{
s__(
'ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration.',
)
}}</span>
</template>
<template slot="modal-footer">
<gl-button variant="secondary" @click="handleCancel">{{ s__('Cancel') }}</gl-button>
<template v-if="confirmCleanup">
<gl-button :disabled="!canSubmit" variant="warning" @click="handleSubmit">{{
s__('ClusterIntegration|Remove integration')
}}</gl-button>
<gl-button :disabled="!canSubmit" variant="danger" @click="handleSubmit(true)">{{
s__('ClusterIntegration|Remove integration and resources')
}}</gl-button>
</template>
<template v-else>
<gl-button :disabled="!canSubmit" variant="danger" @click="handleSubmit">{{
s__('ClusterIntegration|Remove integration')
}}</gl-button>
</template>
</template>
</gl-modal>
</div>
</template>
......@@ -4,6 +4,7 @@ import $ from 'jquery';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
import sanitize from 'sanitize-html';
import axios from '~/lib/utils/axios_utils';
import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility';
import flash from '~/flash';
import { __ } from '~/locale';
......@@ -116,7 +117,7 @@ export default class ProjectFindFile {
if (searchText) {
matches = fuzzaldrinPlus.match(filePath, searchText);
}
const blobItemUrl = `${this.options.blobUrlTemplate}/${encodeURIComponent(filePath)}`;
const blobItemUrl = joinPaths(this.options.blobUrlTemplate, escapeFileUrl(filePath));
const html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl);
results.push(this.element.find('.tree-table > tbody').append(html));
}
......
......@@ -26,6 +26,11 @@ export default {
required: false,
default: '',
},
variant: {
type: String,
required: false,
default: 'secondary',
},
},
data() {
......@@ -53,6 +58,7 @@ export default {
:menu-class="`dropdown-menu-selectable ${menuClass}`"
split
:text="dropdownToggleText"
:variant="variant"
v-bind="$attrs"
@click="triggerEvent"
>
......
......@@ -45,7 +45,7 @@ def execute
def all_groups
return [owned_groups] if params[:owned]
return [groups_with_min_access_level] if min_access_level?
return [Group.all] if current_user&.full_private_access? && all_available?
return [Group.all] if current_user&.can_read_all_resources? && all_available?
groups = []
groups << Gitlab::ObjectHierarchy.new(groups_for_ancestors, groups_for_descendants).all_objects if current_user
......
......@@ -127,7 +127,7 @@ def user_can_see_all_confidential_issues?
return @user_can_see_all_confidential_issues if defined?(@user_can_see_all_confidential_issues)
return @user_can_see_all_confidential_issues = false if current_user.blank?
return @user_can_see_all_confidential_issues = true if current_user.full_private_access?
return @user_can_see_all_confidential_issues = true if current_user.can_read_all_resources?
@user_can_see_all_confidential_issues =
if project? && project
......
......@@ -15,15 +15,43 @@ def initialize(current_user, params)
def execute
raise GitLabAccessDeniedError unless current_user.admin?
raise InvalidFingerprint unless valid_fingerprint_param?
Key.where(fingerprint_query).first # rubocop: disable CodeReuse/ActiveRecord
keys = by_key_type
keys = by_user(keys)
keys = sort(keys)
by_fingerprint(keys)
end
private
attr_reader :current_user, :params
def by_key_type
if params[:key_type] == 'ssh'
Key.regular_keys
else
Key.all
end
end
def sort(keys)
keys.order_last_used_at_desc
end
def by_user(keys)
return keys unless params[:user]
keys.for_user(params[:user])
end
def by_fingerprint(keys)
return keys unless params[:fingerprint].present?
raise InvalidFingerprint unless valid_fingerprint_param?
keys.where(fingerprint_query).first # rubocop: disable CodeReuse/ActiveRecord
end
def valid_fingerprint_param?
if fingerprint_type == "sha256"
Base64.decode64(fingerprint).length == 32
......
......@@ -11,15 +11,23 @@ def initialize(current_user: nil, source_project:)
end
# rubocop: disable CodeReuse/ActiveRecord
def execute
if @source_project.fork_network
@source_project.fork_network.projects
.public_or_visible_to_user(current_user)
.non_archived
.with_feature_available_for_user(:merge_requests, current_user)
def execute(include_routes: false)
if source_project.fork_network
include_routes ? projects.inc_routes : projects
else
Project.where(id: source_project)
end
end
# rubocop: enable CodeReuse/ActiveRecord
private
def projects
source_project
.fork_network
.projects
.public_or_visible_to_user(current_user)
.non_archived
.with_feature_available_for_user(:merge_requests, current_user)
end
end
......@@ -13,18 +13,26 @@ def execute
tokens = PersonalAccessToken.all
tokens = by_user(tokens)
tokens = by_impersonation(tokens)
by_state(tokens)
tokens = by_state(tokens)
sort(tokens)
end
private
# rubocop: disable CodeReuse/ActiveRecord
def by_user(tokens)
return tokens unless @params[:user]
tokens.where(user: @params[:user])
tokens.for_user(@params[:user])
end
def sort(tokens)
available_sort_orders = PersonalAccessToken.simple_sorts.keys
return tokens unless available_sort_orders.include?(params[:sort])
tokens.order_by(params[:sort])
end
# rubocop: enable CodeReuse/ActiveRecord
def by_impersonation(tokens)
case @params[:impersonation]
......
......@@ -88,7 +88,7 @@ def format_mr_branch_names(merge_request)
def target_projects(project)
MergeRequestTargetProjectFinder.new(current_user: current_user, source_project: project)
.execute
.execute(include_routes: true)
end
def merge_request_button_visibility(merge_request, closed)
......
......@@ -44,6 +44,14 @@ def current_user_menu?(item)
current_user_menu_items.include?(item)
end
# Used to preload when you are rendering many projects and checking access
#
# rubocop: disable CodeReuse/ActiveRecord: `projects` can be array which also responds to pluck
def load_max_project_member_accesses(projects)
current_user&.max_member_access_for_project_ids(projects.pluck(:id))
end
# rubocop: enable CodeReuse/ActiveRecord
def max_project_member_access(project)
current_user&.max_member_access_for_project(project.id) || Gitlab::Access::NO_ACCESS
end
......
......@@ -887,7 +887,7 @@ def successful_deployment_status
def each_report(report_types)
job_artifacts_for_types(report_types).each do |report_artifact|
report_artifact.each_blob do |blob|
yield report_artifact.file_type, blob
yield report_artifact.file_type, blob, report_artifact
end
end
end
......
......@@ -242,7 +242,7 @@ def visible_to_user?(user = nil)
return false unless readable_by?(user)
user.full_private_access? ||
user.can_read_all_resources? ||
::Gitlab::ExternalAuthorization.access_allowed?(
user, project.external_authorization_classification_label)
end
......
......@@ -39,6 +39,10 @@ class Key < ApplicationRecord
alias_attribute :fingerprint_md5, :fingerprint
scope :preload_users, -> { preload(:user) }
scope :for_user, -> (user) { where(user: user) }
scope :order_last_used_at_desc, -> { reorder(::Gitlab::Database.nulls_last_order('last_used_at', 'DESC')) }
def self.regular_keys
where(type: ['Key', nil])
end
......
......@@ -3,6 +3,7 @@
class PersonalAccessToken < ApplicationRecord
include Expirable
include TokenAuthenticatable
include Sortable
add_authentication_token_field :token, digest: true
......@@ -20,6 +21,8 @@ class PersonalAccessToken < ApplicationRecord
scope :inactive, -> { where("revoked = true OR expires_at < NOW()") }
scope :with_impersonation, -> { where(impersonation: true) }
scope :without_impersonation, -> { where(impersonation: false) }
scope :for_user, -> (user) { where(user: user) }
scope :preload_users, -> { preload(:user) }
validates :scopes, presence: true
validate :validate_scopes
......
......@@ -408,6 +408,7 @@ class Project < ApplicationRecord
scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids).distinct }
scope :with_push, -> { joins(:events).where('events.action = ?', Event::PUSHED) }
scope :with_project_feature, -> { joins('LEFT JOIN project_features ON projects.id = project_features.project_id') }
scope :inc_routes, -> { includes(:route, namespace: :route) }
scope :with_statistics, -> { includes(:statistics) }
scope :with_service, ->(service) { joins(service).eager_load(service) }
scope :with_shared_runners, -> { where(shared_runners_enabled: true) }
......
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