Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
81a37f0581
commit
25307dda30
|
@ -1,3 +1,7 @@
|
|||
<!-- This template is used as a starting point for understing and articulating a customer problem.
|
||||
Learn more about it in the handbook: https://about.gitlab.com/handbook/product-development-flow/#validation-phase-2-problem-validation
|
||||
-->
|
||||
|
||||
## Problem Statement
|
||||
|
||||
<!-- What is the problem we hope to validate? Reference how to write a real customer problem statement at https://productcoalition.com/how-to-write-a-good-customer-problem-statement-a815f80189ba for guidance. -->
|
||||
|
@ -45,4 +49,8 @@ For example, if the solution will take a product manager, designer, and engineer
|
|||
- [ ] The problem is well described and detailed with necessary requirements for product design to understand the problem
|
||||
- [ ] The problem is well described and detailed with necessary requirements for engineering to understand the problem
|
||||
|
||||
## Research Issue
|
||||
|
||||
<!-- Link to the Problem Validation Research issue that will be executed by the UX Researcher. https://gitlab.com/gitlab-org/ux-research/ -->
|
||||
|
||||
/label ~"workflow::validation backlog" ~devops:: ~category: ~group::
|
||||
|
|
|
@ -2293,6 +2293,15 @@ entry.
|
|||
- [Remove diffs gradual load feature flag](gitlab-org/gitlab@027d7c4327b5b6205a84281239027273517bf81b) ([merge request](gitlab-org/gitlab!55478))
|
||||
- [Remove partial index for Hashed Storage migration](gitlab-org/gitlab@3ed017a1023d7b0941a7606b69e6caee8d22f15c) ([merge request](gitlab-org/gitlab!62920))
|
||||
|
||||
## 14.0.12 (2021-11-05)
|
||||
|
||||
### Changed (4 changes)
|
||||
|
||||
- [Geo: Alternate redownload and normal design sync attempts](gitlab-org/gitlab@ed34172e5c7425316480efb732a9429e93e81017) ([merge request](gitlab-org/gitlab!73722)) **GitLab Enterprise Edition**
|
||||
- [Geo: Alternate redownload and normal SSF sync attempts](gitlab-org/gitlab@c0f2f40b98c4b9fc72c21c474a2224e045263ea2) ([merge request](gitlab-org/gitlab!73722)) **GitLab Enterprise Edition**
|
||||
- [Geo: Alternate redownload and normal project syncs](gitlab-org/gitlab@6370a7258719d5eb0ad83c54383ecb7f4fd54fc2) ([merge request](gitlab-org/gitlab!73722)) **GitLab Enterprise Edition**
|
||||
- [Geo: Reduce frequency of redownload attempts](gitlab-org/gitlab@1bcd41f28733b01286a42689857f6530c0805186) ([merge request](gitlab-org/gitlab!73722)) **GitLab Enterprise Edition**
|
||||
|
||||
## 14.0.11 (2021-09-23)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
|
|
@ -128,6 +128,7 @@ export default {
|
|||
</p>
|
||||
|
||||
<gl-tabs>
|
||||
<slot name="ee-security-tab"></slot>
|
||||
<gl-tab>
|
||||
<template #title>
|
||||
<span data-testid="cluster-agent-token-count">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import AgentShowPage from './components/show.vue';
|
||||
import AgentShowPage from 'ee_else_ce/clusters/agents/components/show.vue';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<script>
|
||||
import { GlTab, GlTabs } from '@gitlab/ui';
|
||||
import IncubationBanner from './incubation_banner.vue';
|
||||
import ServiceAccounts from './service_accounts.vue';
|
||||
|
||||
export default {
|
||||
components: { GlTab, GlTabs, IncubationBanner, ServiceAccounts },
|
||||
props: {
|
||||
serviceAccounts: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
createServiceAccountUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyIllustrationUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
feedbackUrl(template) {
|
||||
return `https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/meta/-/issues/new?issuable_template=${template}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<incubation-banner
|
||||
:share-feedback-url="feedbackUrl('general_feedback')"
|
||||
:report-bug-url="feedbackUrl('report_bug')"
|
||||
:feature-request-url="feedbackUrl('feature_request')"
|
||||
/>
|
||||
<gl-tabs>
|
||||
<gl-tab :title="__('Configuration')">
|
||||
<service-accounts
|
||||
class="gl-mx-3"
|
||||
:list="serviceAccounts"
|
||||
:create-url="createServiceAccountUrl"
|
||||
:empty-illustration-url="emptyIllustrationUrl"
|
||||
/>
|
||||
</gl-tab>
|
||||
<gl-tab :title="__('Deployments')" disabled />
|
||||
<gl-tab :title="__('Services')" disabled />
|
||||
</gl-tabs>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,44 @@
|
|||
<script>
|
||||
import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
components: { GlAlert, GlLink, GlSprintf },
|
||||
props: {
|
||||
shareFeedbackUrl: {
|
||||
required: true,
|
||||
type: String,
|
||||
},
|
||||
reportBugUrl: {
|
||||
required: true,
|
||||
type: String,
|
||||
},
|
||||
featureRequestUrl: {
|
||||
required: true,
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-alert :dismissible="false" variant="info">
|
||||
{{ __('This is an experimental feature developed by GitLab Incubation Engineering.') }}
|
||||
<gl-sprintf
|
||||
:message="
|
||||
__(
|
||||
'We invite you to %{featureLinkStart}request a feature%{featureLinkEnd}, %{bugLinkStart}report a bug%{bugLinkEnd} or %{feedbackLinkStart}share feedback%{feedbackLinkEnd}',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #featureLink="{ content }">
|
||||
<gl-link :href="featureRequestUrl">{{ content }}</gl-link>
|
||||
</template>
|
||||
<template #bugLink="{ content }">
|
||||
<gl-link :href="reportBugUrl">{{ content }}</gl-link>
|
||||
</template>
|
||||
<template #feedbackLink="{ content }">
|
||||
<gl-link :href="shareFeedbackUrl">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</gl-alert>
|
||||
</template>
|
|
@ -0,0 +1,65 @@
|
|||
<script>
|
||||
import { GlButton, GlEmptyState, GlTable } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
components: { GlButton, GlEmptyState, GlTable },
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
createUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyIllustrationUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableFields: [
|
||||
{ key: 'environment', label: __('Environment'), sortable: true },
|
||||
{ key: 'gcp_project', label: __('Google Cloud Project'), sortable: true },
|
||||
{ key: 'service_account_exists', label: __('Service Account'), sortable: true },
|
||||
{ key: 'service_account_key_exists', label: __('Service Account Key'), sortable: true },
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<gl-empty-state
|
||||
v-if="list.length === 0"
|
||||
:title="__('No service accounts')"
|
||||
:description="
|
||||
__('Service Accounts keys authorize GitLab to deploy your Google Cloud project')
|
||||
"
|
||||
:primary-button-link="createUrl"
|
||||
:primary-button-text="__('Create service account')"
|
||||
:svg-path="emptyIllustrationUrl"
|
||||
/>
|
||||
|
||||
<div v-else>
|
||||
<h2 class="gl-font-size-h2">{{ __('Service Accounts') }}</h2>
|
||||
<p>{{ __('Service Accounts keys authorize GitLab to deploy your Google Cloud project') }}</p>
|
||||
|
||||
<gl-table :items="list" :fields="tableFields">
|
||||
<template #cell(service_account_exists)="{ value }">
|
||||
{{ value ? '✔' : __('Not found') }}
|
||||
</template>
|
||||
<template #cell(service_account_key_exists)="{ value }">
|
||||
{{ value ? '✔' : __('Not found') }}
|
||||
</template>
|
||||
</gl-table>
|
||||
|
||||
<gl-button :href="createUrl" category="primary" variant="info">
|
||||
{{ __('Create service account') }}
|
||||
</gl-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,19 @@
|
|||
import Vue from 'vue';
|
||||
import App from './components/app.vue';
|
||||
|
||||
const elementRenderer = (element, props = {}) => (createElement) =>
|
||||
createElement(element, { props });
|
||||
|
||||
export default () => {
|
||||
const root = document.querySelector('#js-google-cloud');
|
||||
|
||||
// uncomment this once backend is ready
|
||||
// const dataset = JSON.parse(root.getAttribute('data'));
|
||||
const mockDataset = {
|
||||
createServiceAccountUrl: '#create-url',
|
||||
serviceAccounts: [],
|
||||
emptyIllustrationUrl:
|
||||
'https://gitlab.com/gitlab-org/gitlab-svgs/-/raw/main/illustrations/pipelines_empty.svg',
|
||||
};
|
||||
return new Vue({ el: root, render: elementRenderer(App, mockDataset) });
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
import initGoogleCloud from '~/google_cloud/index';
|
||||
|
||||
initGoogleCloud();
|
|
@ -23,14 +23,14 @@ export default class Project {
|
|||
});
|
||||
}
|
||||
|
||||
$('.hide-no-ssh-message').on('click', function (e) {
|
||||
$('.js-hide-no-ssh-message').on('click', function (e) {
|
||||
Cookies.set('hide_no_ssh_message', 'false');
|
||||
$(this).parents('.no-ssh-key-message').remove();
|
||||
$(this).parents('.js-no-ssh-key-message').remove();
|
||||
return e.preventDefault();
|
||||
});
|
||||
$('.hide-no-password-message').on('click', function (e) {
|
||||
$('.js-hide-no-password-message').on('click', function (e) {
|
||||
Cookies.set('hide_no_password_message', 'false');
|
||||
$(this).parents('.no-password-message').remove();
|
||||
$(this).parents('.js-no-password-message').remove();
|
||||
return e.preventDefault();
|
||||
});
|
||||
$('.hide-auto-devops-implicitly-enabled-banner').on('click', function (e) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlModal, GlModalDirective, GlFormTextarea, GlButton } from '@gitlab/ui';
|
||||
import { GlModal, GlModalDirective, GlFormInput, GlButton } from '@gitlab/ui';
|
||||
import { uniqueId } from 'lodash';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
import { __ } from '~/locale';
|
||||
|
@ -7,7 +7,7 @@ import { __ } from '~/locale';
|
|||
export default {
|
||||
components: {
|
||||
GlModal,
|
||||
GlFormTextarea,
|
||||
GlFormInput,
|
||||
GlButton,
|
||||
},
|
||||
directives: {
|
||||
|
@ -88,7 +88,12 @@ export default {
|
|||
<p>
|
||||
<code class="gl-white-space-pre-wrap">{{ confirmPhrase }}</code>
|
||||
</p>
|
||||
<gl-form-textarea id="confirm_name_input" v-model="userInput" name="confirm_name_input" />
|
||||
<gl-form-input
|
||||
id="confirm_name_input"
|
||||
v-model="userInput"
|
||||
name="confirm_name_input"
|
||||
type="text"
|
||||
/>
|
||||
<slot name="modal-footer"></slot>
|
||||
</div>
|
||||
</gl-modal>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
import TermsApp from 'jh_else_ce/terms/components/app.vue';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import TermsApp from './components/app.vue';
|
||||
|
||||
export const initTermsApp = () => {
|
||||
const el = document.getElementById('js-terms-of-service');
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
class Projects::ClusterAgentsController < Projects::ApplicationController
|
||||
before_action :authorize_can_read_cluster_agent!
|
||||
|
||||
before_action do
|
||||
push_frontend_feature_flag(:cluster_vulnerabilities, project, default_enabled: :yaml)
|
||||
end
|
||||
|
||||
feature_category :kubernetes_management
|
||||
|
||||
def show
|
||||
|
@ -17,3 +21,5 @@ class Projects::ClusterAgentsController < Projects::ApplicationController
|
|||
access_denied!
|
||||
end
|
||||
end
|
||||
|
||||
Projects::ClusterAgentsController.prepend_mod_with('Projects::ClusterAgentsController')
|
||||
|
|
|
@ -196,12 +196,26 @@ module ProjectsHelper
|
|||
cookies["hide_auto_devops_implicitly_enabled_banner_#{project.id}".to_sym].blank?
|
||||
end
|
||||
|
||||
def link_to_set_password
|
||||
if current_user.require_password_creation_for_git?
|
||||
link_to s_('SetPasswordToCloneLink|set a password'), edit_profile_password_path
|
||||
else
|
||||
link_to s_('CreateTokenToCloneLink|create a personal access token'), profile_personal_access_tokens_path
|
||||
end
|
||||
def no_password_message
|
||||
push_pull_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('gitlab-basics/start-using-git', anchor: 'pull-and-push') }
|
||||
clone_with_https_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('gitlab-basics/start-using-git', anchor: 'clone-with-https') }
|
||||
set_password_link_start = '<a href="%{url}">'.html_safe % { url: edit_profile_password_path }
|
||||
set_up_pat_link_start = '<a href="%{url}">'.html_safe % { url: profile_personal_access_tokens_path }
|
||||
|
||||
message = if current_user.require_password_creation_for_git?
|
||||
_('Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_password_link_start}set a password%{link_end} or %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}.')
|
||||
else
|
||||
_('Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}.')
|
||||
end
|
||||
|
||||
html_escape(message) % {
|
||||
push_pull_link_start: push_pull_link_start,
|
||||
protocol: gitlab_config.protocol.upcase,
|
||||
clone_with_https_link_start: clone_with_https_link_start,
|
||||
set_password_link_start: set_password_link_start,
|
||||
set_up_pat_link_start: set_up_pat_link_start,
|
||||
link_end: '</a>'.html_safe
|
||||
}
|
||||
end
|
||||
|
||||
# Returns true if any projects are present.
|
||||
|
@ -384,12 +398,11 @@ module ProjectsHelper
|
|||
|
||||
# Returns the confirm phrase the user needs to type in order to delete the project
|
||||
#
|
||||
# Occasionally a user will delete one project, believing it is a different (similar) one.
|
||||
# Specifically, a user might delete an original project, believing it is a fork.
|
||||
# Thus the phrase should be the project full name to include the namespace.
|
||||
# Thus the phrase should include the namespace to make it very clear to the
|
||||
# user which project is subject to deletion.
|
||||
# Relevant issue: https://gitlab.com/gitlab-org/gitlab/-/issues/343591
|
||||
def delete_confirm_phrase(project)
|
||||
s_('DeleteProject|Delete %{name}') % { name: project.full_name }
|
||||
project.path_with_namespace
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -48,7 +48,7 @@ class CommitStatus < Ci::ApplicationRecord
|
|||
scope :ordered, -> { order(:name) }
|
||||
scope :ordered_by_stage, -> { order(stage_idx: :asc) }
|
||||
scope :latest_ordered, -> { latest.ordered.includes(project: :namespace) }
|
||||
scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) }
|
||||
scope :retried_ordered, -> { retried.order(name: :asc, id: :desc).includes(project: :namespace) }
|
||||
scope :ordered_by_pipeline, -> { order(pipeline_id: :asc) }
|
||||
scope :before_stage, -> (index) { where('stage_idx < ?', index) }
|
||||
scope :for_stage, -> (index) { where(stage_idx: index) }
|
||||
|
|
|
@ -7,6 +7,7 @@ class MergeRequestDiffCommit < ApplicationRecord
|
|||
include ShaAttribute
|
||||
include CachedCommit
|
||||
include IgnorableColumns
|
||||
include FromUnion
|
||||
|
||||
ignore_column %i[author_name author_email committer_name committer_email],
|
||||
remove_with: '14.6',
|
||||
|
|
|
@ -473,7 +473,11 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def active_for_authentication?
|
||||
super && can?(:log_in)
|
||||
return false unless super
|
||||
|
||||
check_ldap_if_ldap_blocked!
|
||||
|
||||
can?(:log_in)
|
||||
end
|
||||
|
||||
# The messages for these keys are defined in `devise.en.yml`
|
||||
|
@ -2167,6 +2171,13 @@ class User < ApplicationRecord
|
|||
def ci_job_token_scope_cache_key
|
||||
"users:#{id}:ci:job_token_scope"
|
||||
end
|
||||
|
||||
# An `ldap_blocked` user will be unblocked if LDAP indicates they are allowed.
|
||||
def check_ldap_if_ldap_blocked!
|
||||
return unless ::Gitlab::Auth::Ldap::Config.enabled? && ldap_blocked?
|
||||
|
||||
::Gitlab::Auth::Ldap::Access.allowed?(self)
|
||||
end
|
||||
end
|
||||
|
||||
User.prepend_mod_with('User')
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
- if show_no_password_message?
|
||||
.no-password-message.gl-alert.gl-alert-warning
|
||||
= sprite_icon('warning', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
|
||||
%button.js-close.gl-alert-dismiss{ type: 'button', 'aria-label': _('Dismiss') }
|
||||
= sprite_icon('close', size: 16, css_class: 'gl-icon')
|
||||
= render 'shared/global_alert',
|
||||
variant: :warning,
|
||||
alert_class: 'js-no-password-message',
|
||||
close_button_class: 'js-hide-no-password-message' do
|
||||
.gl-alert-body
|
||||
- translation_params = { protocol: gitlab_config.protocol.upcase, set_password_link: link_to_set_password }
|
||||
- set_password_message = _("You won't be able to pull or push repositories via %{protocol} until you %{set_password_link} on your account") % translation_params
|
||||
= set_password_message.html_safe
|
||||
= no_password_message
|
||||
.gl-alert-actions
|
||||
= link_to _('Remind later'), '#', class: 'hide-no-password-message btn gl-alert-action btn-info btn-md gl-button'
|
||||
= link_to _("Don't show again"), profile_path(user: {hide_no_password: true}), method: :put, role: 'button', class: 'btn gl-alert-action btn-md btn-default gl-button btn-default-secondary'
|
||||
= link_to _('Remind later'), '#', class: 'js-hide-no-password-message gl-alert-action btn btn-confirm btn-md gl-button'
|
||||
= link_to _("Don't show again"), profile_path(user: { hide_no_password: true }), method: :put, role: 'button', class: 'gl-alert-action btn btn-default btn-md gl-button'
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
- if show_no_ssh_key_message?
|
||||
%div{ class: 'no-ssh-key-message gl-alert gl-alert-warning', role: 'alert' }
|
||||
= sprite_icon('warning', css_class: 'gl-icon s16 gl-alert-icon gl-alert-icon-no-title')
|
||||
%button{ class: 'gl-alert-dismiss hide-no-ssh-message', type: 'button', 'aria-label': _('Dismiss') }
|
||||
= sprite_icon('close', css_class: 'gl-icon s16')
|
||||
= render 'shared/global_alert',
|
||||
variant: :warning,
|
||||
alert_class: 'js-no-ssh-message',
|
||||
close_button_class: 'js-hide-no-ssh-message' do
|
||||
.gl-alert-body
|
||||
= s_("MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile")
|
||||
= s_("MissingSSHKeyWarningLink|You can't push or pull repositories using SSH until you add an SSH key to your profile.")
|
||||
.gl-alert-actions
|
||||
= link_to s_('MissingSSHKeyWarningLink|Add SSH key'), profile_keys_path, class: "btn gl-alert-action btn-warning btn-md gl-button"
|
||||
= link_to s_("MissingSSHKeyWarningLink|Don't show again"), profile_path(user: {hide_no_ssh_key: true}), method: :put, role: 'button', class: 'btn gl-alert-action btn-md btn-warning gl-button btn-warning-secondary'
|
||||
= link_to s_('MissingSSHKeyWarningLink|Add SSH key'), profile_keys_path, class: "gl-alert-action btn btn-confirm btn-md gl-button"
|
||||
= link_to s_("MissingSSHKeyWarningLink|Don't show again"), profile_path(user: { hide_no_ssh_key: true }), method: :put, role: 'button', class: 'gl-alert-action btn btn-default btn-md gl-button'
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: cluster_vulnerabilities
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73321
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343917
|
||||
milestone: '14.5'
|
||||
type: development
|
||||
group: group::container security
|
||||
default_enabled: false
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343046
|
|||
milestone: '14.5'
|
||||
type: development
|
||||
group: group::access
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -42,11 +42,15 @@ GitLab to an earlier version, the feature flag status may change.
|
|||
|
||||
Features that are disabled by default may change or be removed without notice in a future version of GitLab.
|
||||
|
||||
Data corruption, stability degradation, or performance degradation might occur if
|
||||
Data corruption, stability degradation, performance degradation, or security issues might occur if
|
||||
you enable a feature that's disabled by default. Problems caused by using a default
|
||||
disabled feature aren't covered by GitLab support, unless you were directed by GitLab
|
||||
to enable the feature.
|
||||
|
||||
Security issues found in features that are disabled by default are patched in regular releases
|
||||
and do not follow our regular [maintenance policy](../policy/maintenance.md#security-releases)
|
||||
with regards to backporting the fix.
|
||||
|
||||
## Risks when disabling released features
|
||||
|
||||
In most cases, the feature flag code is removed in a future version of GitLab.
|
||||
|
|
|
@ -74,6 +74,20 @@ you want using steps 1 and 2 from the GitLab downloads page.
|
|||
postgresql['trust_auth_cidr_addresses'] = %w(127.0.0.1/32 10.10.1.30/32 10.10.1.31/32 10.10.1.32/32 10.10.1.33/32 10.10.1.38/32)
|
||||
```
|
||||
|
||||
1. If you run multiple Sidekiq nodes with a shared file storage, such as NFS, you must
|
||||
specify the UIDs and GIDs to ensure they match between servers. Specifying the UIDs
|
||||
and GIDs prevents permissions issues in the file system. This advice is similar to the
|
||||
[advice for Geo setups](geo/replication/multiple_servers.md#step-4-configure-the-frontend-application-nodes-on-the-geo-secondary-site):
|
||||
|
||||
```ruby
|
||||
user['uid'] = 9000
|
||||
user['gid'] = 9000
|
||||
web_server['uid'] = 9001
|
||||
web_server['gid'] = 9001
|
||||
registry['uid'] = 9002
|
||||
registry['gid'] = 9002
|
||||
```
|
||||
|
||||
1. Disable other services:
|
||||
|
||||
```ruby
|
||||
|
|
|
@ -56,11 +56,18 @@ To add this badge to a project:
|
|||
|
||||
## Group badges
|
||||
|
||||
Badges can be added to a group and are visible on every project's
|
||||
overview page that's under that group. In this case, they cannot be edited or
|
||||
deleted on the project level. If you need to have individual badges for each
|
||||
project, consider adding them on the [project level](#project-badges) or use
|
||||
[placeholders](#placeholders).
|
||||
By adding a badge to a group, you add and enforce a project-level badge
|
||||
for all projects in the group. The group badge is visible on the **Overview**
|
||||
page of any project that belongs to the group.
|
||||
|
||||
NOTE:
|
||||
While these badges appear as project-level badges in the codebase, they
|
||||
cannot be edited or deleted at the project level.
|
||||
|
||||
If you need individual badges for each project, either:
|
||||
|
||||
- Add the badge at the [project level](#project-badges).
|
||||
- Use [placeholders](#placeholders).
|
||||
|
||||
To add a new badge to a group:
|
||||
|
||||
|
|
|
@ -44,7 +44,22 @@ Users with the [Owner role](../../permissions.md) in a group can
|
|||
[import and export group wikis](../../group/settings/import_export.md) when importing
|
||||
or exporting a group.
|
||||
|
||||
Content created in a group wiki is not deleted when an account is downgraded or a GitLab trial ends.
|
||||
Content created in a group wiki is not deleted when an account is downgraded or a
|
||||
GitLab trial ends. The group wiki data is exported whenever the group owner of
|
||||
the wiki is exported.
|
||||
|
||||
To access the group wiki data from the export file if the feature is no longer
|
||||
available, you have to:
|
||||
|
||||
1. Extract the [export file tarball](../../group/settings/import_export.md) with
|
||||
this command, replacing `FILENAME` with your file's name:
|
||||
`tar -xvzf FILENAME.tar.gz`
|
||||
1. Browse to the `repositories` directory. This directory contains a
|
||||
[Git bundle](https://git-scm.com/docs/git-bundle) with the extension `.wiki.bundle`.
|
||||
1. Clone the Git bundle into a new repository, replacing `FILENAME` with
|
||||
your bundle's name: `git clone FILENAME.wiki.bundle`
|
||||
|
||||
All files in the wiki are available in this Git repository.
|
||||
|
||||
## Related topics
|
||||
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module BulkImports
|
||||
module Groups
|
||||
module Graphql
|
||||
module GetMilestonesQuery
|
||||
extend self
|
||||
|
||||
def to_s
|
||||
<<-'GRAPHQL'
|
||||
query ($full_path: ID!, $cursor: String, $per_page: Int) {
|
||||
group(fullPath: $full_path) {
|
||||
milestones(first: $per_page, after: $cursor, includeDescendants: false) {
|
||||
page_info: pageInfo {
|
||||
next_page: endCursor
|
||||
has_next_page: hasNextPage
|
||||
}
|
||||
nodes {
|
||||
iid
|
||||
title
|
||||
description
|
||||
state
|
||||
start_date: startDate
|
||||
due_date: dueDate
|
||||
created_at: createdAt
|
||||
updated_at: updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
def variables(context)
|
||||
{
|
||||
full_path: context.entity.source_full_path,
|
||||
cursor: context.tracker.next_page,
|
||||
per_page: ::BulkImports::Tracker::DEFAULT_PAGE_SIZE
|
||||
}
|
||||
end
|
||||
|
||||
def base_path
|
||||
%w[data group milestones]
|
||||
end
|
||||
|
||||
def data_path
|
||||
base_path << 'nodes'
|
||||
end
|
||||
|
||||
def page_info_path
|
||||
base_path << 'page_info'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,7 +10,10 @@ module Gitlab
|
|||
# this process needs Git/Gitaly access, and duplicating all that code is far
|
||||
# too much, this migration relies on global models such as Project,
|
||||
# MergeRequest, etc.
|
||||
# rubocop: disable Metrics/ClassLength
|
||||
class FixMergeRequestDiffCommitUsers
|
||||
BATCH_SIZE = 100
|
||||
|
||||
def initialize
|
||||
@commits = {}
|
||||
@users = {}
|
||||
|
@ -33,24 +36,47 @@ module Gitlab
|
|||
# Loading everything using one big query may result in timeouts (e.g.
|
||||
# for projects the size of gitlab-org/gitlab). So instead we query
|
||||
# data on a per merge request basis.
|
||||
project.merge_requests.each_batch do |mrs|
|
||||
::MergeRequestDiffCommit
|
||||
.select([
|
||||
:merge_request_diff_id,
|
||||
:relative_order,
|
||||
:sha,
|
||||
:committer_id,
|
||||
:commit_author_id
|
||||
])
|
||||
.joins(merge_request_diff: :merge_request)
|
||||
.where(merge_requests: { id: mrs.select(:id) })
|
||||
.where('commit_author_id IS NULL OR committer_id IS NULL')
|
||||
.each do |commit|
|
||||
project.merge_requests.each_batch(column: :iid) do |mrs|
|
||||
mrs.ids.each do |mr_id|
|
||||
each_row_to_check(mr_id) do |commit|
|
||||
update_commit(project, commit)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def each_row_to_check(merge_request_id, &block)
|
||||
columns = %w[merge_request_diff_id relative_order].map do |col|
|
||||
Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: col,
|
||||
order_expression: MergeRequestDiffCommit.arel_table[col.to_sym].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
)
|
||||
end
|
||||
|
||||
order = Pagination::Keyset::Order.build(columns)
|
||||
scope = MergeRequestDiffCommit
|
||||
.joins(:merge_request_diff)
|
||||
.where(merge_request_diffs: { merge_request_id: merge_request_id })
|
||||
.where('commit_author_id IS NULL OR committer_id IS NULL')
|
||||
.order(order)
|
||||
|
||||
Pagination::Keyset::Iterator
|
||||
.new(scope: scope, use_union_optimization: true)
|
||||
.each_batch(of: BATCH_SIZE) do |rows|
|
||||
rows
|
||||
.select([
|
||||
:merge_request_diff_id,
|
||||
:relative_order,
|
||||
:sha,
|
||||
:committer_id,
|
||||
:commit_author_id
|
||||
])
|
||||
.each(&block)
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop: disable Metrics/AbcSize
|
||||
def update_commit(project, row)
|
||||
commit = find_commit(project, row.sha)
|
||||
|
@ -125,5 +151,6 @@ module Gitlab
|
|||
MergeRequestDiffCommit.arel_table
|
||||
end
|
||||
end
|
||||
# rubocop: enable Metrics/ClassLength
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2914,6 +2914,9 @@ msgstr ""
|
|||
msgid "Advanced export options"
|
||||
msgstr ""
|
||||
|
||||
msgid "AdvancedSearch|Reindex required"
|
||||
msgstr ""
|
||||
|
||||
msgid "After a successful password update you will be redirected to login screen."
|
||||
msgstr ""
|
||||
|
||||
|
@ -7400,6 +7403,9 @@ msgstr ""
|
|||
msgid "ClusterAgents|Registration token"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterAgents|Security"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterAgents|Select an Agent"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9742,6 +9748,9 @@ msgstr ""
|
|||
msgid "Create requirement"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create service account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create snippet"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9775,9 +9784,6 @@ msgstr ""
|
|||
msgid "CreateTag|Tag"
|
||||
msgstr ""
|
||||
|
||||
msgid "CreateTokenToCloneLink|create a personal access token"
|
||||
msgstr ""
|
||||
|
||||
msgid "CreateValueStreamForm|%{name} (default)"
|
||||
msgstr ""
|
||||
|
||||
|
@ -11107,9 +11113,6 @@ msgstr ""
|
|||
msgid "Delete variable"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeleteProject|Delete %{name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "DeleteProject|Failed to remove project repository. Please try again or contact administrator."
|
||||
msgstr ""
|
||||
|
||||
|
@ -16034,6 +16037,9 @@ msgstr ""
|
|||
msgid "Google Cloud"
|
||||
msgstr ""
|
||||
|
||||
msgid "Google Cloud Project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Google authentication is not %{link_start}properly configured%{link_end}. Ask your GitLab administrator if you want to use this service."
|
||||
msgstr ""
|
||||
|
||||
|
@ -18647,6 +18653,9 @@ msgstr ""
|
|||
msgid "Interval Pattern"
|
||||
msgstr ""
|
||||
|
||||
msgid "Introduced in GitLab 13.1, before using %{reindexing_link_start}zero-downtime reindexing%{link_end} and %{migrations_link_start}Advanced Search migrations%{link_end}, you need to %{recreate_link_start}recreate your index%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Introducing Your DevOps Reports"
|
||||
msgstr ""
|
||||
|
||||
|
@ -22387,6 +22396,9 @@ msgstr ""
|
|||
msgid "MissingSSHKeyWarningLink|Don't show again"
|
||||
msgstr ""
|
||||
|
||||
msgid "MissingSSHKeyWarningLink|You can't push or pull repositories using SSH until you add an SSH key to your profile."
|
||||
msgstr ""
|
||||
|
||||
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
|
||||
msgstr ""
|
||||
|
||||
|
@ -23366,6 +23378,9 @@ msgstr ""
|
|||
msgid "No schedules"
|
||||
msgstr ""
|
||||
|
||||
msgid "No service accounts"
|
||||
msgstr ""
|
||||
|
||||
msgid "No severity matches the provided parameter"
|
||||
msgstr ""
|
||||
|
||||
|
@ -23461,6 +23476,9 @@ msgstr ""
|
|||
msgid "Not confidential"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not found"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not found."
|
||||
msgstr ""
|
||||
|
||||
|
@ -31282,6 +31300,18 @@ msgstr ""
|
|||
msgid "Service"
|
||||
msgstr ""
|
||||
|
||||
msgid "Service Account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Service Account Key"
|
||||
msgstr ""
|
||||
|
||||
msgid "Service Accounts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Service Accounts keys authorize GitLab to deploy your Google Cloud project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Service Desk"
|
||||
msgstr ""
|
||||
|
||||
|
@ -31336,6 +31366,9 @@ msgstr ""
|
|||
msgid "ServicePing|Turn on service ping to review instance-level analytics."
|
||||
msgstr ""
|
||||
|
||||
msgid "Services"
|
||||
msgstr ""
|
||||
|
||||
msgid "Session ID"
|
||||
msgstr ""
|
||||
|
||||
|
@ -31474,9 +31507,6 @@ msgstr ""
|
|||
msgid "Set what should be replicated by this secondary site."
|
||||
msgstr ""
|
||||
|
||||
msgid "SetPasswordToCloneLink|set a password"
|
||||
msgstr ""
|
||||
|
||||
msgid "SetStatusModal|Add status emoji"
|
||||
msgstr ""
|
||||
|
||||
|
@ -35110,6 +35140,9 @@ msgstr ""
|
|||
msgid "This is a self-managed instance of GitLab."
|
||||
msgstr ""
|
||||
|
||||
msgid "This is an experimental feature developed by GitLab Incubation Engineering."
|
||||
msgstr ""
|
||||
|
||||
msgid "This is the highest peak of users on your installation since the license started."
|
||||
msgstr ""
|
||||
|
||||
|
@ -37021,6 +37054,9 @@ msgstr ""
|
|||
msgid "UsageQuota|Learn more about usage quotas"
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|No CI minutes usage data available."
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|Packages"
|
||||
msgstr ""
|
||||
|
||||
|
@ -38356,6 +38392,9 @@ msgstr ""
|
|||
msgid "We heard back from your device. You have been authenticated."
|
||||
msgstr ""
|
||||
|
||||
msgid "We invite you to %{featureLinkStart}request a feature%{featureLinkEnd}, %{bugLinkStart}report a bug%{bugLinkEnd} or %{feedbackLinkStart}share feedback%{feedbackLinkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "We recommend cloud-based mobile authenticator apps such as Authy, Duo Mobile, and LastPass. They can restore access if you lose your hardware device."
|
||||
msgstr ""
|
||||
|
||||
|
@ -39552,9 +39591,6 @@ msgstr ""
|
|||
msgid "You won't be able to create new projects because you have reached your project limit."
|
||||
msgstr ""
|
||||
|
||||
msgid "You won't be able to pull or push repositories via %{protocol} until you %{set_password_link} on your account"
|
||||
msgstr ""
|
||||
|
||||
msgid "You'll be charged for %{true_up_link_start}users over license%{link_end} on a quarterly or annual basis, depending on the terms of your agreement."
|
||||
msgstr ""
|
||||
|
||||
|
@ -39705,6 +39741,12 @@ msgstr ""
|
|||
msgid "Your account has been deactivated. You will not be able to: "
|
||||
msgstr ""
|
||||
|
||||
msgid "Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_password_link_start}set a password%{link_end} or %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Your account is locked."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@
|
|||
"@babel/preset-env": "^7.10.1",
|
||||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "1.219.0",
|
||||
"@gitlab/svgs": "1.220.0",
|
||||
"@gitlab/tributejs": "1.0.0",
|
||||
"@gitlab/ui": "32.31.0",
|
||||
"@gitlab/ui": "32.33.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "6.1.4-1",
|
||||
"@rails/ujs": "6.1.4-1",
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'No Password Alert' do
|
||||
let_it_be(:message_password_auth_enabled) { 'Your account is authenticated with SSO or SAML. To push and pull over HTTP with Git using this account, you must set a password or set up a Personal Access Token to use instead of a password. For more information, see Clone with HTTPS.' }
|
||||
let_it_be(:message_password_auth_disabled) { 'Your account is authenticated with SSO or SAML. To push and pull over HTTP with Git using this account, you must set up a Personal Access Token to use instead of a password. For more information, see Clone with HTTPS.' }
|
||||
|
||||
let(:project) { create(:project, :repository, namespace: user.namespace) }
|
||||
|
||||
context 'with internal auth enabled' do
|
||||
|
@ -15,7 +18,7 @@ RSpec.describe 'No Password Alert' do
|
|||
let(:user) { create(:user) }
|
||||
|
||||
it 'shows no alert' do
|
||||
expect(page).not_to have_content "You won't be able to pull or push repositories via HTTP until you set a password on your account"
|
||||
expect(page).not_to have_content message_password_auth_enabled
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -23,7 +26,7 @@ RSpec.describe 'No Password Alert' do
|
|||
let(:user) { create(:user, password_automatically_set: true) }
|
||||
|
||||
it 'shows a password alert' do
|
||||
expect(page).to have_content "You won't be able to pull or push repositories via HTTP until you set a password on your account"
|
||||
expect(page).to have_content message_password_auth_enabled
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -41,7 +44,7 @@ RSpec.describe 'No Password Alert' do
|
|||
gitlab_sign_in_via('saml', user, 'my-uid')
|
||||
visit project_path(project)
|
||||
|
||||
expect(page).to have_content "You won't be able to pull or push repositories via HTTP until you create a personal access token on your account"
|
||||
expect(page).to have_content message_password_auth_disabled
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -51,7 +54,7 @@ RSpec.describe 'No Password Alert' do
|
|||
gitlab_sign_in_via('saml', user, 'my-uid')
|
||||
visit project_path(project)
|
||||
|
||||
expect(page).not_to have_content "You won't be able to pull or push repositories via HTTP until you create a personal access token on your account"
|
||||
expect(page).not_to have_content message_password_auth_disabled
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -257,7 +257,7 @@ RSpec.describe 'Project' do
|
|||
end
|
||||
|
||||
it 'deletes a project', :sidekiq_inline do
|
||||
expect { remove_with_confirm('Delete project', "Delete #{project.full_name}", 'Yes, delete project') }.to change { Project.count }.by(-1)
|
||||
expect { remove_with_confirm('Delete project', project.path_with_namespace, 'Yes, delete project') }.to change { Project.count }.by(-1)
|
||||
expect(page).to have_content "Project '#{project.full_name}' is in the process of being deleted."
|
||||
expect(Project.all.count).to be_zero
|
||||
expect(project.issues).to be_empty
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { GlAlert, GlKeysetPagination, GlLoadingIcon, GlSprintf, GlTab } from '@gitlab/ui';
|
||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import ClusterAgentShow from '~/clusters/agents/components/show.vue';
|
||||
import TokenTable from '~/clusters/agents/components/token_table.vue';
|
||||
import getAgentQuery from '~/clusters/agents/graphql/queries/get_cluster_agent.query.graphql';
|
||||
|
@ -40,28 +42,34 @@ describe('ClusterAgentShow', () => {
|
|||
queryResponse || jest.fn().mockResolvedValue({ data: { project: { clusterAgent } } });
|
||||
const apolloProvider = createMockApollo([[getAgentQuery, agentQueryResponse]]);
|
||||
|
||||
wrapper = shallowMount(ClusterAgentShow, {
|
||||
localVue,
|
||||
apolloProvider,
|
||||
propsData,
|
||||
stubs: { GlSprintf, TimeAgoTooltip, GlTab },
|
||||
});
|
||||
wrapper = extendedWrapper(
|
||||
shallowMount(ClusterAgentShow, {
|
||||
localVue,
|
||||
apolloProvider,
|
||||
propsData,
|
||||
stubs: { GlSprintf, TimeAgoTooltip, GlTab },
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const createWrapperWithoutApollo = ({ clusterAgent, loading = false }) => {
|
||||
const createWrapperWithoutApollo = ({ clusterAgent, loading = false, slots = {} }) => {
|
||||
const $apollo = { queries: { clusterAgent: { loading } } };
|
||||
|
||||
wrapper = shallowMount(ClusterAgentShow, {
|
||||
propsData,
|
||||
mocks: { $apollo, clusterAgent },
|
||||
stubs: { GlTab },
|
||||
});
|
||||
wrapper = extendedWrapper(
|
||||
shallowMount(ClusterAgentShow, {
|
||||
propsData,
|
||||
mocks: { $apollo, clusterAgent },
|
||||
slots,
|
||||
stubs: { GlTab },
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const findCreatedText = () => wrapper.find('[data-testid="cluster-agent-create-info"]').text();
|
||||
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
|
||||
const findPaginationButtons = () => wrapper.find(GlKeysetPagination);
|
||||
const findTokenCount = () => wrapper.find('[data-testid="cluster-agent-token-count"]').text();
|
||||
const findCreatedText = () => wrapper.findByTestId('cluster-agent-create-info').text();
|
||||
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findPaginationButtons = () => wrapper.findComponent(GlKeysetPagination);
|
||||
const findTokenCount = () => wrapper.findByTestId('cluster-agent-token-count').text();
|
||||
const findEESecurityTabSlot = () => wrapper.findByTestId('ee-security-tab');
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
|
@ -87,7 +95,7 @@ describe('ClusterAgentShow', () => {
|
|||
});
|
||||
|
||||
it('renders token table', () => {
|
||||
expect(wrapper.find(TokenTable).exists()).toBe(true);
|
||||
expect(wrapper.findComponent(TokenTable).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should not render pagination buttons when there are no additional pages', () => {
|
||||
|
@ -188,8 +196,27 @@ describe('ClusterAgentShow', () => {
|
|||
});
|
||||
|
||||
it('displays an alert message', () => {
|
||||
expect(wrapper.find(GlAlert).exists()).toBe(true);
|
||||
expect(wrapper.findComponent(GlAlert).exists()).toBe(true);
|
||||
expect(wrapper.text()).toContain(ClusterAgentShow.i18n.loadingError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ee-security-tab slot', () => {
|
||||
it('does not display when a slot is not passed in', async () => {
|
||||
createWrapperWithoutApollo({ clusterAgent: defaultClusterAgent });
|
||||
await nextTick();
|
||||
expect(findEESecurityTabSlot().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does display when a slot is passed in', async () => {
|
||||
createWrapperWithoutApollo({
|
||||
clusterAgent: defaultClusterAgent,
|
||||
slots: {
|
||||
'ee-security-tab': `<gl-tab data-testid="ee-security-tab">Security Tab!</gl-tab>`,
|
||||
},
|
||||
});
|
||||
await nextTick();
|
||||
expect(findEESecurityTabSlot().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlTab, GlTabs } from '@gitlab/ui';
|
||||
import App from '~/google_cloud/components/app.vue';
|
||||
import IncubationBanner from '~/google_cloud/components/incubation_banner.vue';
|
||||
import ServiceAccounts from '~/google_cloud/components/service_accounts.vue';
|
||||
|
||||
describe('google_cloud App component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findIncubationBanner = () => wrapper.findComponent(IncubationBanner);
|
||||
const findTabs = () => wrapper.findComponent(GlTabs);
|
||||
const findTabItems = () => findTabs().findAllComponents(GlTab);
|
||||
const findConfigurationTab = () => findTabItems().at(0);
|
||||
const findDeploymentTab = () => findTabItems().at(1);
|
||||
const findServicesTab = () => findTabItems().at(2);
|
||||
const findServiceAccounts = () => findConfigurationTab().findComponent(ServiceAccounts);
|
||||
|
||||
beforeEach(() => {
|
||||
const propsData = {
|
||||
serviceAccounts: [{}, {}],
|
||||
createServiceAccountUrl: '#url-create-service-account',
|
||||
emptyIllustrationUrl: '#url-empty-illustration',
|
||||
};
|
||||
wrapper = shallowMount(App, { propsData });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('should contain incubation banner', () => {
|
||||
expect(findIncubationBanner().exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('google_cloud App tabs', () => {
|
||||
it('should contain tabs', () => {
|
||||
expect(findTabs().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should contain three tab items', () => {
|
||||
expect(findTabItems().length).toBe(3);
|
||||
});
|
||||
|
||||
describe('configuration tab', () => {
|
||||
it('should exist', () => {
|
||||
expect(findConfigurationTab().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should contain service accounts component', () => {
|
||||
expect(findServiceAccounts().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deployments tab', () => {
|
||||
it('should exist', () => {
|
||||
expect(findDeploymentTab().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('services tab', () => {
|
||||
it('should exist', () => {
|
||||
expect(findServicesTab().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,60 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { GlAlert, GlLink } from '@gitlab/ui';
|
||||
import IncubationBanner from '~/google_cloud/components/incubation_banner.vue';
|
||||
|
||||
describe('IncubationBanner component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findLinks = () => wrapper.findAllComponents(GlLink);
|
||||
const findFeatureRequestLink = () => findLinks().at(0);
|
||||
const findReportBugLink = () => findLinks().at(1);
|
||||
const findShareFeedbackLink = () => findLinks().at(2);
|
||||
|
||||
beforeEach(() => {
|
||||
const propsData = {
|
||||
shareFeedbackUrl: 'url_general_feedback',
|
||||
reportBugUrl: 'url_report_bug',
|
||||
featureRequestUrl: 'url_feature_request',
|
||||
};
|
||||
wrapper = mount(IncubationBanner, { propsData });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('contains alert', () => {
|
||||
expect(findAlert().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('contains relevant text', () => {
|
||||
expect(findAlert().text()).toContain(
|
||||
'This is an experimental feature developed by GitLab Incubation Engineering.',
|
||||
);
|
||||
});
|
||||
|
||||
describe('has relevant gl-links', () => {
|
||||
it('three in total', () => {
|
||||
expect(findLinks().length).toBe(3);
|
||||
});
|
||||
|
||||
it('contains feature request link', () => {
|
||||
const link = findFeatureRequestLink();
|
||||
expect(link.text()).toBe('request a feature');
|
||||
expect(link.attributes('href')).toBe('url_feature_request');
|
||||
});
|
||||
|
||||
it('contains report bug link', () => {
|
||||
const link = findReportBugLink();
|
||||
expect(link.text()).toBe('report a bug');
|
||||
expect(link.attributes('href')).toBe('url_report_bug');
|
||||
});
|
||||
|
||||
it('contains share feedback link', () => {
|
||||
const link = findShareFeedbackLink();
|
||||
expect(link.text()).toBe('share feedback');
|
||||
expect(link.attributes('href')).toBe('url_general_feedback');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,79 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { GlButton, GlEmptyState, GlTable } from '@gitlab/ui';
|
||||
import ServiceAccounts from '~/google_cloud/components/service_accounts.vue';
|
||||
|
||||
describe('ServiceAccounts component', () => {
|
||||
describe('when the project does not have any service accounts', () => {
|
||||
let wrapper;
|
||||
|
||||
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
const findButtonInEmptyState = () => findEmptyState().findComponent(GlButton);
|
||||
|
||||
beforeEach(() => {
|
||||
const propsData = {
|
||||
list: [],
|
||||
createUrl: '#create-url',
|
||||
emptyIllustrationUrl: '#empty-illustration-url',
|
||||
};
|
||||
wrapper = mount(ServiceAccounts, { propsData });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('shows the empty state component', () => {
|
||||
expect(findEmptyState().exists()).toBe(true);
|
||||
});
|
||||
it('shows the link to create new service accounts', () => {
|
||||
const button = findButtonInEmptyState();
|
||||
expect(button.exists()).toBe(true);
|
||||
expect(button.text()).toBe('Create service account');
|
||||
expect(button.attributes('href')).toBe('#create-url');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when three service accounts are passed via props', () => {
|
||||
let wrapper;
|
||||
|
||||
const findTitle = () => wrapper.find('h2');
|
||||
const findDescription = () => wrapper.find('p');
|
||||
const findTable = () => wrapper.findComponent(GlTable);
|
||||
const findRows = () => findTable().findAll('tr');
|
||||
const findButton = () => wrapper.findComponent(GlButton);
|
||||
|
||||
beforeEach(() => {
|
||||
const propsData = {
|
||||
list: [{}, {}, {}],
|
||||
createUrl: '#create-url',
|
||||
emptyIllustrationUrl: '#empty-illustration-url',
|
||||
};
|
||||
wrapper = mount(ServiceAccounts, { propsData });
|
||||
});
|
||||
|
||||
it('shows the title', () => {
|
||||
expect(findTitle().text()).toBe('Service Accounts');
|
||||
});
|
||||
|
||||
it('shows the description', () => {
|
||||
expect(findDescription().text()).toBe(
|
||||
'Service Accounts keys authorize GitLab to deploy your Google Cloud project',
|
||||
);
|
||||
});
|
||||
|
||||
it('shows the table', () => {
|
||||
expect(findTable().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('table must have three rows + header row', () => {
|
||||
expect(findRows().length).toBe(4);
|
||||
});
|
||||
|
||||
it('shows the link to create new service accounts', () => {
|
||||
const button = findButton();
|
||||
expect(button.exists()).toBe(true);
|
||||
expect(button.text()).toBe('Create service account');
|
||||
expect(button.attributes('href')).toBe('#create-url');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -27,6 +27,7 @@ exports[`VersionRow renders 1`] = `
|
|||
>
|
||||
<span
|
||||
class="gl-truncate"
|
||||
data-testid="truncate-end-container"
|
||||
title="@gitlab-org/package-15"
|
||||
>
|
||||
<span
|
||||
|
|
|
@ -71,10 +71,10 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
|
|||
</code>
|
||||
</p>
|
||||
|
||||
<gl-form-textarea-stub
|
||||
<gl-form-input-stub
|
||||
id="confirm_name_input"
|
||||
name="confirm_name_input"
|
||||
noresize="true"
|
||||
type="text"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -51,10 +51,10 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
|
|||
</code>
|
||||
</p>
|
||||
|
||||
<gl-form-textarea-stub
|
||||
<gl-form-input-stub
|
||||
id="confirm_name_input"
|
||||
name="confirm_name_input"
|
||||
noresize="true"
|
||||
type="text"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -268,7 +268,7 @@ RSpec.describe ProjectsHelper do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#link_to_set_password' do
|
||||
describe '#no_password_message' do
|
||||
let(:user) { create(:user, password_automatically_set: true) }
|
||||
|
||||
before do
|
||||
|
@ -276,18 +276,18 @@ RSpec.describe ProjectsHelper do
|
|||
end
|
||||
|
||||
context 'password authentication is enabled for Git' do
|
||||
it 'returns link to set a password' do
|
||||
it 'returns message prompting user to set password or set up a PAT' do
|
||||
stub_application_setting(password_authentication_enabled_for_git?: true)
|
||||
|
||||
expect(helper.link_to_set_password).to match %r{<a href="#{edit_profile_password_path}">set a password</a>}
|
||||
expect(helper.no_password_message).to eq('Your account is authenticated with SSO or SAML. To <a href="/help/gitlab-basics/start-using-git#pull-and-push" target="_blank" rel="noopener noreferrer">push and pull</a> over HTTP with Git using this account, you must <a href="/-/profile/password/edit">set a password</a> or <a href="/-/profile/personal_access_tokens">set up a Personal Access Token</a> to use instead of a password. For more information, see <a href="/help/gitlab-basics/start-using-git#clone-with-https" target="_blank" rel="noopener noreferrer">Clone with HTTPS</a>.')
|
||||
end
|
||||
end
|
||||
|
||||
context 'password authentication is disabled for Git' do
|
||||
it 'returns link to create a personal access token' do
|
||||
it 'returns message prompting user to set up a PAT' do
|
||||
stub_application_setting(password_authentication_enabled_for_git?: false)
|
||||
|
||||
expect(helper.link_to_set_password).to match %r{<a href="#{profile_personal_access_tokens_path}">create a personal access token</a>}
|
||||
expect(helper.no_password_message).to eq('Your account is authenticated with SSO or SAML. To <a href="/help/gitlab-basics/start-using-git#pull-and-push" target="_blank" rel="noopener noreferrer">push and pull</a> over HTTP with Git using this account, you must <a href="/-/profile/personal_access_tokens">set up a Personal Access Token</a> to use instead of a password. For more information, see <a href="/help/gitlab-basics/start-using-git#clone-with-https" target="_blank" rel="noopener noreferrer">Clone with HTTPS</a>.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -987,8 +987,8 @@ RSpec.describe ProjectsHelper do
|
|||
describe "#delete_confirm_phrase" do
|
||||
subject { helper.delete_confirm_phrase(project) }
|
||||
|
||||
it 'includes the project full name' do
|
||||
expect(subject).to eq("Delete #{project.full_name}")
|
||||
it 'includes the project path with namespace' do
|
||||
expect(subject).to eq(project.path_with_namespace)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe BulkImports::Groups::Graphql::GetMilestonesQuery do
|
||||
it 'has a valid query' do
|
||||
tracker = create(:bulk_import_tracker)
|
||||
context = BulkImports::Pipeline::Context.new(tracker)
|
||||
|
||||
query = GraphQL::Query.new(
|
||||
GitlabSchema,
|
||||
described_class.to_s,
|
||||
variables: described_class.variables(context)
|
||||
)
|
||||
result = GitlabSchema.static_validator.validate(query)
|
||||
|
||||
expect(result[:errors]).to be_empty
|
||||
end
|
||||
|
||||
describe '#data_path' do
|
||||
it 'returns data path' do
|
||||
expected = %w[data group milestones nodes]
|
||||
|
||||
expect(described_class.data_path).to eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#page_info_path' do
|
||||
it 'returns pagination information path' do
|
||||
expected = %w[data group milestones page_info]
|
||||
|
||||
expect(described_class.page_info_path).to eq(expected)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -49,6 +49,36 @@ RSpec.describe Gitlab::BackgroundMigration::FixMergeRequestDiffCommitUsers do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#process' do
|
||||
it 'processes the merge requests of the project' do
|
||||
project = create(:project, :repository)
|
||||
commit = project.commit
|
||||
mr = create(
|
||||
:merge_request_with_diffs,
|
||||
source_project: project,
|
||||
target_project: project
|
||||
)
|
||||
|
||||
diff = mr.merge_request_diffs.first
|
||||
|
||||
create(
|
||||
:merge_request_diff_commit,
|
||||
merge_request_diff: diff,
|
||||
sha: commit.sha,
|
||||
relative_order: 9000
|
||||
)
|
||||
|
||||
migration.process(project)
|
||||
|
||||
updated = diff
|
||||
.merge_request_diff_commits
|
||||
.find_by(sha: commit.sha, relative_order: 9000)
|
||||
|
||||
expect(updated.commit_author_id).not_to be_nil
|
||||
expect(updated.committer_id).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_commit' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:mr) do
|
||||
|
|
|
@ -379,6 +379,22 @@ RSpec.describe CommitStatus do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.retried_ordered' do
|
||||
subject { described_class.retried_ordered.to_a }
|
||||
|
||||
let!(:statuses) do
|
||||
[create_status(name: 'aa', ref: 'bb', status: 'running', retried: true),
|
||||
create_status(name: 'cc', ref: 'cc', status: 'pending', retried: true),
|
||||
create_status(name: 'aa', ref: 'cc', status: 'success', retried: true),
|
||||
create_status(name: 'cc', ref: 'bb', status: 'success'),
|
||||
create_status(name: 'aa', ref: 'bb', status: 'success')]
|
||||
end
|
||||
|
||||
it 'returns retried statuses in order' do
|
||||
is_expected.to eq(statuses.values_at(2, 0, 1))
|
||||
end
|
||||
end
|
||||
|
||||
describe '.running_or_pending' do
|
||||
subject { described_class.running_or_pending.order(:id) }
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ RSpec.describe User do
|
|||
include ProjectForksHelper
|
||||
include TermsHelper
|
||||
include ExclusiveLeaseHelpers
|
||||
include LdapHelpers
|
||||
|
||||
it_behaves_like 'having unique enum values'
|
||||
|
||||
|
@ -5808,7 +5809,7 @@ RSpec.describe User do
|
|||
end
|
||||
|
||||
describe '#active_for_authentication?' do
|
||||
subject { user.active_for_authentication? }
|
||||
subject(:active_for_authentication?) { user.active_for_authentication? }
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
|
@ -5818,6 +5819,14 @@ RSpec.describe User do
|
|||
end
|
||||
|
||||
it { is_expected.to be false }
|
||||
|
||||
it 'does not check if LDAP is allowed' do
|
||||
stub_ldap_setting(enabled: true)
|
||||
|
||||
expect(Gitlab::Auth::Ldap::Access).not_to receive(:allowed?)
|
||||
|
||||
active_for_authentication?
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is a ghost user' do
|
||||
|
@ -5828,6 +5837,28 @@ RSpec.describe User do
|
|||
it { is_expected.to be false }
|
||||
end
|
||||
|
||||
context 'when user is ldap_blocked' do
|
||||
before do
|
||||
user.ldap_block
|
||||
end
|
||||
|
||||
it 'rechecks if LDAP is allowed when LDAP is enabled' do
|
||||
stub_ldap_setting(enabled: true)
|
||||
|
||||
expect(Gitlab::Auth::Ldap::Access).to receive(:allowed?)
|
||||
|
||||
active_for_authentication?
|
||||
end
|
||||
|
||||
it 'does not check if LDAP is allowed when LDAP is not enabled' do
|
||||
stub_ldap_setting(enabled: false)
|
||||
|
||||
expect(Gitlab::Auth::Ldap::Access).not_to receive(:allowed?)
|
||||
|
||||
active_for_authentication?
|
||||
end
|
||||
end
|
||||
|
||||
context 'based on user type' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -904,20 +904,20 @@
|
|||
stylelint-declaration-strict-value "1.7.7"
|
||||
stylelint-scss "3.18.0"
|
||||
|
||||
"@gitlab/svgs@1.219.0":
|
||||
version "1.219.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.219.0.tgz#82735876b98bd3a46f42b4a424b45086ed48e7ac"
|
||||
integrity sha512-UOy0+6A6PTbjNHLFBc70ATYztsiQfWHPORgPGnzugYJz2F7ewMr4p6R8d9avFqMNtVB5mIHSnbrsr0pp0XVMGA==
|
||||
"@gitlab/svgs@1.220.0":
|
||||
version "1.220.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.220.0.tgz#188bdefe86cdbf8be1faa7a92dbac31c728066c7"
|
||||
integrity sha512-9QRXQG6IrQoviU86g2Y4l19yE81UyEg/iMoGetMfUdQ64NW6unLN7uNbUaO1ws1J0p7uG0dKwR6ohD7tEUPLFA==
|
||||
|
||||
"@gitlab/tributejs@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
|
||||
integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
|
||||
|
||||
"@gitlab/ui@32.31.0":
|
||||
version "32.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.31.0.tgz#e379f79f0797c98d67e121739add8dec8281a5d4"
|
||||
integrity sha512-a/03Jgh3TJx0W1lJjsYZiAKbRQHGvomrGhzDvBpxKve2FXrYdo4G6gbwlIKJGiooB5YmZ5OIWhgnhQ8FSy15Aw==
|
||||
"@gitlab/ui@32.33.0":
|
||||
version "32.33.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.33.0.tgz#387c0c0fc515a44b8d115a1da1903e84233fbaaf"
|
||||
integrity sha512-wmyfRMEQ4ZQLCR4FS7fkCY1FCNX6amPyZYYzCZTV52NMtKlgaxczB7YkY1ufdtg5ctmI2NcQNkRGbdW3Et0Riw==
|
||||
dependencies:
|
||||
"@babel/standalone" "^7.0.0"
|
||||
bootstrap-vue "2.20.1"
|
||||
|
|
Loading…
Reference in New Issue