Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
ad4dfa2eb4
commit
bd091da6d5
2
Gemfile
2
Gemfile
|
@ -398,7 +398,7 @@ group :development, :test do
|
|||
end
|
||||
|
||||
group :development, :test, :danger do
|
||||
gem 'gitlab-dangerfiles', '~> 2.10.1', require: false
|
||||
gem 'gitlab-dangerfiles', '~> 2.10.2', require: false
|
||||
end
|
||||
|
||||
group :development, :test, :coverage do
|
||||
|
|
|
@ -463,7 +463,7 @@ GEM
|
|||
terminal-table (~> 1.5, >= 1.5.1)
|
||||
gitlab-chronic (0.10.5)
|
||||
numerizer (~> 0.2)
|
||||
gitlab-dangerfiles (2.10.1)
|
||||
gitlab-dangerfiles (2.10.2)
|
||||
danger (>= 8.3.1)
|
||||
danger-gitlab (>= 8.0.0)
|
||||
gitlab-experiment (0.7.0)
|
||||
|
@ -1478,7 +1478,7 @@ DEPENDENCIES
|
|||
gitaly (~> 14.8.0.pre.rc1)
|
||||
github-markup (~> 1.7.0)
|
||||
gitlab-chronic (~> 0.10.5)
|
||||
gitlab-dangerfiles (~> 2.10.1)
|
||||
gitlab-dangerfiles (~> 2.10.2)
|
||||
gitlab-experiment (~> 0.7.0)
|
||||
gitlab-fog-azure-rm (~> 1.2.0)
|
||||
gitlab-labkit (~> 0.22.0)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { s__, __ } from '~/locale';
|
||||
|
||||
export const integrationLevels = {
|
||||
PROJECT: 'project',
|
||||
GROUP: 'group',
|
||||
INSTANCE: 'instance',
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ import { GlButton, GlModalDirective, GlSafeHtmlDirective as SafeHtml, GlForm } f
|
|||
import axios from 'axios';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import { mapState, mapActions, mapGetters } from 'vuex';
|
||||
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import {
|
||||
I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE,
|
||||
|
@ -41,10 +42,8 @@ export default {
|
|||
SafeHtml,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
inject: {
|
||||
helpHtml: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
@ -81,28 +80,28 @@ export default {
|
|||
disableButtons() {
|
||||
return Boolean(this.isSaving || this.isResetting || this.isTesting);
|
||||
},
|
||||
form() {
|
||||
return this.$refs.integrationForm.$el;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['setOverride', 'requestJiraIssueTypes']),
|
||||
form() {
|
||||
return this.$refs.integrationForm.$el;
|
||||
},
|
||||
setIsValidated() {
|
||||
this.isValidated = true;
|
||||
},
|
||||
onSaveClick() {
|
||||
this.isSaving = true;
|
||||
|
||||
if (this.integrationActive && !this.form.checkValidity()) {
|
||||
if (this.integrationActive && !this.form().checkValidity()) {
|
||||
this.isSaving = false;
|
||||
this.setIsValidated();
|
||||
return;
|
||||
}
|
||||
|
||||
this.form.submit();
|
||||
this.form().submit();
|
||||
},
|
||||
onTestClick() {
|
||||
if (!this.form.checkValidity()) {
|
||||
if (!this.form().checkValidity()) {
|
||||
this.setIsValidated();
|
||||
return;
|
||||
}
|
||||
|
@ -147,7 +146,7 @@ export default {
|
|||
this.requestJiraIssueTypes(this.getFormData());
|
||||
},
|
||||
getFormData() {
|
||||
return new FormData(this.form);
|
||||
return new FormData(this.form());
|
||||
},
|
||||
onToggleIntegrationState(integrationActive) {
|
||||
this.integrationActive = integrationActive;
|
||||
|
|
|
@ -116,13 +116,13 @@ export default function initIntegrationSettingsForm() {
|
|||
|
||||
return new Vue({
|
||||
el: customSettingsEl,
|
||||
name: 'IntegrationEditRoot',
|
||||
store: createStore(initialState),
|
||||
render(createElement) {
|
||||
return createElement(IntegrationForm, {
|
||||
props: {
|
||||
provide: {
|
||||
helpHtml,
|
||||
},
|
||||
});
|
||||
render(createElement) {
|
||||
return createElement(IntegrationForm);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import { integrationLevels } from '~/integrations/constants';
|
||||
|
||||
export const isInheriting = (state) => (state.defaultState === null ? false : !state.override);
|
||||
|
||||
export const isProjectLevel = (state) =>
|
||||
state.customState.integrationLevel === integrationLevels.PROJECT;
|
||||
|
||||
export const propsSource = (state, getters) =>
|
||||
getters.isInheriting ? state.defaultState : state.customState;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import setupToggleButtons from '~/toggle_buttons';
|
||||
import { initToggle } from '~/toggles';
|
||||
|
||||
function updateVisibility(selector, isVisible) {
|
||||
Array.from(document.querySelectorAll(selector)).forEach((el) => {
|
||||
|
@ -11,12 +11,12 @@ function updateVisibility(selector, isVisible) {
|
|||
}
|
||||
|
||||
export default () => {
|
||||
const toggleContainer = document.querySelector('.js-auto-ssl-toggle-container');
|
||||
const sslToggle = initToggle(document.querySelector('.js-enable-ssl-gl-toggle'));
|
||||
const sslToggleInput = document.querySelector('.js-project-feature-toggle-input');
|
||||
|
||||
if (toggleContainer) {
|
||||
const onToggleButtonClicked = (isAutoSslEnabled) => {
|
||||
if (sslToggle) {
|
||||
sslToggle.$on('change', (isAutoSslEnabled) => {
|
||||
updateVisibility('.js-shown-unless-auto-ssl', !isAutoSslEnabled);
|
||||
|
||||
updateVisibility('.js-shown-if-auto-ssl', isAutoSslEnabled);
|
||||
|
||||
Array.from(document.querySelectorAll('.js-enabled-unless-auto-ssl')).forEach((el) => {
|
||||
|
@ -26,8 +26,9 @@ export default () => {
|
|||
el.removeAttribute('disabled');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setupToggleButtons(toggleContainer, onToggleButtonClicked);
|
||||
sslToggleInput.setAttribute('value', isAutoSslEnabled);
|
||||
});
|
||||
}
|
||||
return sslToggle;
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ import { EDITOR_READY_EVENT } from '~/editor/constants';
|
|||
import { CiSchemaExtension } from '~/editor/extensions/source_editor_ci_schema_ext';
|
||||
import SourceEditor from '~/vue_shared/components/source_editor.vue';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { SOURCE_EDITOR_DEBOUNCE } from '../../constants';
|
||||
|
||||
export default {
|
||||
editorOptions: {
|
||||
|
@ -10,6 +11,7 @@ export default {
|
|||
// autocomplete for keywords
|
||||
quickSuggestions: true,
|
||||
},
|
||||
debounceValue: SOURCE_EDITOR_DEBOUNCE,
|
||||
components: {
|
||||
SourceEditor,
|
||||
},
|
||||
|
@ -34,6 +36,7 @@ export default {
|
|||
<div class="gl-border-solid gl-border-gray-100 gl-border-1 gl-border-t-none!">
|
||||
<source-editor
|
||||
ref="editor"
|
||||
:debounce-value="$options.debounceValue"
|
||||
:editor-options="$options.editorOptions"
|
||||
:file-name="ciConfigPath"
|
||||
v-bind="$attrs"
|
||||
|
|
|
@ -47,6 +47,7 @@ export const DRAWER_EXPANDED_KEY = 'pipeline_editor_drawer_expanded';
|
|||
|
||||
export const BRANCH_PAGINATION_LIMIT = 20;
|
||||
export const BRANCH_SEARCH_DEBOUNCE = '500';
|
||||
export const SOURCE_EDITOR_DEBOUNCE = 500;
|
||||
|
||||
export const STARTER_TEMPLATE_NAME = 'Getting-Started';
|
||||
|
||||
|
|
|
@ -8,16 +8,12 @@ export const initToggle = (el) => {
|
|||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
name,
|
||||
isChecked,
|
||||
disabled,
|
||||
isLoading,
|
||||
label,
|
||||
help,
|
||||
labelPosition,
|
||||
...dataset
|
||||
} = el.dataset;
|
||||
const { name, id, isChecked, disabled, isLoading, label, help, labelPosition, ...dataset } =
|
||||
el.dataset || {};
|
||||
|
||||
const dataAttrs = Object.fromEntries(
|
||||
Object.entries(dataset).map(([key, value]) => [`data-${kebabCase(key)}`, value]),
|
||||
);
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
|
@ -50,9 +46,7 @@ export const initToggle = (el) => {
|
|||
labelPosition,
|
||||
},
|
||||
class: el.className,
|
||||
attrs: Object.fromEntries(
|
||||
Object.entries(dataset).map(([key, value]) => [`data-${kebabCase(key)}`, value]),
|
||||
),
|
||||
attrs: { id, ...dataAttrs },
|
||||
on: {
|
||||
change: (newValue) => {
|
||||
this.value = newValue;
|
||||
|
|
|
@ -46,6 +46,11 @@ export default {
|
|||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
debounceValue: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: CONTENT_UPDATE_DEBOUNCE,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -73,9 +78,7 @@ export default {
|
|||
...this.editorOptions,
|
||||
});
|
||||
|
||||
this.editor.onDidChangeModelContent(
|
||||
debounce(this.onFileChange.bind(this), CONTENT_UPDATE_DEBOUNCE),
|
||||
);
|
||||
this.editor.onDidChangeModelContent(debounce(this.onFileChange.bind(this), this.debounceValue));
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.editor.dispose();
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
- lets_encrypt_link_start = "<a href=\"%{lets_encrypt_link_url}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-nowrap\">".html_safe % { lets_encrypt_link_url: lets_encrypt_link_url }
|
||||
- lets_encrypt_link_end = "</a>".html_safe
|
||||
= _("Automatic certificate management using %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}").html_safe % { lets_encrypt_link_start: lets_encrypt_link_start, lets_encrypt_link_end: lets_encrypt_link_end }
|
||||
%button{ type: "button", id: "pages_domain_auto_ssl_enabled_button",
|
||||
class: "js-project-feature-toggle project-feature-toggle mt-2 #{"is-checked" if auto_ssl_available_and_enabled}",
|
||||
"aria-label": _("Automatic certificate management using Let's Encrypt") }
|
||||
= render "shared/gl_toggle",
|
||||
id: "pages_domain_auto_ssl_enabled_button",
|
||||
is_checked: auto_ssl_available_and_enabled,
|
||||
classes: "js-project-feature-toggle js-enable-ssl-gl-toggle mt-2",
|
||||
label: _("Automatic certificate management using Let's Encrypt"),
|
||||
label_position: 'hidden'
|
||||
= f.hidden_field :auto_ssl_enabled?, class: "js-project-feature-toggle-input"
|
||||
%span.toggle-icon
|
||||
= sprite_icon("status_success_borderless", size: 18, css_class: "gl-text-blue-500 toggle-status-checked")
|
||||
= sprite_icon("status_failed_borderless", size: 18, css_class: "gl-text-gray-400 toggle-status-unchecked")
|
||||
%p.text-secondary.mt-3
|
||||
%p.gl-text-secondary.gl-mt-1
|
||||
- docs_link_url = help_page_path("user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md")
|
||||
- docs_link_start = "<a href=\"%{docs_link_url}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-nowrap\">".html_safe % { docs_link_url: docs_link_url }
|
||||
- docs_link_end = "</a>".html_safe
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
- classes = local_assigns.fetch(:classes)
|
||||
- name = local_assigns.fetch(:name, nil)
|
||||
- id = local_assigns.fetch(:id, nil)
|
||||
- is_checked = local_assigns.fetch(:is_checked, false).to_s
|
||||
- disabled = local_assigns.fetch(:disabled, false).to_s
|
||||
- is_loading = local_assigns.fetch(:is_loading, false).to_s
|
||||
|
@ -13,6 +14,7 @@
|
|||
|
||||
%span{ class: classes,
|
||||
data: { name: name,
|
||||
id: id,
|
||||
is_checked: is_checked,
|
||||
disabled: disabled,
|
||||
is_loading: is_loading,
|
||||
|
|
|
@ -19,4 +19,4 @@ return if product_intelligence_paths_to_review.empty? || product_intelligence.sk
|
|||
|
||||
warn format(CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(product_intelligence_paths_to_review)) unless product_intelligence.has_approved_label?
|
||||
|
||||
helper.labels_to_add.merge(labels_to_add) unless labels_to_add.empty?
|
||||
helper.labels_to_add.concat(labels_to_add) unless labels_to_add.empty?
|
||||
|
|
|
@ -26,4 +26,4 @@ labels_to_add = helper.changes_by_category.each_with_object([]) do |(category, _
|
|||
memo << label
|
||||
end
|
||||
|
||||
helper.labels_to_add.merge(labels_to_add) if labels_to_add.any?
|
||||
helper.labels_to_add.concat(labels_to_add) if labels_to_add.any?
|
||||
|
|
|
@ -80,4 +80,3 @@
|
|||
image_url: https://about.gitlab.com/images/home/kubernetes.png
|
||||
published_at: 2021-01-22
|
||||
release: 13.8
|
||||
|
||||
|
|
|
@ -120,4 +120,3 @@
|
|||
image_url: https://about.gitlab.com/images/13_9/deploy_keys.png
|
||||
published_at: 2021-02-22
|
||||
release: 13.9
|
||||
|
||||
|
|
|
@ -57,4 +57,3 @@
|
|||
image_url: https://about.gitlab.com/images/14_4/monitor-integrated-error-tracking.png
|
||||
published_at: 2021-10-22
|
||||
release: 14.4
|
||||
|
||||
|
|
|
@ -39,4 +39,3 @@
|
|||
image_url: https://about.gitlab.com/images/14_7/group_access_token.png
|
||||
published_at: 2022-01-22
|
||||
release: 14.7
|
||||
|
||||
|
|
|
@ -89,4 +89,3 @@
|
|||
image_url: 'https://about.gitlab.com/images/14_8/rp_roadmap_settings.png'
|
||||
published_at: 2022-02-22
|
||||
release: 14.8
|
||||
|
|
@ -124,8 +124,8 @@ NOTE:
|
|||
This is applicable to all the projects that use the [`gitlab-dangerfiles` gem](https://rubygems.org/gems/gitlab-dangerfiles).
|
||||
|
||||
Danger is often used to improve MR hygiene by adding labels. Instead of calling the
|
||||
API directly in your `Dangerfile`, add the labels to `helper.labels_to_add` set (with `helper.labels_to_add << label`
|
||||
or `helper.labels_to_add.merge(array_of_labels)`.
|
||||
API directly in your `Dangerfile`, add the labels to `helper.labels_to_add` array (with `helper.labels_to_add << label`
|
||||
or `helper.labels_to_add.concat(array_of_labels)`.
|
||||
`gitlab-dangerfiles` will then take care of adding the labels to the MR with a single API call after all the rules
|
||||
have had the chance to add to `helper.labels_to_add`.
|
||||
|
||||
|
|
|
@ -4,43 +4,50 @@ group: Integrations
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Microsoft Azure OAuth 2.0 OmniAuth Provider **(FREE SELF)**
|
||||
# Use Microsoft Azure as an authentication provider **(FREE SELF)**
|
||||
|
||||
You can enable the Microsoft Azure OAuth 2.0 OmniAuth provider and sign in to
|
||||
GitLab with your Microsoft Azure credentials. You can configure the provider that uses
|
||||
[the earlier Azure Active Directory v1.0 endpoint](https://docs.microsoft.com/en-us/azure/active-directory/azuread-dev/v1-protocols-oauth-code),
|
||||
or the provider that uses the v2.0 endpoint.
|
||||
|
||||
NOTE:
|
||||
Per Microsoft, this provider uses the [older Azure Active Directory v1.0 endpoint](https://docs.microsoft.com/en-us/azure/active-directory/azuread-dev/v1-protocols-oauth-code).
|
||||
Microsoft documentation suggests that you should use the [OpenID Connect protocol to use the v2 endpoints](../administration/auth/oidc.md#microsoft-azure) for new projects.
|
||||
To use v2 endpoints via OmniAuth, please follow [Microsoft Azure OAuth 2.0 OmniAuth Provider v2 instructions](#microsoft-azure-oauth-20-omniauth-provider-v2).
|
||||
For new projects, Microsoft suggests you use the
|
||||
[OpenID Connect protocol](../administration/auth/oidc.md#microsoft-azure),
|
||||
which uses the Microsoft identity platform (v2.0) endpoint.
|
||||
|
||||
## Register an Azure application
|
||||
|
||||
To enable the Microsoft Azure OAuth 2.0 OmniAuth provider, you must register
|
||||
your application with Azure. Azure generates a client ID and secret key for you
|
||||
to use.
|
||||
an Azure application and get a client ID and secret key.
|
||||
|
||||
Sign in to the [Azure Portal](https://portal.azure.com), and follow the
|
||||
instructions in the [Microsoft Quickstart documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app).
|
||||
|
||||
As you go through the Microsoft procedure, keep the following in mind:
|
||||
|
||||
- If you have multiple instances of Azure Active Directory, you can switch to the desired tenant.
|
||||
- You're setting up a Web application.
|
||||
- The redirect URI requires the URL of the Azure OAuth callback of your GitLab
|
||||
1. Sign in to the [Azure portal](https://portal.azure.com).
|
||||
1. If you have multiple Azure Active Directory tenants, switch to the desired tenant.
|
||||
1. [Register an application](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app)
|
||||
and provide the following information:
|
||||
- The redirect URI, which requires the URL of the Azure OAuth callback of your GitLab
|
||||
installation. For example, `https://gitlab.mycompany.com/users/auth/azure_oauth2/callback`.
|
||||
The type dropdown should be set to **Web**.
|
||||
- The `client ID` and `client secret` are terms associated with OAuth 2.0. In some Microsoft documentation,
|
||||
the terms may be listed as `Application ID` and `Application Secret`.
|
||||
- If you have to generate a new client secret, follow the Microsoft documentation
|
||||
for [creating a new application secret](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#create-a-new-application-secret).
|
||||
- Save the client ID and client secret for your new app, as the client secret is only
|
||||
displayed one time.
|
||||
- The application type, which must be set to **Web**.
|
||||
1. Save the client ID and client secret. The client secret is only
|
||||
displayed once.
|
||||
|
||||
If required, you can [create a new application secret](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#option-2-create-a-new-application-secret).
|
||||
|
||||
`client ID` and `client secret` are terms associated with OAuth 2.0.
|
||||
In some Microsoft documentation, the terms are named `Application ID` and
|
||||
`Application Secret`.
|
||||
|
||||
## Enable Microsoft OAuth in GitLab
|
||||
|
||||
1. On your GitLab server, open the configuration file.
|
||||
|
||||
For Omnibus GitLab:
|
||||
- **For Omnibus installations**
|
||||
|
||||
```shell
|
||||
sudo editor /etc/gitlab/gitlab.rb
|
||||
```
|
||||
|
||||
For installations from source:
|
||||
- **For installations from source**
|
||||
|
||||
```shell
|
||||
cd /home/git/gitlab
|
||||
|
@ -48,12 +55,12 @@ As you go through the Microsoft procedure, keep the following in mind:
|
|||
sudo -u git -H editor config/gitlab.yml
|
||||
```
|
||||
|
||||
1. Refer to [Configure initial settings](omniauth.md#configure-initial-settings)
|
||||
for initial settings.
|
||||
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
|
||||
|
||||
1. Add the provider configuration:
|
||||
1. Add the provider configuration. Replace `CLIENT ID`, `CLIENT SECRET`, and `TENANT ID`
|
||||
with the values you got when you registered the Azure application.
|
||||
|
||||
For Omnibus GitLab:
|
||||
- **For Omnibus installations**
|
||||
|
||||
```ruby
|
||||
gitlab_rails['omniauth_providers'] = [
|
||||
|
@ -69,7 +76,7 @@ As you go through the Microsoft procedure, keep the following in mind:
|
|||
]
|
||||
```
|
||||
|
||||
For installations from source:
|
||||
- **For installations from source**
|
||||
|
||||
```yaml
|
||||
- { name: 'azure_oauth2',
|
||||
|
@ -79,27 +86,22 @@ As you go through the Microsoft procedure, keep the following in mind:
|
|||
tenant_id: 'TENANT ID' } }
|
||||
```
|
||||
|
||||
The `base_azure_url` is optional and can be added for different locales;
|
||||
such as `base_azure_url: "https://login.microsoftonline.de"`.
|
||||
|
||||
1. Replace `CLIENT ID`, `CLIENT SECRET` and `TENANT ID` with the values you got above.
|
||||
You can optionally add `base_azure_url` for different locales,
|
||||
for example, `base_azure_url: "https://login.microsoftonline.de"`.
|
||||
|
||||
1. Save the configuration file.
|
||||
|
||||
1. Reconfigure or restart GitLab, depending on your installation method:
|
||||
1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
if you installed using Omnibus, or [restart GitLab](../administration/restart_gitlab.md#installations-from-source)
|
||||
if you installed from source.
|
||||
|
||||
- *If you installed from Omnibus GitLab,*
|
||||
[reconfigure](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) GitLab.
|
||||
- *If you installed from source,*
|
||||
[restart GitLab](../administration/restart_gitlab.md#installations-from-source).
|
||||
1. Refresh the GitLab sign-in page. A Microsoft icon should display below the
|
||||
sign-in form.
|
||||
|
||||
On the sign-in page, you should now see a Microsoft icon below the regular
|
||||
sign-in form. Click the icon to begin the authentication process. Microsoft then
|
||||
asks you to sign in and authorize the GitLab application. If successful, you are
|
||||
returned to GitLab and signed in.
|
||||
1. Select the icon. Sign in to Microsoft and authorize the GitLab application.
|
||||
|
||||
Read [Enable OmniAuth for an Existing User](omniauth.md#enable-omniauth-for-an-existing-user)
|
||||
for information on how existing GitLab users can connect to their newly-available Azure AD accounts.
|
||||
Read [Enable OmniAuth for an existing user](omniauth.md#enable-omniauth-for-an-existing-user)
|
||||
for information on how existing GitLab users can connect to their new Azure AD accounts.
|
||||
|
||||
## Microsoft Azure OAuth 2.0 OmniAuth Provider v2
|
||||
|
||||
|
|
|
@ -217,13 +217,3 @@ add a to-do item:
|
|||
![Alert Details Add a to do](img/alert_detail_add_todo_v13_9.png)
|
||||
|
||||
To view your To-Do List, on the top bar, select **To-Do List** (**{todo-done}**).
|
||||
|
||||
## View the environment that generated the alert
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/232492) in GitLab 13.5 behind a feature flag, disabled by default.
|
||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/232492) in GitLab 13.6.
|
||||
|
||||
WARNING:
|
||||
This feature might not be available to you. Check the **version history** note above for details.
|
||||
|
||||
The environment information and the link are displayed in the [Alert Details tab](#alert-details-tab).
|
||||
|
|
|
@ -95,7 +95,7 @@ RSpec.describe 'User adds pages domain', :js do
|
|||
|
||||
fill_in 'Domain', with: 'my.test.domain.com'
|
||||
|
||||
find('.js-auto-ssl-toggle-container .project-feature-toggle').click
|
||||
find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click
|
||||
|
||||
fill_in 'Certificate (PEM)', with: certificate_pem
|
||||
fill_in 'Key (PEM)', with: certificate_key
|
||||
|
|
|
@ -50,7 +50,7 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do
|
|||
expect(page).to have_selector '.card-header', text: 'Certificate'
|
||||
expect(page).to have_text domain.subject
|
||||
|
||||
find('.js-auto-ssl-toggle-container .project-feature-toggle').click
|
||||
find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click
|
||||
|
||||
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true'
|
||||
expect(page).not_to have_selector '.card-header', text: 'Certificate'
|
||||
|
@ -74,7 +74,7 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do
|
|||
expect(page).not_to have_field 'Certificate (PEM)', type: 'textarea'
|
||||
expect(page).not_to have_field 'Key (PEM)', type: 'textarea'
|
||||
|
||||
find('.js-auto-ssl-toggle-container .project-feature-toggle').click
|
||||
find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click
|
||||
|
||||
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false'
|
||||
expect(page).to have_field 'Certificate (PEM)', type: 'textarea'
|
||||
|
|
|
@ -37,7 +37,7 @@ describe('IntegrationForm', () => {
|
|||
const createComponent = ({
|
||||
customStateProps = {},
|
||||
initialState = {},
|
||||
props = {},
|
||||
provide = {},
|
||||
mountFn = shallowMountExtended,
|
||||
} = {}) => {
|
||||
const store = createStore({
|
||||
|
@ -47,7 +47,7 @@ describe('IntegrationForm', () => {
|
|||
dispatch = jest.spyOn(store, 'dispatch').mockImplementation();
|
||||
|
||||
wrapper = mountFn(IntegrationForm, {
|
||||
propsData: { ...props },
|
||||
provide,
|
||||
store,
|
||||
stubs: {
|
||||
OverrideDropdown,
|
||||
|
@ -300,7 +300,7 @@ describe('IntegrationForm', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('with `helpHtml` prop', () => {
|
||||
describe('with `helpHtml` provided', () => {
|
||||
const mockTestId = 'jest-help-html-test';
|
||||
|
||||
setHTMLFixture(`
|
||||
|
@ -316,7 +316,7 @@ describe('IntegrationForm', () => {
|
|||
const mockHelpHtml = document.querySelector(`[data-testid="${mockTestId}"]`);
|
||||
|
||||
createComponent({
|
||||
props: {
|
||||
provide: {
|
||||
helpHtml: mockHelpHtml.outerHTML,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ export const mockIntegrationProps = {
|
|||
fields: [],
|
||||
type: '',
|
||||
inheritFromId: 25,
|
||||
integrationLevel: 'project',
|
||||
};
|
||||
|
||||
export const mockJiraIssueTypes = [
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import { currentKey, isInheriting, propsSource } from '~/integrations/edit/store/getters';
|
||||
import {
|
||||
currentKey,
|
||||
isInheriting,
|
||||
isProjectLevel,
|
||||
propsSource,
|
||||
} from '~/integrations/edit/store/getters';
|
||||
|
||||
import createState from '~/integrations/edit/store/state';
|
||||
import { integrationLevels } from '~/integrations/constants';
|
||||
import { mockIntegrationProps } from '../mock_data';
|
||||
|
||||
describe('Integration form store getters', () => {
|
||||
|
@ -45,6 +52,18 @@ describe('Integration form store getters', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('isProjectLevel', () => {
|
||||
it.each`
|
||||
integrationLevel | expected
|
||||
${integrationLevels.PROJECT} | ${true}
|
||||
${integrationLevels.GROUP} | ${false}
|
||||
${integrationLevels.INSTANCE} | ${false}
|
||||
`('when integrationLevel is `$integrationLevel`', ({ integrationLevel, expected }) => {
|
||||
state.customState.integrationLevel = integrationLevel;
|
||||
expect(isProjectLevel(state)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('propsSource', () => {
|
||||
beforeEach(() => {
|
||||
state.defaultState = defaultState;
|
||||
|
|
|
@ -58,7 +58,6 @@ describe('Incident Tabs component', () => {
|
|||
const findTabs = () => wrapper.findAll(GlTab);
|
||||
const findSummaryTab = () => findTabs().at(0);
|
||||
const findMetricsTab = () => wrapper.find('[data-testid="metrics-tab"]');
|
||||
const findTimelineTab = () => wrapper.find('[data-testid="timeline-events-tab"]');
|
||||
const findAlertDetailsTab = () => wrapper.find('[data-testid="alert-details-tab"]');
|
||||
const findAlertDetailsComponent = () => wrapper.find(AlertDetailsTable);
|
||||
const findDescriptionComponent = () => wrapper.find(DescriptionComponent);
|
||||
|
@ -74,29 +73,6 @@ describe('Incident Tabs component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('incident timeline tab', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('renders the timeline tab when feature flag is enabled', () => {
|
||||
expect(findTimelineTab().exists()).toBe(true);
|
||||
expect(findTimelineTab().attributes('title')).toBe('Timeline');
|
||||
});
|
||||
|
||||
it('does not render timeline tab when feature flag is disabled', () => {
|
||||
mountComponent({}, { provide: { glFeatures: { incidentTimelineEventTab: false } } });
|
||||
|
||||
expect(findTimelineTab().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not render timeline tab when not available in license', () => {
|
||||
mountComponent({}, { provide: { glFeatures: { incidentTimelineEvents: false } } });
|
||||
|
||||
expect(findTimelineTab().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with an alert present', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import initForm from '~/pages/projects/pages_domains/form';
|
||||
|
||||
const ENABLED_UNLESS_AUTO_SSL_CLASS = 'js-enabled-unless-auto-ssl';
|
||||
const SSL_TOGGLE_CLASS = 'js-enable-ssl-gl-toggle';
|
||||
const SSL_TOGGLE_INPUT_CLASS = 'js-project-feature-toggle-input';
|
||||
const SHOW_IF_AUTO_SSL_CLASS = 'js-shown-if-auto-ssl';
|
||||
const SHOW_UNLESS_AUTO_SSL_CLASS = 'js-shown-unless-auto-ssl';
|
||||
const D_NONE_CLASS = 'd-none';
|
||||
|
||||
describe('Page domains form', () => {
|
||||
let toggle;
|
||||
|
||||
const findEnabledUnless = () => document.querySelector(`.${ENABLED_UNLESS_AUTO_SSL_CLASS}`);
|
||||
const findSslToggle = () => document.querySelector(`.${SSL_TOGGLE_CLASS} button`);
|
||||
const findSslToggleInput = () => document.querySelector(`.${SSL_TOGGLE_INPUT_CLASS}`);
|
||||
const findIfAutoSsl = () => document.querySelector(`.${SHOW_IF_AUTO_SSL_CLASS}`);
|
||||
const findUnlessAutoSsl = () => document.querySelector(`.${SHOW_UNLESS_AUTO_SSL_CLASS}`);
|
||||
|
||||
const create = () => {
|
||||
setFixtures(`
|
||||
<form>
|
||||
<span
|
||||
class="${SSL_TOGGLE_CLASS}"
|
||||
data-label="SSL toggle"
|
||||
></span>
|
||||
<input class="${SSL_TOGGLE_INPUT_CLASS}" type="hidden" />
|
||||
<span class="${SHOW_UNLESS_AUTO_SSL_CLASS}"></span>
|
||||
<span class="${SHOW_IF_AUTO_SSL_CLASS}"></span>
|
||||
<button class="${ENABLED_UNLESS_AUTO_SSL_CLASS}"></button>
|
||||
</form>
|
||||
`);
|
||||
};
|
||||
|
||||
it('instantiates the toggle', () => {
|
||||
create();
|
||||
initForm();
|
||||
|
||||
expect(findSslToggle()).not.toBe(null);
|
||||
});
|
||||
|
||||
describe('when auto SSL is enabled', () => {
|
||||
beforeEach(() => {
|
||||
create();
|
||||
toggle = initForm();
|
||||
toggle.$emit('change', true);
|
||||
});
|
||||
|
||||
it('sets the correct classes', () => {
|
||||
expect(Array.from(findIfAutoSsl().classList)).not.toContain(D_NONE_CLASS);
|
||||
expect(Array.from(findUnlessAutoSsl().classList)).toContain(D_NONE_CLASS);
|
||||
});
|
||||
|
||||
it('sets the correct disabled value', () => {
|
||||
expect(findEnabledUnless().getAttribute('disabled')).toBe('disabled');
|
||||
});
|
||||
|
||||
it('sets the correct value for the input', () => {
|
||||
expect(findSslToggleInput().getAttribute('value')).toBe('true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when auto SSL is not enabled', () => {
|
||||
beforeEach(() => {
|
||||
create();
|
||||
toggle = initForm();
|
||||
toggle.$emit('change', false);
|
||||
});
|
||||
|
||||
it('sets the correct classes', () => {
|
||||
expect(Array.from(findIfAutoSsl().classList)).toContain(D_NONE_CLASS);
|
||||
expect(Array.from(findUnlessAutoSsl().classList)).not.toContain(D_NONE_CLASS);
|
||||
});
|
||||
|
||||
it('sets the correct disabled value', () => {
|
||||
expect(findUnlessAutoSsl().getAttribute('disabled')).toBe(null);
|
||||
});
|
||||
|
||||
it('sets the correct value for the input', () => {
|
||||
expect(findSslToggleInput().getAttribute('value')).toBe('false');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
|
||||
import { EDITOR_READY_EVENT } from '~/editor/constants';
|
||||
import { SOURCE_EDITOR_DEBOUNCE } from '~/pipeline_editor/constants';
|
||||
import TextEditor from '~/pipeline_editor/components/editor/text_editor.vue';
|
||||
import {
|
||||
mockCiConfigPath,
|
||||
|
@ -22,7 +23,7 @@ describe('Pipeline Editor | Text editor component', () => {
|
|||
|
||||
const MockSourceEditor = {
|
||||
template: '<div/>',
|
||||
props: ['value', 'fileName'],
|
||||
props: ['value', 'fileName', 'editorOptions', 'debounceValue'],
|
||||
};
|
||||
|
||||
const createComponent = (glFeatures = {}, mountFn = shallowMount) => {
|
||||
|
@ -90,6 +91,14 @@ describe('Pipeline Editor | Text editor component', () => {
|
|||
expect(findEditor().props('fileName')).toBe(mockCiConfigPath);
|
||||
});
|
||||
|
||||
it('passes down editor configs options', () => {
|
||||
expect(findEditor().props('editorOptions')).toEqual({ quickSuggestions: true });
|
||||
});
|
||||
|
||||
it('passes down editor debounce value', () => {
|
||||
expect(findEditor().props('debounceValue')).toBe(SOURCE_EDITOR_DEBOUNCE);
|
||||
});
|
||||
|
||||
it('bubbles up events', () => {
|
||||
findEditor().vm.$emit(EDITOR_READY_EVENT, editorInstanceDetail);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ exports[`Snippet Blob Edit component with loaded blob matches snapshot 1`] = `
|
|||
/>
|
||||
|
||||
<source-editor-stub
|
||||
debouncevalue="250"
|
||||
editoroptions="[object Object]"
|
||||
fileglobalid="blob_local_7"
|
||||
filename="foo/bar/test.md"
|
||||
|
|
|
@ -99,10 +99,12 @@ describe('toggles/index.js', () => {
|
|||
const name = 'toggle-name';
|
||||
const help = 'Help text';
|
||||
const foo = 'bar';
|
||||
const id = 'an-id';
|
||||
|
||||
beforeEach(() => {
|
||||
initToggleWithOptions({
|
||||
name,
|
||||
id,
|
||||
isChecked: true,
|
||||
disabled: true,
|
||||
isLoading: true,
|
||||
|
@ -144,6 +146,10 @@ describe('toggles/index.js', () => {
|
|||
it('passes custom dataset to the wrapper', () => {
|
||||
expect(toggleWrapper.dataset.foo).toBe('bar');
|
||||
});
|
||||
|
||||
it('passes an id to the wrapper', () => {
|
||||
expect(toggleWrapper.id).toBe(id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue