Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-01-27 21:11:27 +00:00
parent 9beaa68169
commit 936139e69c
112 changed files with 670 additions and 1747 deletions

View File

@ -43,9 +43,9 @@
.rules:dont-interrupt:
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
- if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_IID == null'
allow_failure: true
- if: $CI_MERGE_REQUEST_IID
- if: '$CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached"'
when: manual
allow_failure: true

View File

@ -8,7 +8,7 @@
# No specific specs in mr pipeline
.all-specs-mr: &all-specs-mr
if: $CI_MERGE_REQUEST_IID && $QA_TESTS == ""
if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $QA_TESTS == ""'
when: manual
# Triggered by change pattern

View File

@ -21,7 +21,7 @@
if: '$FORCE_GITLAB_CI'
.if-default-refs: &if-default-refs
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_COMMIT_REF_NAME == "ruby2" || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_COMMIT_REF_NAME == "ruby2" || ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
.if-default-branch-refs: &if-default-branch-refs
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_IID == null'
@ -30,33 +30,33 @@
if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
.if-default-branch-or-tag: &if-default-branch-or-tag
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_TAG'
if: '($CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_IID == null) || $CI_COMMIT_TAG'
.if-tag: &if-tag
if: '$CI_COMMIT_TAG'
.if-merge-request: &if-merge-request
if: '$CI_MERGE_REQUEST_IID'
if: '$CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached"'
# Once https://gitlab.com/gitlab-org/gitlab/-/issues/373904 is implemented, we should be able to change this back to
# if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_APPROVALS_COUNT > 0'
# if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_APPROVALS_COUNT > 0'
# or any similar condition to check that the MR has *any* approval (not just required approval).
#
# Temprorarily adding || $CI_MERGE_REQUEST_LABELS =~ /pipeline:run-full-rspec/ for backward compatibility,
# remove once https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/1557 is fully rolled out
.if-merge-request-approved: &if-merge-request-approved
if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_LABELS =~ /pipeline:mr-approved/ || $CI_MERGE_REQUEST_LABELS =~ /pipeline:run-full-rspec/'
if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS =~ /pipeline:mr-approved/ || $CI_MERGE_REQUEST_LABELS =~ /pipeline:run-full-rspec/'
# Temprorarily adding && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-full-rspec/ for backward compatibility,
# remove once https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/1557 is fully rolled out
.if-merge-request-not-approved: &if-merge-request-not-approved
if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_LABELS !~ /pipeline:mr-approved/ && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-full-rspec/'
if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS !~ /pipeline:mr-approved/ && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-full-rspec/'
.if-automated-merge-request: &if-automated-merge-request
if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "release-tools/update-gitaly" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /stable-ee$/'
.if-merge-request-targeting-stable-branch: &if-merge-request-targeting-stable-branch
if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee)?$/'
if: '($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee)?$/'
.if-merge-request-labels-run-in-ruby2: &if-merge-request-labels-run-in-ruby2
if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-in-ruby2/'
@ -104,10 +104,10 @@
if: '$CI_MERGE_REQUEST_LABELS =~ /frontend/ && $CI_MERGE_REQUEST_LABELS =~ /feature flag/'
.if-security-merge-request: &if-security-merge-request
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID'
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached")'
.if-fork-merge-request: &if-fork-merge-request
if: '$CI_PROJECT_NAMESPACE !~ /^gitlab(-org)?($|\/)/ && $CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-all-rspec/'
if: '$CI_PROJECT_NAMESPACE !~ /^gitlab(-org)?($|\/)/ && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_LABELS !~ /pipeline:run-all-rspec/'
.if-schedule-pipeline: &if-schedule-pipeline
if: '$CI_PIPELINE_SOURCE == "schedule"'
@ -140,16 +140,16 @@
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH'
.if-dot-com-gitlab-org-merge-request: &if-dot-com-gitlab-org-merge-request
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_MERGE_REQUEST_IID'
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached")'
.if-dot-com-gitlab-org-and-security-merge-request: &if-dot-com-gitlab-org-and-security-merge-request
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && $CI_MERGE_REQUEST_IID'
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached")'
.if-dot-com-gitlab-org-and-security-merge-request-and-qa-tests-specified: &if-dot-com-gitlab-org-and-security-merge-request-and-qa-tests-specified
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && $CI_MERGE_REQUEST_IID && $QA_TESTS'
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $QA_TESTS'
.if-dot-com-gitlab-org-and-security-merge-request-manual-ff-package-and-e2e: &if-dot-com-gitlab-org-and-security-merge-request-manual-ff-package-and-e2e
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && $CI_MERGE_REQUEST_IID && $QA_MANUAL_FF_PACKAGE_AND_QA'
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $QA_MANUAL_FF_PACKAGE_AND_QA'
.if-dot-com-gitlab-org-and-security-tag: &if-dot-com-gitlab-org-and-security-tag
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/security$)/ && $CI_COMMIT_TAG'
@ -1062,7 +1062,7 @@
- <<: *if-default-branch-refs
changes: *frontend-build-patterns
allow_failure: true
- if: '$DANGER_GITLAB_API_TOKEN && $CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
- if: '$DANGER_GITLAB_API_TOKEN && ($CI_MERGE_REQUEST_EVENT_TYPE == "merged_result" || $CI_MERGE_REQUEST_EVENT_TYPE == "detached") && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
changes: *frontend-build-patterns
allow_failure: true

View File

@ -14,6 +14,7 @@ import {
GlModal,
GlSprintf,
} from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { getCookie, setCookie } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import Tracking from '~/tracking';
@ -31,6 +32,7 @@ import {
EVENT_ACTION,
EXPANDED_VARIABLES_NOTE,
EDIT_VARIABLE_ACTION,
FLAG_LINK_TITLE,
VARIABLE_ACTIONS,
variableOptions,
} from '../constants';
@ -41,13 +43,6 @@ import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
const trackingMixin = Tracking.mixin({ label: EVENT_LABEL });
export default {
modalId: ADD_CI_VARIABLE_MODAL_ID,
tokens: awsTokens,
tokenList: awsTokenList,
awsTipMessage: AWS_TIP_MESSAGE,
containsVariableReferenceMessage: CONTAINS_VARIABLE_REFERENCE_MESSAGE,
environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE,
expandedVariablesNote: EXPANDED_VARIABLES_NOTE,
components: {
CiEnvironmentsDropdown,
GlAlert,
@ -75,7 +70,6 @@ export default {
'isProtectedByDefault',
'maskedEnvironmentVariablesLink',
'maskableRegex',
'protectedEnvironmentVariablesLink',
],
props: {
areScopedVariablesAvailable: {
@ -273,7 +267,20 @@ export default {
this.validationErrorEventProperty = '';
},
},
defaultScope: allEnvironments.text,
i18n: {
awsTipMessage: AWS_TIP_MESSAGE,
containsVariableReferenceMessage: CONTAINS_VARIABLE_REFERENCE_MESSAGE,
defaultScope: allEnvironments.text,
environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE,
expandedVariablesNote: EXPANDED_VARIABLES_NOTE,
flagsLinkTitle: FLAG_LINK_TITLE,
},
flagLink: helpPagePath('ci/variables/index', {
anchor: 'define-a-cicd-variable-in-the-ui',
}),
modalId: ADD_CI_VARIABLE_MODAL_ID,
tokens: awsTokens,
tokenList: awsTokenList,
variableOptions,
};
</script>
@ -340,15 +347,20 @@ export default {
data-testid="environment-scope"
>
<template #label>
{{ __('Environment scope') }}
<gl-link
:title="$options.environmentScopeLinkTitle"
:href="environmentScopeLink"
target="_blank"
data-testid="environment-scope-link"
>
<gl-icon name="question" :size="12" />
</gl-link>
<div class="gl-display-flex gl-align-items-center">
<span class="gl-mr-2">
{{ __('Environment scope') }}
</span>
<gl-link
class="gl-display-flex"
:title="$options.i18n.environmentScopeLinkTitle"
:href="environmentScopeLink"
target="_blank"
data-testid="environment-scope-link"
>
<gl-icon name="question-o" :size="14" />
</gl-link>
</div>
</template>
<ci-environments-dropdown
v-if="areScopedVariablesAvailable"
@ -358,12 +370,27 @@ export default {
@create-environment-scope="createEnvironmentScope"
/>
<gl-form-input v-else :value="$options.defaultScope" class="gl-w-full" readonly />
<gl-form-input v-else :value="$options.i18n.defaultScope" class="gl-w-full" readonly />
</gl-form-group>
</template>
</div>
<gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
<gl-form-group>
<template #label>
<div class="gl-display-flex gl-align-items-center">
<span class="gl-mr-2">
{{ __('Flags') }}
</span>
<gl-link
class="gl-display-flex"
:title="$options.i18n.flagsLinkTitle"
:href="$options.flagLink"
target="_blank"
>
<gl-icon name="question-o" :size="14" />
</gl-link>
</div>
</template>
<gl-form-checkbox
v-model="variable.protected"
class="gl-mb-0"
@ -371,9 +398,6 @@ export default {
:data-is-protected-checked="variable.protected"
>
{{ __('Protect variable') }}
<gl-link target="_blank" :href="protectedEnvironmentVariablesLink">
<gl-icon name="question" :size="12" />
</gl-link>
<p class="gl-mt-2 text-secondary">
{{ __('Export variable to pipelines running on protected branches and tags only.') }}
</p>
@ -384,9 +408,6 @@ export default {
data-testid="ci-variable-masked-checkbox"
>
{{ __('Mask variable') }}
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">
<gl-icon name="question" :size="12" />
</gl-link>
<p class="gl-mt-2 text-secondary">
{{ __('Variable will be masked in job logs.') }}
<span
@ -397,7 +418,7 @@ export default {
{{ __('Requires values to meet regular expression requirements.') }}</span
>
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">{{
__('More information')
__('Learn more.')
}}</gl-link>
</p>
</gl-form-checkbox>
@ -408,11 +429,8 @@ export default {
@change="setVariableRaw"
>
{{ __('Expand variable reference') }}
<gl-link target="_blank" :href="containsVariableReferenceLink">
<gl-icon name="question" :size="12" />
</gl-link>
<p class="gl-mt-2 gl-mb-0 gl-text-secondary">
<gl-sprintf :message="$options.expandedVariablesNote">
<gl-sprintf :message="$options.i18n.expandedVariablesNote">
<template #code="{ content }">
<code>{{ content }}</code>
</template>
@ -431,7 +449,7 @@ export default {
<div class="gl-display-flex gl-flex-direction-row gl-flex-wrap-wrap gl-md-flex-wrap-nowrap">
<div>
<p>
<gl-sprintf :message="$options.awsTipMessage">
<gl-sprintf :message="$options.i18n.awsTipMessage">
<template #deployLink="{ content }">
<gl-link :href="awsTipDeployLink" target="_blank">{{ content }}</gl-link>
</template>
@ -467,7 +485,7 @@ export default {
variant="warning"
data-testid="contains-variable-reference"
>
<gl-sprintf :message="$options.containsVariableReferenceMessage">
<gl-sprintf :message="$options.i18n.containsVariableReferenceMessage">
<template #code="{ content }">
<code>{{ content }}</code>
</template>

View File

@ -72,14 +72,14 @@ export const AWS_TOKEN_CONSTANTS = [AWS_ACCESS_KEY_ID, AWS_DEFAULT_REGION, AWS_S
export const CONTAINS_VARIABLE_REFERENCE_MESSAGE = __(
'Unselect "Expand variable reference" if you want to use the variable value as a raw string.',
);
export const DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT = s__(
'CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables.',
);
export const ENVIRONMENT_SCOPE_LINK_TITLE = __('Learn more');
export const EXCEEDS_VARIABLE_LIMIT_TEXT = s__(
'CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables.',
);
export const DEFAULT_EXCEEDS_VARIABLE_LIMIT_TEXT = s__(
'CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables.',
);
export const FLAG_LINK_TITLE = s__('CiVariable|Define a CI/CD variable in the UI');
export const MAXIMUM_VARIABLE_LIMIT_REACHED = s__(
'CiVariables|Maximum number of variables reached.',
);

View File

@ -25,7 +25,6 @@ const mountCiVariableListApp = (containerEl) => {
projectFullPath,
projectId,
protectedByDefault,
protectedEnvironmentVariablesLink,
} = containerEl.dataset;
const parsedIsProject = parseBoolean(isProject);
@ -66,7 +65,6 @@ const mountCiVariableListApp = (containerEl) => {
maskableRegex,
projectFullPath,
projectId,
protectedEnvironmentVariablesLink,
},
render(createElement) {
return createElement(component);

View File

@ -1,10 +1,9 @@
<script>
import { mapGetters, mapState } from 'vuex';
import { mapState } from 'vuex';
import { __ } from '~/locale';
import { rightSidebarViews, SIDEBAR_INIT_WIDTH, SIDEBAR_NAV_WIDTH } from '../../constants';
import JobsDetail from '../jobs/detail.vue';
import PipelinesList from '../pipelines/list.vue';
import Clientside from '../preview/clientside.vue';
import ResizablePanel from '../resizable_panel.vue';
import TerminalView from '../terminal/view.vue';
import CollapsibleSidebar from './collapsible_sidebar.vue';
@ -20,12 +19,8 @@ export default {
},
computed: {
...mapState('terminal', { isTerminalVisible: 'isVisible' }),
...mapState(['currentMergeRequestId', 'clientsidePreviewEnabled']),
...mapGetters(['packageJson']),
...mapState(['currentMergeRequestId']),
...mapState('rightPane', ['isOpen']),
showLivePreview() {
return this.packageJson && this.clientsidePreviewEnabled;
},
rightExtensionTabs() {
return [
{
@ -37,12 +32,6 @@ export default {
],
icon: 'rocket',
},
{
show: this.showLivePreview,
title: __('Live preview'),
views: [{ component: Clientside, ...rightSidebarViews.clientSidePreview }],
icon: 'live-preview',
},
{
show: this.isTerminalVisible,
title: __('Terminal'),

View File

@ -1,191 +0,0 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import { listen } from 'codesandbox-api';
import { isEmpty, debounce } from 'lodash';
import { SandpackClient } from '@codesandbox/sandpack-client';
import { mapActions, mapGetters, mapState } from 'vuex';
import {
packageJsonPath,
LIVE_PREVIEW_DEBOUNCE,
PING_USAGE_PREVIEW_KEY,
PING_USAGE_PREVIEW_SUCCESS_KEY,
} from '../../constants';
import eventHub from '../../eventhub';
import { createPathWithExt } from '../../utils';
import Navigator from './navigator.vue';
export default {
components: {
Navigator,
GlLoadingIcon,
},
data() {
return {
client: {},
loading: false,
sandpackReady: false,
};
},
computed: {
...mapState(['entries', 'promotionSvgPath', 'links', 'codesandboxBundlerUrl']),
...mapGetters(['packageJson', 'currentProject']),
normalizedEntries() {
return Object.keys(this.entries).reduce((acc, path) => {
const file = this.entries[path];
if (file.type === 'tree' || !(file.raw || file.content)) return acc;
return {
...acc,
[`/${path}`]: {
code: file.content || file.raw,
},
};
}, {});
},
mainEntry() {
if (!this.packageJson.raw) return false;
const parsedPackage = JSON.parse(this.packageJson.raw);
return parsedPackage.main;
},
showPreview() {
return this.mainEntry && !this.loading;
},
showEmptyState() {
return !this.mainEntry && !this.loading;
},
showOpenInCodeSandbox() {
return this.currentProject && this.currentProject.visibility === 'public';
},
sandboxOpts() {
return {
files: { ...this.normalizedEntries },
entry: `/${this.mainEntry}`,
showOpenInCodeSandbox: this.showOpenInCodeSandbox,
};
},
},
watch: {
sandpackReady: {
handler(val) {
if (val) {
this.pingUsage(PING_USAGE_PREVIEW_SUCCESS_KEY);
}
},
},
},
mounted() {
this.onFilesChangeCallback = debounce(() => this.update(), LIVE_PREVIEW_DEBOUNCE);
eventHub.$on('ide.files.change', this.onFilesChangeCallback);
this.loading = true;
return this.loadFileContent(packageJsonPath)
.then(() => {
this.loading = false;
})
.then(() => this.$nextTick())
.then(() => this.initPreview());
},
beforeDestroy() {
// Setting sandpackReady = false protects us form a phantom `update()` being called when `debounce` finishes.
this.sandpackReady = false;
eventHub.$off('ide.files.change', this.onFilesChangeCallback);
if (!isEmpty(this.client)) {
this.client.cleanup();
}
this.client = {};
if (this.listener) {
this.listener();
}
},
methods: {
...mapActions(['getFileData', 'getRawFileData']),
...mapActions('clientside', ['pingUsage']),
loadFileContent(path) {
return this.getFileData({ path, makeFileActive: false }).then(() =>
this.getRawFileData({ path }),
);
},
initPreview() {
if (!this.mainEntry) return null;
this.pingUsage(PING_USAGE_PREVIEW_KEY);
return this.loadFileContent(this.mainEntry)
.then(() => this.$nextTick())
.then(() => {
this.initClient();
this.listener = listen((e) => {
switch (e.type) {
case 'done':
this.sandpackReady = true;
break;
default:
break;
}
});
});
},
update() {
if (!this.sandpackReady) return;
if (isEmpty(this.client)) {
this.initPreview();
return;
}
this.client.updatePreview(this.sandboxOpts);
},
initClient() {
const { codesandboxBundlerUrl: bundlerURL } = this;
const settings = {
fileResolver: {
isFile: (p) => Promise.resolve(Boolean(this.entries[createPathWithExt(p)])),
readFile: (p) => this.loadFileContent(createPathWithExt(p)).then((content) => content),
},
...(bundlerURL ? { bundlerURL } : {}),
};
this.client = new SandpackClient('#ide-preview', this.sandboxOpts, settings);
},
},
};
</script>
<template>
<div class="preview h-100 w-100 d-flex flex-column gl-bg-white">
<template v-if="showPreview">
<navigator :client="client" />
<div id="ide-preview"></div>
</template>
<div
v-else-if="showEmptyState"
v-once
class="d-flex h-100 flex-column align-items-center justify-content-center svg-content"
>
<img :src="promotionSvgPath" :alt="s__('IDE|Live Preview')" width="130" height="100" />
<h3>{{ s__('IDE|Live Preview') }}</h3>
<p class="text-center">
{{ s__('IDE|Preview your web application using Web IDE client-side evaluation.') }}
</p>
<a
:href="links.webIDEHelpPagePath"
class="btn gl-button btn-confirm"
target="_blank"
rel="noopener noreferrer"
>
{{ s__('IDE|Get started with Live Preview') }}
</a>
</div>
<gl-loading-icon v-else size="lg" class="align-self-center mt-auto mb-auto" />
</div>
</template>

View File

@ -1,136 +0,0 @@
<script>
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { listen } from 'codesandbox-api';
export default {
components: {
GlIcon,
GlLoadingIcon,
},
props: {
client: {
type: Object,
required: true,
},
},
data() {
return {
currentBrowsingIndex: null,
navigationStack: [],
forwardNavigationStack: [],
path: '',
loading: true,
};
},
computed: {
backButtonDisabled() {
return this.navigationStack.length <= 1;
},
forwardButtonDisabled() {
return !this.forwardNavigationStack.length;
},
},
mounted() {
this.listener = listen((e) => {
switch (e.type) {
case 'urlchange':
this.onUrlChange(e);
break;
case 'done':
this.loading = false;
break;
default:
break;
}
});
},
beforeDestroy() {
this.listener();
},
methods: {
onUrlChange(e) {
const lastPath = this.path;
this.path = e.url.replace(this.client.bundlerURL, '') || '/';
if (lastPath !== this.path) {
this.currentBrowsingIndex =
this.currentBrowsingIndex === null ? 0 : this.currentBrowsingIndex + 1;
this.navigationStack.push(this.path);
}
},
back() {
const lastPath = this.path;
this.visitPath(this.navigationStack[this.currentBrowsingIndex - 1]);
this.forwardNavigationStack.push(lastPath);
if (this.currentBrowsingIndex === 1) {
this.currentBrowsingIndex = null;
this.navigationStack = [];
}
},
forward() {
this.visitPath(this.forwardNavigationStack.splice(0, 1)[0]);
},
refresh() {
this.visitPath(this.path);
},
visitPath(path) {
// eslint-disable-next-line vue/no-mutating-props
this.client.iframe.src = `${this.client.bundlerURL}${path}`;
},
},
};
</script>
<template>
<header class="ide-preview-header d-flex align-items-center">
<button
:aria-label="s__('IDE|Back')"
:disabled="backButtonDisabled"
:class="{
'disabled-content': backButtonDisabled,
}"
type="button"
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
@click="back"
>
<gl-icon :size="24" name="chevron-left" class="m-auto" />
</button>
<button
:aria-label="s__('IDE|Back')"
:disabled="forwardButtonDisabled"
:class="{
'disabled-content': forwardButtonDisabled,
}"
type="button"
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
@click="forward"
>
<gl-icon :size="24" name="chevron-right" class="m-auto" />
</button>
<button
:aria-label="s__('IDE|Refresh preview')"
type="button"
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
@click="refresh"
>
<gl-icon :size="16" name="retry" class="m-auto" />
</button>
<div class="position-relative w-100 gl-ml-2">
<input
:value="path || '/'"
type="text"
class="ide-navigator-location form-control bg-white"
readonly
/>
<gl-loading-icon
v-if="loading"
size="sm"
class="position-absolute ide-preview-loading-icon"
/>
</div>
</header>
</template>

View File

@ -64,7 +64,6 @@ export const rightSidebarViews = {
pipelines: { name: 'pipelines-list', keepAlive: true },
jobsDetail: { name: 'jobs-detail', keepAlive: false },
mergeRequestInfo: { name: 'merge-request-info', keepAlive: true },
clientSidePreview: { name: 'clientside', keepAlive: false },
terminal: { name: 'terminal', keepAlive: true },
};
@ -101,22 +100,13 @@ export const commitActionTypes = {
update: 'update',
};
export const packageJsonPath = 'package.json';
export const SIDE_LEFT = 'left';
export const SIDE_RIGHT = 'right';
// Live Preview feature
export const LIVE_PREVIEW_DEBOUNCE = 2000;
// This is the maximum number of files to auto open when opening the Web IDE
// from a merge request
export const MAX_MR_FILES_AUTO_OPEN = 10;
export const DEFAULT_BRANCH = 'main';
// Ping Usage Metrics Keys
export const PING_USAGE_PREVIEW_KEY = 'web_ide_clientside_preview';
export const PING_USAGE_PREVIEW_SUCCESS_KEY = 'web_ide_clientside_preview_success';
export const GITLAB_WEB_IDE_FEEDBACK_ISSUE = 'https://gitlab.com/gitlab-org/gitlab/-/issues/377367';

View File

@ -67,10 +67,8 @@ export const initLegacyWebIDE = (el, options = {}) => {
forkInfo: el.dataset.forkInfo ? JSON.parse(el.dataset.forkInfo) : null,
});
this.init({
clientsidePreviewEnabled: parseBoolean(el.dataset.clientsidePreviewEnabled),
renderWhitespaceInCode: parseBoolean(el.dataset.renderWhitespaceInCode),
editorTheme: window.gon?.user_color_scheme || DEFAULT_THEME,
codesandboxBundlerUrl: el.dataset.codesandboxBundlerUrl,
environmentsGuidanceAlertDismissed: !parseBoolean(el.dataset.enableEnvironmentsGuidance),
previewMarkdownPath: el.dataset.previewMarkdownPath,
userPreferencesPath: el.dataset.userPreferencesPath,

View File

@ -2,7 +2,6 @@ import Api from '~/api';
import { addNumericSuffix } from '~/ide/utils';
import {
leftSidebarViews,
packageJsonPath,
DEFAULT_PERMISSIONS,
PERMISSION_READ_MR,
PERMISSION_CREATE_MR,
@ -153,8 +152,6 @@ export const currentBranch = (state, getters) =>
export const branchName = (_state, getters) => getters.currentBranch && getters.currentBranch.name;
export const packageJson = (state) => state.entries[packageJsonPath];
export const isOnDefaultBranch = (_state, getters) =>
getters.currentProject && getters.currentProject.default_branch === getters.branchName;

View File

@ -3,7 +3,6 @@ import Vuex from 'vuex';
import * as actions from './actions';
import * as getters from './getters';
import branches from './modules/branches';
import clientsideModule from './modules/clientside';
import commitModule from './modules/commit';
import editorModule from './modules/editor';
import { setupFileEditorsSync } from './modules/editor/setup';
@ -29,7 +28,6 @@ export const createStoreOptions = () => ({
branches,
fileTemplates: fileTemplates(),
rightPane: paneModule(),
clientside: clientsideModule(),
router: routerModule,
editor: editorModule,
},

View File

@ -1,11 +0,0 @@
import axios from '~/lib/utils/axios_utils';
export const pingUsage = ({ rootGetters }, metricName) => {
const { web_url: projectUrl } = rootGetters.currentProject;
const url = `${projectUrl}/service_ping/${metricName}`;
return axios.post(url);
};
export default pingUsage;

View File

@ -1,6 +0,0 @@
import * as actions from './actions';
export default () => ({
namespaced: true,
actions,
});

View File

@ -26,10 +26,8 @@ export default () => ({
path: '',
entry: {},
},
clientsidePreviewEnabled: false,
renderWhitespaceInCode: false,
editorTheme: DEFAULT_THEME,
codesandboxBundlerUrl: null,
environmentsGuidanceAlertDismissed: false,
environmentsGuidanceAlertDetected: false,
previewMarkdownPath: '',

View File

@ -27,7 +27,7 @@ export default {
},
i18n: {
signInButtonTextWithSubscriptions: s__('Integrations|Sign in to add namespaces'),
signInText: s__('JiraService|Sign in to GitLab.com to get started.'),
signInText: s__('JiraService|Sign in to GitLab to get started.'),
},
GITLAB_COM_BASE_PATH,
methods: {

View File

@ -334,7 +334,7 @@ export const timeToHoursMinutes = (time = '') => {
* @param {String} offset An optional Date-compatible offset.
* @returns {String} The combined Date's ISO string representation.
*/
export const dateAndTimeToISOString = (date, time = '00:00', offset = '') => {
export const dateAndTimeToISOString = (date, time, offset = '') => {
const { year, month, day } = dateToYearMonthDate(date);
const { hours, minutes } = timeToHoursMinutes(time);
const dateString = `${year}-${month}-${day}T${hours}:${minutes}:00.000${offset || 'Z'}`;

View File

@ -1,13 +1,11 @@
<script>
import { GlDisclosureDropdown, GlTooltipDirective } from '@gitlab/ui';
import { GlDisclosureDropdown, GlTooltip } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
directives: {
GlTooltip: GlTooltipDirective,
},
components: {
GlDisclosureDropdown,
GlTooltip,
},
i18n: {
createNew: __('Create new...'),
@ -18,17 +16,23 @@ export default {
required: true,
},
},
toggleId: 'create-menu-toggle',
};
</script>
<template>
<gl-disclosure-dropdown
v-gl-tooltip:super-sidebar.bottom="$options.i18n.createNew"
category="tertiary"
icon="plus"
:items="groups"
no-caret
text-sr-only
:toggle-text="$options.i18n.createNew"
/>
<div>
<gl-disclosure-dropdown
category="tertiary"
icon="plus"
:items="groups"
no-caret
text-sr-only
:toggle-text="$options.i18n.createNew"
:toggle-id="$options.toggleId"
/>
<gl-tooltip :target="`#${$options.toggleId}`" placement="bottom" container="#super-sidebar">
{{ $options.i18n.createNew }}
</gl-tooltip>
</div>
</template>

View File

@ -906,8 +906,7 @@ $ide-commit-header-height: 48px;
padding-bottom: 0;
}
.ide-right-sidebar-terminal,
.ide-right-sidebar-clientside {
.ide-right-sidebar-terminal {
padding: 0;
}
}
@ -1083,43 +1082,6 @@ $ide-commit-header-height: 48px;
}
}
.ide-preview-header {
padding: 0 $grid-size;
border-bottom: 1px solid var(--ide-border-color-alt, $white-dark);
background-color: var(--ide-highlight-background, $gray-light);
min-height: 44px;
}
.ide-navigator-btn {
height: 24px;
min-width: 24px;
max-width: 24px;
padding: 0;
margin: 0 ($grid-size / 2);
color: var(--ide-text-color-secondary, $gray-600);
&:first-child {
margin-left: 0;
}
}
.ide-navigator-location {
padding-top: ($grid-size / 2);
padding-bottom: ($grid-size / 2);
&:focus {
outline: 0;
box-shadow: none;
border-color: var(--ide-border-color, $gray-100);
}
}
.ide-preview-loading-icon {
right: $grid-size;
top: 50%;
transform: translateY(-50%);
}
.ide-file-templates {
padding: $grid-size $gl-padding;
background-color: var(--ide-background, $gray-light);

View File

@ -1,17 +0,0 @@
# frozen_string_literal: true
module ClientsidePreviewCSP
extend ActiveSupport::Concern
included do
content_security_policy do |p|
next if p.directives.blank?
next unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
default_frame_src = p.directives['frame-src'] || p.directives['default-src']
frame_src_values = Array.wrap(default_frame_src) | [Gitlab::CurrentSettings.web_ide_clientside_preview_bundler_url].compact
p.frame_src(*frame_src_values)
end
end
end

View File

@ -20,6 +20,7 @@ module RecordUserLastActivity
return if Gitlab::Database.read_only?
return unless current_user && current_user.last_activity_on != Date.today
Users::ActivityService.new(current_user).execute
# TODO: add namespace & project - https://gitlab.com/gitlab-org/gitlab/-/issues/387952
Users::ActivityService.new(author: current_user).execute
end
end

View File

@ -144,7 +144,8 @@ class GraphqlController < ApplicationController
def set_user_last_activity
return unless current_user
Users::ActivityService.new(current_user).execute
# TODO: add namespace & project - https://gitlab.com/gitlab-org/gitlab/-/issues/387951
Users::ActivityService.new(author: current_user).execute
end
def track_vs_code_usage

View File

@ -2,7 +2,6 @@
class IdeController < ApplicationController
include VSCodeCDNCSP
include ClientsidePreviewCSP
include StaticObjectExternalStorageCSP
include Gitlab::Utils::StrongMemoize

View File

@ -5,24 +5,6 @@ class Projects::ServicePingController < Projects::ApplicationController
feature_category :web_ide
def web_ide_clientside_preview
return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_count
head(:ok)
end
def web_ide_clientside_preview_success
return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
Gitlab::UsageDataCounters::WebIdeCounter.increment_previews_success_count
Gitlab::UsageDataCounters::EditorUniqueCounter.track_live_preview_edit_action(author: current_user,
project: project)
head(:ok)
end
def web_ide_pipelines_count
Gitlab::UsageDataCounters::WebIdeCounter.increment_pipelines_count

View File

@ -116,7 +116,7 @@ module Repositories
end
def log_user_activity
Users::ActivityService.new(user).execute
Users::ActivityService.new(author: user, project: project, namespace: project&.namespace).execute
end
end
end

View File

@ -289,7 +289,7 @@ class SessionsController < Devise::SessionsController
def log_user_activity(user)
login_counter.increment
Users::ActivityService.new(user).execute
Users::ActivityService.new(author: user).execute
end
def load_recaptcha

View File

@ -384,7 +384,6 @@ module ApplicationSettingsHelper
:user_default_internal_regex,
:user_oauth_applications,
:version_check_enabled,
:web_ide_clientside_preview_enabled,
:diff_max_patch_bytes,
:diff_max_files,
:diff_max_lines,

View File

@ -43,9 +43,7 @@ module IdeHelper
'promotion-svg-path': image_path('illustrations/web-ide_promotion.svg'),
'ci-help-page-path' => help_page_path('ci/quick_start/index'),
'web-ide-help-page-path' => help_page_path('user/project/web_ide/index.md'),
'clientside-preview-enabled': Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?.to_s,
'render-whitespace-in-code': current_user.render_whitespace_in_code.to_s,
'codesandbox-bundler-url': Gitlab::CurrentSettings.web_ide_clientside_preview_bundler_url,
'default-branch' => @project && @project.default_branch,
'project' => convert_to_project_entity_json(@project),
'enable-environments-guidance' => enable_environments_guidance?.to_s,

View File

@ -12,6 +12,7 @@ class ApplicationSetting < ApplicationRecord
ignore_columns %i[static_objects_external_storage_auth_token], remove_with: '14.9', remove_after: '2022-03-22'
ignore_column :user_email_lookup_limit, remove_with: '15.0', remove_after: '2022-04-18'
ignore_column :send_user_confirmation_email, remove_with: '15.8', remove_after: '2022-12-18'
ignore_column :web_ide_clientside_preview_enabled, remove_with: '15.11', remove_after: '2023-04-22'
INSTANCE_REVIEW_MIN_USERS = 50
GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \

View File

@ -523,12 +523,6 @@ module ApplicationSettingImplementation
static_objects_external_storage_url.present?
end
# This will eventually be configurable
# https://gitlab.com/gitlab-org/gitlab/issues/208161
def web_ide_clientside_preview_bundler_url
'https://sandbox-prod.gitlab-static.net'
end
def ensure_key_restrictions!
return if Gitlab::Database.read_only?
return unless Gitlab::FIPS.enabled?

View File

@ -245,7 +245,7 @@ class EventCreateService
Users::LastPushEventService.new(current_user)
.cache_last_push_event(event)
Users::ActivityService.new(current_user).execute
Users::ActivityService.new(author: current_user, namespace: namespace, project: project).execute
end
def create_event(resource_parent, current_user, status, attributes = {})

View File

@ -4,38 +4,56 @@ module Users
class ActivityService
LEASE_TIMEOUT = 1.minute.to_i
def initialize(author)
def initialize(author:, namespace: nil, project: nil)
@user = if author.respond_to?(:username)
author
elsif author.respond_to?(:user)
author.user
end
@user = nil unless @user.is_a?(User)
@user = nil unless user.is_a?(User)
@namespace = namespace
@project = project
end
def execute
return unless @user
return unless user
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes { record_activity }
end
private
attr_reader :user, :namespace, :project
def record_activity
return if Gitlab::Database.read_only?
today = Date.today
return if @user.last_activity_on == today
return if user.last_activity_on == today
lease = Gitlab::ExclusiveLease.new("activity_service:#{@user.id}",
lease = Gitlab::ExclusiveLease.new("activity_service:#{user.id}",
timeout: LEASE_TIMEOUT)
return unless lease.try_obtain
@user.update_attribute(:last_activity_on, today)
user.update_attribute(:last_activity_on, today)
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('unique_active_user', values: @user.id)
Gitlab::UsageDataCounters::HLLRedisCounter.track_event('unique_active_user', values: user.id)
return unless Feature.enabled?(:route_hll_to_snowplow_phase3)
Gitlab::Tracking.event(
'Users::ActivityService',
'perform_action',
user: user,
namespace: namespace,
project: project,
label: 'redis_hll_counters.manage.unique_active_users_monthly',
context: [
Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'unique_active_user').to_context
]
)
end
end
end

View File

@ -89,26 +89,6 @@
.settings-content
= render 'terminal'
%section.settings.no-animate#js-web-ide-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Web IDE')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Manage Web IDE features.')
.settings-content
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: "js-web-ide-settings"), html: { class: 'fieldset-form', id: 'web-ide-settings' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
- link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('user/project/web_ide/index', anchor: 'enable-live-preview') }
= f.gitlab_ui_checkbox_component :web_ide_clientside_preview_enabled,
s_('IDE|Live Preview'),
help_text: s_('Preview JavaScript projects in the Web IDE with CodeSandbox Live Preview. %{link_start}Learn more.%{link_end} ').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
= f.submit _('Save changes'), pajamas_button: true
= render_if_exists 'admin/application_settings/maintenance_mode_settings_form'
= render 'admin/application_settings/gitpod'
= render 'admin/application_settings/kroki'

View File

@ -24,7 +24,6 @@
aws_tip_commands_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'use-an-image-to-run-aws-commands'),
aws_tip_learn_link: help_page_path('ci/cloud_deployment/index.md'),
contains_variable_reference_link: help_page_path('ci/variables/index', anchor: 'prevent-cicd-variable-expansion'),
protected_environment_variables_link: help_page_path('ci/variables/index', anchor: 'protect-a-cicd-variable'),
masked_environment_variables_link: help_page_path('ci/variables/index', anchor: 'mask-a-cicd-variable'),
environment_scope_link: help_page_path('ci/environments/index', anchor: 'limit-the-environment-scope-of-a-cicd-variable') } }

View File

@ -0,0 +1,23 @@
---
description: User's last_activity_on gets updated
category: Users::ActivityService
action: perform_action
label_description: key_path of Service Ping metric redis_hll_counters.manage.unique_active_users_monthly
property_description:
value_description:
extra_properties:
identifiers:
product_section: dev
product_stage: manage
product_group: manage
product_category:
milestone: "15.8"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108108
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -590,8 +590,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
scope :service_ping, controller: :service_ping do
post :web_ide_clientside_preview # rubocop:todo Cop/PutProjectRoutesUnderScope
post :web_ide_clientside_preview_success # rubocop:todo Cop/PutProjectRoutesUnderScope
post :web_ide_pipelines_count # rubocop:todo Cop/PutProjectRoutesUnderScope
end

View File

@ -24,7 +24,7 @@
stage: verify # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381669 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The `POST ci/lint` API endpoint is deprecated in 15.7, and will be removed in 16.0. This endpoint does not validate the full range of CI/CD configuration options. Instead, use [`POST /projects/:id/ci/lint`](https://docs.gitlab.com/15.5/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace), which properly validates CI/CD configuration.
The `POST ci/lint` API endpoint is deprecated in 15.7, and will be removed in 16.0. This endpoint does not validate the full range of CI/CD configuration options. Instead, use [`POST /projects/:id/ci/lint`](https://docs.gitlab.com/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace), which properly validates CI/CD configuration.
#
# OPTIONAL END OF SUPPORT FIELDS
#

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class AddDeployKeyIdToCreateAccessLevels < Gitlab::Database::Migration[2.1]
def up
add_column :protected_tag_create_access_levels, :deploy_key_id, :integer
end
def down
remove_column :protected_tag_create_access_levels, :deploy_key_id
end
end

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class AddIndexForProtectedTagCreateAccessLevels < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
DEPLOY_KEY_INDEX_NAME = 'index_protected_tag_create_access_levels_on_deploy_key_id'
def up
add_concurrent_foreign_key :protected_tag_create_access_levels, :keys, column: :deploy_key_id, on_delete: :cascade
add_concurrent_index :protected_tag_create_access_levels, :deploy_key_id,
name: DEPLOY_KEY_INDEX_NAME
end
def down
remove_foreign_key_if_exists :protected_tag_create_access_levels, column: :deploy_key_id
remove_concurrent_index_by_name :protected_tag_create_access_levels, name: DEPLOY_KEY_INDEX_NAME
end
end

View File

@ -0,0 +1 @@
be87eb6052d3f853f05f59a6deb8669857047ca95d28b209b1c19c66fa96ff15

View File

@ -0,0 +1 @@
277c1abd9cc4f9fb6aca4991b7643d8b9964ef466f4d209848c90b34c8eec9c0

View File

@ -21005,7 +21005,8 @@ CREATE TABLE protected_tag_create_access_levels (
user_id integer,
group_id integer,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL
updated_at timestamp without time zone NOT NULL,
deploy_key_id integer
);
CREATE SEQUENCE protected_tag_create_access_levels_id_seq
@ -31069,6 +31070,8 @@ CREATE UNIQUE INDEX index_protected_environments_on_project_id_and_name ON prote
CREATE INDEX index_protected_tag_create_access ON protected_tag_create_access_levels USING btree (protected_tag_id);
CREATE INDEX index_protected_tag_create_access_levels_on_deploy_key_id ON protected_tag_create_access_levels USING btree (deploy_key_id);
CREATE INDEX index_protected_tag_create_access_levels_on_group_id ON protected_tag_create_access_levels USING btree (group_id);
CREATE INDEX index_protected_tag_create_access_levels_on_user_id ON protected_tag_create_access_levels USING btree (user_id);
@ -33597,6 +33600,9 @@ ALTER TABLE ONLY sprints
ALTER TABLE ONLY push_event_payloads
ADD CONSTRAINT fk_36c74129da FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE;
ALTER TABLE ONLY protected_tag_create_access_levels
ADD CONSTRAINT fk_386a642e13 FOREIGN KEY (deploy_key_id) REFERENCES keys(id) ON DELETE CASCADE;
ALTER TABLE ONLY incident_management_timeline_events
ADD CONSTRAINT fk_38a74279df FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL;

View File

@ -41,7 +41,10 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
sudo -u git -H editor /home/git/gitlab/config/gitlab.yml
```
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings) for initial settings to enable single sign-on and add `atlassian_oauth2` as an OAuth provider.
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
to add `atlassian_oauth2` as a single sign-on provider. This enables
Just-In-Time account provisioning for users who do not have an existing
GitLab account.
1. Add the provider configuration for Atlassian:
For Omnibus GitLab installations:

View File

@ -27,7 +27,9 @@ Authentiq generates a Client ID and the accompanying Client Secret for you to us
sudo -u git -H editor /home/git/gitlab/config/gitlab.yml
```
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings) for initial settings to enable single sign-on and add Authentiq as an OAuth provider.
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
to add `authentiq` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration for Authentiq:

View File

@ -41,7 +41,9 @@ To enable AWS Cognito as an authentication provider, complete the following step
## Configure GitLab
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
to add `cognito` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. On your GitLab server, open the configuration file.
**For Omnibus installations**
@ -95,4 +97,4 @@ Select this option to begin the authentication process.
AWS Cognito then asks you to sign in and authorize the GitLab application.
If the authorization is successful, you're redirected and signed in to your GitLab instance.
For more information, see [Configure initial settings](../../integration/omniauth.md#configure-initial-settings).
For more information, see [Configure common settings](../../integration/omniauth.md#configure-common-settings).

View File

@ -40,8 +40,9 @@ this provider also allows Crowd authentication for Git-over-https requests.
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings)
for initial settings.
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
to add `crowd` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration:

View File

@ -25,7 +25,9 @@ JWT provides you with a secret key for you to use.
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](../../integration/omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
to add `jwt` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration.
For Omnibus GitLab:

View File

@ -29,7 +29,9 @@ The OpenID Connect provides you with a client's details and secret for you to us
sudo -u git -H editor config/gitlab.yml
```
1. [Configure initial settings](../../integration/omniauth.md#configure-initial-settings).
1. Edit the [common configuration file settings](../../integration/omniauth.md#configure-common-settings)
to add `openid_connect` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration.
@ -254,7 +256,7 @@ Azure B2C [offers two ways of defining the business logic for logging in a user]
Custom policies are required because standard Azure B2C user flows
[do not send the OpenID `email` claim](https://github.com/MicrosoftDocs/azure-docs/issues/16566).
Therefore, the standard user flows do not work with the
[`allow_single_sign_on` or `auto_link_user` parameters](../../integration/omniauth.md#configure-initial-settings).
[`allow_single_sign_on` or `auto_link_user` parameters](../../integration/omniauth.md#configure-common-settings).
With a standard Azure B2C policy, GitLab cannot create a new account or
link to an existing account with an email address.

View File

@ -522,7 +522,6 @@ listed in the descriptions of the relevant settings.
| `user_show_add_ssh_key_message` | boolean | no | When set to `false` disable the `You won't be able to pull or push project code via SSH` warning shown to users with no uploaded SSH key. |
| `version_check_enabled` | boolean | no | Let GitLab inform you when an update is available. |
| `whats_new_variant` | string | no | What's new variant, possible values: `all_tiers`, `current_tier`, and `disabled`. |
| `web_ide_clientside_preview_enabled` | boolean | no | Live Preview (allow live previews of JavaScript projects in the Web IDE using CodeSandbox Live Preview). |
| `wiki_page_max_content_bytes` | integer | no | Maximum wiki page content size in **bytes**. Default: 52428800 Bytes (50 MB). The minimum value is 1024 bytes. |
| `jira_connect_application_key` | String | no | Application ID of the OAuth application that should be used to authenticate with the GitLab for Jira Cloud app |
| `jira_connect_proxy_url` | String | no | URL of the GitLab instance that should be used as a proxy for the GitLab for Jira Cloud app |

View File

@ -76,7 +76,7 @@ The current production [Web IDE](../../../user/project/web_ide/index.md).
An advanced editor with commit staging that currently supports:
- [Live Preview](../../../user/project/web_ide/index.md#live-preview)
- [Live Preview](../../../user/project/web_ide/index.md#live-preview-removed)
- [Interactive Web Terminals](../../../user/project/web_ide/index.md#interactive-web-terminals-for-the-web-ide)
### Web IDE

View File

@ -200,10 +200,8 @@ associated with your project, you can configure these deployments from your
`.gitlab-ci.yml` file.
NOTE:
Kubernetes configuration isn't supported for Kubernetes clusters that are
Kubernetes configuration isn't supported for Kubernetes clusters
[managed by GitLab](../../user/project/clusters/gitlab_managed_clusters.md).
To follow progress on support for GitLab-managed clusters, see the
[relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/38054).
The following configuration options are supported:

View File

@ -1780,9 +1780,7 @@ environment, using the `production`
**Additional details**:
- Kubernetes configuration is not supported for Kubernetes clusters
that are [managed by GitLab](../../user/project/clusters/gitlab_managed_clusters.md).
To follow progress on support for GitLab-managed clusters, see the
[relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/38054).
[managed by GitLab](../../user/project/clusters/gitlab_managed_clusters.md).
**Related topics**:

View File

@ -2,12 +2,17 @@
stage: none
group: Development
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
remove_date: '2023-02-01'
---
# Set up local CodeSandbox development environment
# Set up local CodeSandbox development environment (removed)
WARNING:
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108627) in GitLab 15.8
and is planned for removal in 15.9. This change is a breaking change.
This guide walks through setting up a local [CodeSandbox repository](https://github.com/codesandbox/codesandbox-client) and integrating it with a local GitLab instance. CodeSandbox
is used to power the Web IDE [Live Preview feature](../../user/project/web_ide/index.md#live-preview). Having a local CodeSandbox setup is useful for debugging upstream issues or
is used to power the Web IDE [Live Preview feature](../../user/project/web_ide/index.md#live-preview-removed). Having a local CodeSandbox setup is useful for debugging upstream issues or
creating upstream contributions like [this one](https://github.com/codesandbox/codesandbox-client/pull/5137).
## Initial setup
@ -114,7 +119,11 @@ out of the box:
npx http-server --proxy http://localhost:3000 -S -C $PATH_TO_CERT_PEM -K $PATH_TO_KEY_PEM -p 8044 -d false
```
### Update `bundler_url` setting in GitLab
### Update `bundler_url` setting in GitLab (removed)
WARNING:
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108627) in GitLab 15.8
and is planned for removal in 15.9. This change is a breaking change.
We need to update our `application_setting_implementation.rb` to point to the server that hosts the
CodeSandbox `sandpack` assets. For instance, if these assets are hosted by a server at `https://sandpack.local:8044`:

View File

@ -210,7 +210,6 @@ The following is example content of the Service Ping payload.
"prometheus_metrics_enabled": false,
"reply_by_email_enabled": "incoming+%{key}@incoming.gitlab.com",
"signup_enabled": true,
"web_ide_clientside_preview_enabled": true,
"projects_with_expiration_policy_disabled": 999,
"projects_with_expiration_policy_enabled": 999,
...

View File

@ -59,7 +59,9 @@ Sign in to the AliCloud platform and create an application on it. AliCloud gener
sudo -u git -H editor config/gitlab.yml
```
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `alicloud` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration. Replace `YOUR_APP_ID` with the ID on the application details page
and `YOUR_APP_SECRET` with the **SecretValue** you got when you registered the AliCloud application.

View File

@ -42,8 +42,9 @@ application.
sudo -u git -H editor config/gitlab.yml
```
1. Read [Configure initial settings](omniauth.md#configure-initial-settings)
for initial settings.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `auth0` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration:

View File

@ -68,7 +68,9 @@ Alternatively, add the `User.Read.All` application permission.
sudo -u git -H editor config/gitlab.yml
```
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `azure_oauth2` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration. Replace `<client_id>`, `<client_secret>`, and `<tenant_id>`
with the values you got when you registered the Azure application.

View File

@ -32,7 +32,9 @@ configure CAS for back-channel logout.
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `cas3` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration:

View File

@ -51,7 +51,9 @@ Sign in to DingTalk Open Platform and create an application on it. DingTalk gene
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `dingtalk` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration:

View File

@ -72,7 +72,9 @@ Facebook. Facebook generates an app ID and secret key for you to use.
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `facebook` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration:

View File

@ -35,7 +35,9 @@ your website could enable the covert redirect attack.
## Enable GitHub OAuth in GitLab
1. [Configure the initial settings](omniauth.md#configure-initial-settings) in GitLab.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `github` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Edit the GitLab configuration file using the following information:

View File

@ -51,7 +51,9 @@ GitLab.com generates an application ID and secret key for you to use.
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `gitlab` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration:
For Omnibus installations authenticating against **GitLab.com**:

View File

@ -71,7 +71,9 @@ On your GitLab server:
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `google_oauth2` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration:
For Omnibus GitLab:

View File

@ -99,9 +99,9 @@ to authenticate with Kerberos tokens.
#### Enable single sign-on
See [Configure initial settings](omniauth.md#configure-initial-settings)
for initial settings to enable single sign-on and add Kerberos servers
as an identity provider.
Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `kerberos` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
## Create and link Kerberos accounts
@ -138,7 +138,8 @@ with your Kerberos credentials.
The first time users sign in to GitLab with their Kerberos accounts,
GitLab creates a matching account.
Before you continue, review the [Configure initial settings](omniauth.md#configure-initial-settings) options in Omnibus and GitLab source. You must also include `kerberos`.
Before you continue, review the [common configuration settings](omniauth.md#configure-common-settings)
options in Omnibus and GitLab source. You must also include `kerberos`.
With that information at hand:

View File

@ -54,7 +54,9 @@ To configure the provider:
:::TabTitle Linux package (Omnibus)
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `oauth2_generic` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Edit `/etc/gitlab/gitlab.rb` to add the configuration for your provider. For example:
```ruby
@ -96,7 +98,9 @@ To configure the provider:
:::TabTitle Helm chart (Kubernetes)
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `oauth2_generic` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Export the Helm values:
```shell
@ -146,7 +150,9 @@ To configure the provider:
:::TabTitle Self-compiled (source)
1. [Configure the initial settings](omniauth.md#configure-initial-settings).
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `oauth2_generic` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Edit `/home/git/gitlab/config/gitlab.yml`:
```yaml

View File

@ -38,7 +38,7 @@ GitLab supports the following OmniAuth providers.
| [SAML](saml.md) | `saml` |
| [Twitter](twitter.md) | `twitter` |
## Initial settings
## Configure common settings
Before you configure the OmniAuth provider,
configure the settings that are common for all providers.
@ -503,7 +503,7 @@ There are two methods to update the `extern_uid`:
Identity.where(extern_uid: 'old-id').update!(extern_uid: 'new-id')`
```
## Limitations
## Known issues
Most supported OmniAuth providers don't support Git over HTTP password authentication.
As a workaround, you can authenticate using a [personal access token](../user/profile/personal_access_tokens.md).

View File

@ -48,7 +48,9 @@ To get the credentials (a pair of Client ID and Client Secret), you must [create
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `salesforce` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration:

View File

@ -41,7 +41,9 @@ For more information on:
sudo -u git -H editor config/gitlab.yml
```
1. Edit the initial [configuration settings](omniauth.md#configure-initial-settings).
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `saml` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. To allow your users to use SAML to sign up without having to manually create
an account first, add the following values to your configuration.

View File

@ -62,7 +62,9 @@ Twitter. Twitter generates a client ID and secret key for you to use.
sudo -u git -H editor config/gitlab.yml
```
1. See [Configure initial settings](omniauth.md#configure-initial-settings) for initial settings.
1. Edit the [common configuration file settings](omniauth.md#configure-common-settings)
to add `twitter` as a single sign-on provider. This enables Just-In-Time
account provisioning for users who do not have an existing GitLab account.
1. Add the provider configuration.

View File

@ -129,7 +129,7 @@ GitLab has several features which can help you manage the number of users:
- Enable the [**Require administrator approval for new sign ups**](../../user/admin_area/settings/sign_up_restrictions.md#require-administrator-approval-for-new-sign-ups)
option.
- Enable `block_auto_created_users` for new sign-ups via [LDAP](../../administration/auth/ldap/index.md#basic-configuration-settings) or [OmniAuth](../../integration/omniauth.md#configure-initial-settings).
- Enable `block_auto_created_users` for new sign-ups via [LDAP](../../administration/auth/ldap/index.md#basic-configuration-settings) or [OmniAuth](../../integration/omniauth.md#configure-common-settings).
- Enable the [User cap](../../user/admin_area/settings/sign_up_restrictions.md#user-cap)
option. **Available in GitLab 13.7 and later**.
- [Disable new sign-ups](../../user/admin_area/settings/sign_up_restrictions.md), and instead manage new

View File

@ -836,7 +836,7 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
The `POST ci/lint` API endpoint is deprecated in 15.7, and will be removed in 16.0. This endpoint does not validate the full range of CI/CD configuration options. Instead, use [`POST /projects/:id/ci/lint`](https://docs.gitlab.com/15.5/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace), which properly validates CI/CD configuration.
The `POST ci/lint` API endpoint is deprecated in 15.7, and will be removed in 16.0. This endpoint does not validate the full range of CI/CD configuration options. Instead, use [`POST /projects/:id/ci/lint`](https://docs.gitlab.com/ee/api/lint.html#validate-a-ci-yaml-configuration-with-a-namespace), which properly validates CI/CD configuration.
</div>
</div>

View File

@ -17,7 +17,7 @@ pending approval state because an administrator has enabled any of the following
- [Require administrator approval for new sign-ups](settings/sign_up_restrictions.md#require-administrator-approval-for-new-sign-ups) setting.
- [User cap](settings/sign_up_restrictions.md#user-cap).
- [Block auto-created users (OmniAuth)](../../integration/omniauth.md#configure-initial-settings)
- [Block auto-created users (OmniAuth)](../../integration/omniauth.md#configure-common-settings)
- [Block auto-created users (LDAP)](../../administration/auth/ldap/index.md#basic-configuration-settings)
When a user registers for an account while this setting is enabled:

View File

@ -49,7 +49,6 @@ The **General** settings contain:
- [External Authentication](external_authorization.md#configuration) - External Classification Policy Authorization.
- [Web terminal](../../../administration/integration/terminal.md#limiting-websocket-connection-time) -
Set max session time for web terminal.
- [Web IDE](../../project/web_ide/index.md#enable-live-preview) - Manage Web IDE features.
- [FLoC](floc.md) - Enable or disable
[Federated Learning of Cohorts (FLoC)](https://en.wikipedia.org/wiki/Federated_Learning_of_Cohorts) tracking.

View File

@ -48,7 +48,7 @@ automatically approved in a background job.
NOTE:
This setting doesn't apply to LDAP or OmniAuth users. To enforce approvals for new users
signing up using OmniAuth or LDAP, set `block_auto_created_users` to `true` in the
[OmniAuth configuration](../../../integration/omniauth.md#configure-initial-settings) or
[OmniAuth configuration](../../../integration/omniauth.md#configure-common-settings) or
[LDAP configuration](../../../administration/auth/ldap/index.md#basic-configuration-settings).
## Require email confirmation

View File

@ -19,7 +19,7 @@ On self-managed GitLab, by default this feature is not available. To make it ava
Cluster cost management provides insights into cluster resource usage. GitLab provides an example
[`kubecost-cost-model`](https://gitlab.com/gitlab-examples/kubecost-cost-model/)
project that uses the GitLab Prometheus integration and
[Kubecost's `cost-model`](https://github.com/kubecost/cost-model) to provide cluster cost
[OpenCost `cost-model`](https://github.com/opencost/opencost) to provide cluster cost
insights within GitLab:
![Example dashboard](img/kubecost_v13_5.png)

View File

@ -109,9 +109,9 @@ Users granted:
### Automatic member removal
After a group sync, for GitLab subgroups, users who are not members of a mapped SAML
group are removed from the group. Users in the top-level group are assigned the
[default membership role](index.md#role).
After a group sync, users who are not members of a mapped SAML group are removed from the group.
On GitLab.com, users in the top-level group are assigned the
[default membership role](index.md#role) instead of being removed.
For example, in the following diagram:

View File

@ -6,6 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Authenticate with the Container Registry **(FREE)**
<!--- start_remove The following content will be removed on remove_date: '2023-11-22' -->
WARNING:
[External authorization](../../admin_area/settings/external_authorization.md) will be enabled by default in GitLab 16.0. External authorization prevents personal access tokens and deploy tokens from accessing container and package registries and affects all users who use these tokens to access the registries. You can disable external authorization if you want to use personal access tokens and deploy tokens with the container or package registries.
<!--- end_remove -->
To authenticate with the Container Registry, you can use a:
- [Personal access token](../../profile/personal_access_tokens.md).

View File

@ -43,6 +43,11 @@ For information on how to create and upload a package, view the GitLab documenta
## Authenticate with the registry
<!--- start_remove The following content will be removed on remove_date: '2023-11-22' -->
WARNING:
[External authorization](../../admin_area/settings/external_authorization.md) will be enabled by default in GitLab 16.0. External authorization prevents personal access tokens and deploy tokens from accessing container and package registries and affects all users who use these tokens to access the registries. You can disable external authorization if you want to use personal access tokens and deploy tokens with the container or package registries.
<!--- end_remove -->
Authentication depends on the package manager being used. For more information, see the docs on the
specific package format you want to use.
@ -59,7 +64,6 @@ For most package types, the following credential types are valid:
- [Job token](../../../ci/jobs/ci_job_token.md):
allows access to packages in the project running the job for the users running the pipeline.
Access to other external projects can be configured.
- If your organization uses two factor authentication (2FA), you must use a personal access token with the scope set to `api`.
- If you are publishing a package via CI/CD pipelines, you must use a CI job token.

View File

@ -96,6 +96,14 @@ When selected, GitLab creates a [to-do list item](../../todos.md) for each revie
To learn more, read [Review a merge request](reviews/index.md).
#### Multiple reviewers for merge requests **(PREMIUM)**
> Introduced in GitLab 13.7.
Merge requests may often require multiple team members to review parts of the
proposed changes. You can add multiple reviewers to a merge request, making it
easier to see who is reviewing changes and who has approved changes.
### Merge requests to close issues
To create a merge request to close an issue when it's merged, you can either:

View File

@ -15,21 +15,21 @@ Suggested Reviewers is the first user-facing GitLab machine learning (ML) powere
When a Project Maintainer or Owner enables Suggested Reviewers in project settings GitLab kicks off a data extraction job for the project which leverages the Merge Request API to understand pattern of review including recency, domain experience, and frequency to suggest an appropriate reviewer.
This data extraction job can take a few hours to complete (possibly up to a day), which is largely dependent on the size of the project. The process is automated and no action is needed during this process. Once data extraction is complete, you will start getting suggestions in merge requests.
This data extraction job can take a few hours to complete (possibly up to a day), which is largely dependent on the size of the project. The process is automated and no action is needed during this process. Once data extraction is complete, you start getting suggestions in merge requests.
### Generating suggestions
Once Suggested Reviewers is enabled and the data extraction is complete, new merge requests or new commits to existing merge requests will automatically trigger a Suggested Reviewers ML model inference and generate up to 5 suggested reviewers. These suggestions are contextual to the changes in the merge request. Additional commits to merge requests may change the reviewer suggestions which will automatically update in the reviewer dropdown list.
Once Suggested Reviewers is enabled and the data extraction is complete, new merge requests or new commits to existing merge requests automatically trigger a Suggested Reviewers ML model inference and generate up to 5 suggested reviewers. These suggestions are contextual to the changes in the merge request. Additional commits to merge requests may change the reviewer suggestions, which are automatically updated in the reviewer dropdown list.
## Progressive enhancement
This feature is designed as a progressive enhancement to the existing GitLab Reviewers functionality. The GitLab Reviewer UI will only offer suggestions if the ML engine is able to provide a recommendation. In the event of an issue or model inference failure, the feature will gracefully degrade. At no point with the usage of Suggested Reviewers prevent a user from being able to manually set a reviewer.
This feature is designed as a progressive enhancement to the existing GitLab Reviewers functionality. The GitLab Reviewer UI only offers suggestions if the ML engine is able to provide a recommendation. In the event of an issue or model inference failure, the feature gracefully degrades. At no point with the usage of Suggested Reviewers prevent a user from being able to manually set a reviewer.
## Model Accuracy
Organizations use many different processes for code review. Some focus on senior engineers reviewing junior engineer's code, others have hierarchical organizational structure based reviews. Suggested Reviewers is focused on contextual reviewers based on historical merge request activity by users. While we will continue evolving the underlying ML model to better serve various code review use cases and processes Suggested Reviewers does not replace the usage of other code review features like Code Owners and [Approval Rules](../approvals/rules.md). Reviewer selection is highly subjective therefore, we do not expect Suggested Reviewers to provide perfect suggestions every time.
Organizations use many different processes for code review. Some focus on senior engineers reviewing junior engineer's code, others have hierarchical organizational structure based reviews. Suggested Reviewers is focused on contextual reviewers based on historical merge request activity by users. While we continue evolving the underlying ML model to better serve various code review use cases and processes Suggested Reviewers does not replace the usage of other code review features like Code Owners and [Approval Rules](../approvals/rules.md). Reviewer selection is highly subjective therefore, we do not expect Suggested Reviewers to provide perfect suggestions every time.
Through analysis of beta customer usage, we find that the Suggested Reviewers ML model provides suggestions that are adopted in 60% of cases. We will be introducing a feedback mechanism into the Suggested Reviewers feature in the future to allow users to flag bad reviewer suggestions to help improve the model. Additionally we will be offering an opt-in feature in the future which will allow the model to use your project's data for training the underlying model.
Through analysis of beta customer usage, we find that the Suggested Reviewers ML model provides suggestions that are adopted in 60% of cases. We plan to introduce a feedback mechanism into the Suggested Reviewers feature in the future to allow users to flag bad reviewer suggestions to help improve the model. Additionally we plan to offer an opt-in feature in the future which allows the model to use your project's data for training the underlying model.
## Off by default

View File

@ -238,7 +238,13 @@ There are two ways to preview Markdown content in the Web IDE:
1. Right-click or use the keyboard shortcut `Command/Control + Shift + P` and
select **Preview Markdown** to toggle a live Markdown preview panel.
## Live Preview
<!--- start_remove The following content will be removed on remove_date: '2023-02-01' -->
## Live Preview (removed)
WARNING:
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108627) in GitLab 15.8
and is planned for removal in 15.9. This change is a breaking change.
> [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/213853) from _Client Side Evaluation_ to _Live Preview_ in GitLab 13.0.
@ -283,6 +289,8 @@ An example `package.json`:
}
```
<!--- end_remove -->
## Interactive Web Terminals for the Web IDE
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/211685) from GitLab Ultimate to GitLab Free in 13.1.

View File

@ -96,7 +96,7 @@ If you do not want to use the Web IDE Beta, you can change your personal prefere
## Known issues
The [Web Terminal](../web_ide/index.md#interactive-web-terminals-for-the-web-ide)
and [Live Preview](../web_ide/index.md#live-preview) are not available in the Web IDE Beta.
and [Live Preview](../web_ide/index.md#live-preview-removed) are not available in the Web IDE Beta.
These features might become available at a later date.

View File

@ -164,7 +164,7 @@ module API
namespace do
after do
::Users::ActivityService.new(@current_user).execute
::Users::ActivityService.new(author: @current_user, project: @project, namespace: @group).execute
end
# Mount endpoints to include in the OpenAPI V2 documentation here

View File

@ -58,7 +58,9 @@ module API
def log_user_activity(actor)
commands = Gitlab::GitAccess::DOWNLOAD_COMMANDS
::Users::ActivityService.new(actor).execute if commands.include?(params[:action])
return unless commands.include?(params[:action])
::Users::ActivityService.new(author: actor, namespace: project&.namespace, project: project).execute
end
def redis_ping

View File

@ -250,8 +250,8 @@ module Gitlab
prometheus_enabled: alt_usage_data(fallback: nil) { Gitlab::Prometheus::Internal.prometheus_enabled? },
prometheus_metrics_enabled: alt_usage_data(fallback: nil) { Gitlab::Metrics.prometheus_metrics_enabled? },
reply_by_email_enabled: alt_usage_data(fallback: nil) { Gitlab::IncomingEmail.enabled? },
web_ide_clientside_preview_enabled: alt_usage_data(fallback: nil) { false },
signup_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.allow_signup? },
web_ide_clientside_preview_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? },
grafana_link_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.grafana_enabled? },
gitpod_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.gitpod_enabled? }
}

View File

@ -7,7 +7,6 @@ module Gitlab
EDIT_BY_SFE = 'g_edit_by_sfe'
EDIT_BY_WEB_IDE = 'g_edit_by_web_ide'
EDIT_CATEGORY = 'ide_edit'
EDIT_BY_LIVE_PREVIEW = 'g_edit_by_live_preview'
class << self
def track_web_ide_edit_action(author:, time: Time.zone.now, project:)
@ -39,10 +38,6 @@ module Gitlab
count_unique(events, date_from, date_to)
end
def track_live_preview_edit_action(author:, time: Time.zone.now, project:)
track_unique_action(EDIT_BY_LIVE_PREVIEW, author, time, project)
end
private
def track_unique_action(event_name, author, time, project = nil)

View File

@ -27,18 +27,6 @@ module Gitlab
count('pipelines')
end
def increment_previews_count
return unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
count('previews')
end
def increment_previews_success_count
return unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
count('previews_success')
end
private
def redis_key(event)

View File

@ -5152,6 +5152,9 @@ msgstr ""
msgid "Approved"
msgstr ""
msgid "Approved MRs"
msgstr ""
msgid "Approved the current merge request."
msgstr ""
@ -5445,6 +5448,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
msgid "Ascending"
msgstr ""
msgid "Ask again later"
msgstr ""
@ -8765,6 +8771,9 @@ msgstr ""
msgid "CiVariable|Create wildcard"
msgstr ""
msgid "CiVariable|Define a CI/CD variable in the UI"
msgstr ""
msgid "CiVariable|New environment"
msgstr ""
@ -8959,6 +8968,9 @@ msgstr ""
msgid "Closed %{epicTimeagoDate}"
msgstr ""
msgid "Closed MRs"
msgstr ""
msgid "Closed date"
msgstr ""
@ -11060,27 +11072,12 @@ msgstr ""
msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes} by %{contributors}."
msgstr ""
msgid "ContributionAnalytics|Approved MRs"
msgstr ""
msgid "ContributionAnalytics|Closed MRs"
msgstr ""
msgid "ContributionAnalytics|Closed issues"
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr ""
msgid "ContributionAnalytics|Contributions per group member"
msgstr ""
msgid "ContributionAnalytics|Failed to load the contribution stats"
msgstr ""
msgid "ContributionAnalytics|Issues"
msgstr ""
@ -11093,18 +11090,9 @@ msgstr ""
msgid "ContributionAnalytics|Last week"
msgstr ""
msgid "ContributionAnalytics|Loading contribution stats for group members"
msgstr ""
msgid "ContributionAnalytics|Merge requests"
msgstr ""
msgid "ContributionAnalytics|Merged MRs"
msgstr ""
msgid "ContributionAnalytics|Name"
msgstr ""
msgid "ContributionAnalytics|No issues for the selected time period."
msgstr ""
@ -11114,15 +11102,6 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
msgid "ContributionAnalytics|Opened MRs"
msgstr ""
msgid "ContributionAnalytics|Opened issues"
msgstr ""
msgid "ContributionAnalytics|Pushed"
msgstr ""
msgid "ContributionAnalytics|The given date range is larger than 31 days"
msgstr ""
@ -11132,10 +11111,10 @@ msgstr ""
msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
msgstr ""
msgid "ContributionAnalytics|Total Contributions"
msgid "Contributions for %{calendar_date}"
msgstr ""
msgid "Contributions for %{calendar_date}"
msgid "Contributions per group member"
msgstr ""
msgid "Contributor"
@ -14110,6 +14089,9 @@ msgstr ""
msgid "Deprioritize label"
msgstr ""
msgid "Descending"
msgstr ""
msgid "Describe the goal of the changes and what reviewers should be aware of."
msgstr ""
@ -20816,9 +20798,6 @@ msgstr ""
msgid "IDE"
msgstr ""
msgid "IDE|Back"
msgstr ""
msgid "IDE|Commit"
msgstr ""
@ -20828,21 +20807,9 @@ msgstr ""
msgid "IDE|Edit"
msgstr ""
msgid "IDE|Get started with Live Preview"
msgstr ""
msgid "IDE|Go to project"
msgstr ""
msgid "IDE|Live Preview"
msgstr ""
msgid "IDE|Preview your web application using Web IDE client-side evaluation."
msgstr ""
msgid "IDE|Refresh preview"
msgstr ""
msgid "IDE|Review"
msgstr ""
@ -23958,10 +23925,10 @@ msgstr ""
msgid "JiraService|Set a custom final state by using transition IDs. %{linkStart}Learn about transition IDs%{linkEnd}"
msgstr ""
msgid "JiraService|Sign in to GitLab to link namespaces."
msgid "JiraService|Sign in to GitLab to get started."
msgstr ""
msgid "JiraService|Sign in to GitLab.com to get started."
msgid "JiraService|Sign in to GitLab to link namespaces."
msgstr ""
msgid "JiraService|This feature requires a Premium plan."
@ -25255,9 +25222,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
msgid "Live preview"
msgstr ""
msgid "Load more"
msgstr ""
@ -25270,6 +25234,9 @@ msgstr ""
msgid "Loading %{name}"
msgstr ""
msgid "Loading contribution stats for group members"
msgstr ""
msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr ""
@ -25501,9 +25468,6 @@ msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
msgid "Manage Web IDE features."
msgstr ""
msgid "Manage access"
msgstr ""
@ -26525,6 +26489,9 @@ msgstr ""
msgid "Merged"
msgstr ""
msgid "Merged MRs"
msgstr ""
msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes."
msgstr ""
@ -29427,6 +29394,12 @@ msgstr ""
msgid "Opened"
msgstr ""
msgid "Opened MRs"
msgstr ""
msgid "Opened issues"
msgstr ""
msgid "OpenedNDaysAgo|Created"
msgstr ""
@ -31937,9 +31910,6 @@ msgstr ""
msgid "Preview"
msgstr ""
msgid "Preview JavaScript projects in the Web IDE with CodeSandbox Live Preview. %{link_start}Learn more.%{link_end} "
msgstr ""
msgid "Preview Markdown"
msgstr ""
@ -34634,6 +34604,9 @@ msgstr ""
msgid "PushRule|Reject unverified users"
msgstr ""
msgid "Pushed"
msgstr ""
msgid "Pushes"
msgstr ""
@ -39957,6 +39930,9 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
msgid "Something went wrong while fetching group member contributions"
msgstr ""
msgid "Something went wrong while fetching latest comments."
msgstr ""
@ -44494,6 +44470,9 @@ msgstr ""
msgid "Total"
msgstr ""
msgid "Total Contributions"
msgstr ""
msgid "Total Score"
msgstr ""

View File

@ -51,14 +51,13 @@
"@apollo/client": "^3.5.10",
"@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2",
"@codesandbox/sandpack-client": "^1.2.2",
"@cubejs-client/core": "^0.31.15",
"@cubejs-client/vue": "^0.31.19",
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/fonts": "^1.2.0",
"@gitlab/svgs": "3.18.0",
"@gitlab/ui": "54.1.1",
"@gitlab/ui": "54.1.2",
"@gitlab/visual-review-tools": "1.7.3",
"@gitlab/web-ide": "0.0.1-dev-20230120231236",
"@rails/actioncable": "6.1.4-7",
@ -109,7 +108,6 @@
"cache-loader": "^4.1.0",
"canvas-confetti": "^1.4.0",
"clipboard": "^2.0.8",
"codesandbox-api": "0.0.23",
"compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1",
"core-js": "^3.27.2",
@ -228,10 +226,10 @@
"cheerio": "^1.0.0-rc.9",
"commander": "^2.20.3",
"custom-jquery-matchers": "^2.1.0",
"eslint": "8.29.0",
"eslint": "8.32.0",
"eslint-import-resolver-jest": "3.0.2",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-unsanitized": "^4.0.2",
"gettext-extractor": "^3.5.3",

View File

@ -42,83 +42,6 @@ RSpec.describe Projects::ServicePingController do
end
end
describe 'POST #web_ide_clientside_preview' do
subject { post :web_ide_clientside_preview, params: { namespace_id: project.namespace, project_id: project } }
context 'when web ide clientside preview is enabled' do
before do
stub_application_setting(web_ide_clientside_preview_enabled: true)
end
it_behaves_like 'counter is not increased'
it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_COUNT'
end
context 'when web ide clientside preview is not enabled' do
let(:user) { project.first_owner }
before do
stub_application_setting(web_ide_clientside_preview_enabled: false)
end
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe 'POST #web_ide_clientside_preview_success' do
subject { post :web_ide_clientside_preview_success, params: { namespace_id: project.namespace, project_id: project } }
context 'when web ide clientside preview is enabled' do
before do
stub_application_setting(web_ide_clientside_preview_enabled: true)
end
it_behaves_like 'counter is not increased'
it_behaves_like 'counter is increased', 'WEB_IDE_PREVIEWS_SUCCESS_COUNT'
context 'when the user has access to the project', :snowplow do
let(:user) { project.owner }
it 'increases the live preview view counter' do
expect(Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_live_preview_edit_action).with(author: user, project: project)
subject
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
let(:project) { create(:project) }
let(:namespace) { project.namespace }
let(:category) { 'Gitlab::UsageDataCounters::EditorUniqueCounter' }
let(:action) { 'ide_edit' }
let(:property) { 'g_edit_by_live_preview' }
let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit' }
let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context] }
let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
end
end
context 'when web ide clientside preview is not enabled' do
let(:user) { project.owner }
before do
stub_application_setting(web_ide_clientside_preview_enabled: false)
end
it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
describe 'POST #web_ide_pipelines_count' do
subject { post :web_ide_pipelines_count, params: { namespace_id: project.namespace, project_id: project } }

View File

@ -221,7 +221,7 @@ RSpec.describe SessionsController do
expect(Gitlab::Metrics).to receive(:counter)
.with(:successful_login_captcha_total, anything)
.and_return(counter)
expect(Gitlab::Metrics).to receive(:counter).and_call_original
expect(Gitlab::Metrics).to receive(:counter).at_least(1).time.and_call_original
post(:create, params: { user: user_params }, session: sesion_params)
end

View File

@ -1,31 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'IDE Clientside Preview CSP', feature_category: :web_ide do
let_it_be(:user) { create(:user) }
shared_context 'disable feature' do
before do
stub_application_setting(web_ide_clientside_preview_enabled: false)
end
end
it_behaves_like 'setting CSP', 'frame-src' do
let(:allowlisted_url) { 'https://sandbox.gitlab-static.test' }
let(:extended_controller_class) { IdeController }
subject do
visit ide_path
response_headers['Content-Security-Policy']
end
before do
stub_application_setting(web_ide_clientside_preview_enabled: true)
stub_application_setting(web_ide_clientside_preview_bundler_url: allowlisted_url)
sign_in(user)
end
end
end

View File

@ -33,7 +33,6 @@ describe('Ci variable modal', () => {
isProtectedByDefault: false,
maskedEnvironmentVariablesLink: '/variables-link',
maskableRegex,
protectedEnvironmentVariablesLink: '/protected-link',
};
const defaultProps = {

View File

@ -68,31 +68,6 @@ describe('ide/components/panes/right.vue', () => {
});
});
describe('clientside live preview tab', () => {
it('is shown if there is a packageJson and clientsidePreviewEnabled', () => {
Vue.set(store.state.entries, 'package.json', {
name: 'package.json',
});
store.state.clientsidePreviewEnabled = true;
createComponent();
expect(wrapper.findComponent(CollapsibleSidebar).props('extensionTabs')).toEqual(
expect.arrayContaining([
expect.objectContaining({
show: true,
title: 'Live preview',
views: expect.arrayContaining([
expect.objectContaining({
name: rightSidebarViews.clientSidePreview.name,
}),
]),
}),
]),
);
});
});
describe('terminal tab', () => {
beforeEach(() => {
createComponent();

View File

@ -1,416 +0,0 @@
import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import { dispatch } from 'codesandbox-api';
import { SandpackClient } from '@codesandbox/sandpack-client';
import Vuex from 'vuex';
import waitForPromises from 'helpers/wait_for_promises';
import Clientside from '~/ide/components/preview/clientside.vue';
import { PING_USAGE_PREVIEW_KEY, PING_USAGE_PREVIEW_SUCCESS_KEY } from '~/ide/constants';
import eventHub from '~/ide/eventhub';
jest.mock('@codesandbox/sandpack-client', () => ({
SandpackClient: jest.fn(),
}));
Vue.use(Vuex);
const dummyPackageJson = () => ({
raw: JSON.stringify({
main: 'index.js',
}),
});
const expectedSandpackOptions = () => ({
files: {},
entry: '/index.js',
showOpenInCodeSandbox: true,
});
const expectedSandpackSettings = () => ({
fileResolver: {
isFile: expect.any(Function),
readFile: expect.any(Function),
},
});
describe('IDE clientside preview', () => {
let wrapper;
let store;
const storeActions = {
getFileData: jest.fn().mockReturnValue(Promise.resolve({})),
getRawFileData: jest.fn().mockReturnValue(Promise.resolve('')),
};
const storeClientsideActions = {
pingUsage: jest.fn().mockReturnValue(Promise.resolve({})),
};
const dispatchCodesandboxReady = () => dispatch({ type: 'done' });
const createComponent = ({ state, getters } = {}) => {
store = new Vuex.Store({
state: {
entries: {},
links: {},
...state,
},
getters: {
packageJson: () => '',
currentProject: () => ({
visibility: 'public',
}),
...getters,
},
actions: storeActions,
modules: {
clientside: {
namespaced: true,
actions: storeClientsideActions,
},
},
});
wrapper = shallowMount(Clientside, {
store,
});
};
const createInitializedComponent = () => {
createComponent();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({
sandpackReady: true,
client: {
cleanup: jest.fn(),
updatePreview: jest.fn(),
},
});
};
afterEach(() => {
wrapper.destroy();
});
describe('without main entry', () => {
it('creates sandpack client', () => {
createComponent();
expect(SandpackClient).not.toHaveBeenCalled();
});
});
describe('with main entry', () => {
beforeEach(() => {
createComponent({ getters: { packageJson: dummyPackageJson } });
return waitForPromises();
});
it('creates sandpack client', () => {
expect(SandpackClient).toHaveBeenCalledWith(
'#ide-preview',
expectedSandpackOptions(),
expectedSandpackSettings(),
);
});
it('pings usage', () => {
expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1);
expect(storeClientsideActions.pingUsage).toHaveBeenCalledWith(
expect.anything(),
PING_USAGE_PREVIEW_KEY,
);
});
it('pings usage success', async () => {
dispatchCodesandboxReady();
await nextTick();
expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(2);
expect(storeClientsideActions.pingUsage).toHaveBeenCalledWith(
expect.anything(),
PING_USAGE_PREVIEW_SUCCESS_KEY,
);
});
});
describe('with codesandboxBundlerUrl', () => {
const TEST_BUNDLER_URL = 'https://test.gitlab-static.test';
beforeEach(() => {
createComponent({
getters: { packageJson: dummyPackageJson },
state: { codesandboxBundlerUrl: TEST_BUNDLER_URL },
});
return waitForPromises();
});
it('creates sandpack client with bundlerURL', () => {
expect(SandpackClient).toHaveBeenCalledWith('#ide-preview', expectedSandpackOptions(), {
...expectedSandpackSettings(),
bundlerURL: TEST_BUNDLER_URL,
});
});
});
describe('with codesandboxBundlerURL', () => {
beforeEach(() => {
createComponent({ getters: { packageJson: dummyPackageJson } });
return waitForPromises();
});
it('creates sandpack client', () => {
expect(SandpackClient).toHaveBeenCalledWith(
'#ide-preview',
{
files: {},
entry: '/index.js',
showOpenInCodeSandbox: true,
},
{
fileResolver: {
isFile: expect.any(Function),
readFile: expect.any(Function),
},
},
);
});
});
describe('computed', () => {
describe('normalizedEntries', () => {
it('returns flattened list of blobs with content', () => {
createComponent({
state: {
entries: {
'index.js': { type: 'blob', raw: 'test' },
'index2.js': { type: 'blob', content: 'content' },
tree: { type: 'tree' },
empty: { type: 'blob' },
},
},
});
expect(wrapper.vm.normalizedEntries).toEqual({
'/index.js': {
code: 'test',
},
'/index2.js': {
code: 'content',
},
});
});
});
describe('mainEntry', () => {
it('returns false when package.json is empty', () => {
createComponent();
expect(wrapper.vm.mainEntry).toBe(false);
});
it('returns main key from package.json', () => {
createComponent({ getters: { packageJson: dummyPackageJson } });
expect(wrapper.vm.mainEntry).toBe('index.js');
});
});
describe('showPreview', () => {
it('returns false if no mainEntry', () => {
createComponent();
expect(wrapper.vm.showPreview).toBe(false);
});
it('returns false if loading and mainEntry exists', () => {
createComponent({ getters: { packageJson: dummyPackageJson } });
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ loading: true });
expect(wrapper.vm.showPreview).toBe(false);
});
it('returns true if not loading and mainEntry exists', () => {
createComponent({ getters: { packageJson: dummyPackageJson } });
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ loading: false });
expect(wrapper.vm.showPreview).toBe(true);
});
});
describe('showEmptyState', () => {
it('returns true if no mainEntry exists', () => {
createComponent();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ loading: false });
expect(wrapper.vm.showEmptyState).toBe(true);
});
it('returns false if loading', () => {
createComponent();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ loading: true });
expect(wrapper.vm.showEmptyState).toBe(false);
});
it('returns false if not loading and mainEntry exists', () => {
createComponent({ getters: { packageJson: dummyPackageJson } });
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ loading: false });
expect(wrapper.vm.showEmptyState).toBe(false);
});
});
describe('showOpenInCodeSandbox', () => {
it('returns true when visibility is public', () => {
createComponent({ getters: { currentProject: () => ({ visibility: 'public' }) } });
expect(wrapper.vm.showOpenInCodeSandbox).toBe(true);
});
it('returns false when visibility is private', () => {
createComponent({ getters: { currentProject: () => ({ visibility: 'private' }) } });
expect(wrapper.vm.showOpenInCodeSandbox).toBe(false);
});
});
describe('sandboxOpts', () => {
beforeEach(() => {
createComponent({
state: {
entries: {
'index.js': { type: 'blob', raw: 'test' },
'package.json': dummyPackageJson(),
},
},
getters: {
packageJson: dummyPackageJson,
},
});
});
it('returns sandbox options', () => {
expect(wrapper.vm.sandboxOpts).toEqual({
files: {
'/index.js': {
code: 'test',
},
'/package.json': {
code: '{"main":"index.js"}',
},
},
entry: '/index.js',
showOpenInCodeSandbox: true,
});
});
});
});
describe('methods', () => {
describe('loadFileContent', () => {
beforeEach(() => {
createComponent();
return wrapper.vm.loadFileContent('package.json');
});
it('calls getFileData', () => {
expect(storeActions.getFileData).toHaveBeenCalledWith(expect.any(Object), {
path: 'package.json',
makeFileActive: false,
});
});
it('calls getRawFileData', () => {
expect(storeActions.getRawFileData).toHaveBeenCalledWith(expect.any(Object), {
path: 'package.json',
});
});
});
describe('update', () => {
it('initializes client if client is empty', () => {
createComponent({ getters: { packageJson: dummyPackageJson } });
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ sandpackReady: true });
wrapper.vm.update();
return waitForPromises().then(() => {
expect(SandpackClient).toHaveBeenCalled();
});
});
it('calls updatePreview', () => {
createInitializedComponent();
wrapper.vm.update();
expect(wrapper.vm.client.updatePreview).toHaveBeenCalledWith(wrapper.vm.sandboxOpts);
});
});
describe('on ide.files.change event', () => {
beforeEach(() => {
createInitializedComponent();
eventHub.$emit('ide.files.change');
});
it('calls updatePreview', () => {
expect(wrapper.vm.client.updatePreview).toHaveBeenCalledWith(wrapper.vm.sandboxOpts);
});
});
});
describe('template', () => {
it('renders ide-preview element when showPreview is true', async () => {
createComponent({ getters: { packageJson: dummyPackageJson } });
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ loading: false });
await nextTick();
expect(wrapper.find('#ide-preview').exists()).toBe(true);
});
it('renders empty state', async () => {
createComponent();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ loading: false });
await nextTick();
expect(wrapper.text()).toContain(
'Preview your web application using Web IDE client-side evaluation.',
);
});
it('renders loading icon', async () => {
createComponent();
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ loading: true });
await nextTick();
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
});
describe('when destroyed', () => {
let spy;
beforeEach(() => {
createInitializedComponent();
spy = wrapper.vm.client.updatePreview;
wrapper.destroy();
});
it('does not call updatePreview', () => {
expect(spy).not.toHaveBeenCalled();
});
});
});

View File

@ -1,161 +0,0 @@
import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { listen } from 'codesandbox-api';
import { nextTick } from 'vue';
import { TEST_HOST } from 'helpers/test_constants';
import ClientsideNavigator from '~/ide/components/preview/navigator.vue';
jest.mock('codesandbox-api', () => ({
listen: jest.fn().mockReturnValue(jest.fn()),
}));
describe('IDE clientside preview navigator', () => {
let wrapper;
let client;
let listenHandler;
const findBackButton = () => wrapper.findAll('button').at(0);
const findForwardButton = () => wrapper.findAll('button').at(1);
const findRefreshButton = () => wrapper.findAll('button').at(2);
beforeEach(() => {
listen.mockClear();
client = { bundlerURL: TEST_HOST, iframe: { src: '' } };
wrapper = shallowMount(ClientsideNavigator, { propsData: { client } });
[[listenHandler]] = listen.mock.calls;
});
afterEach(() => {
wrapper.destroy();
});
it('renders readonly URL bar', async () => {
listenHandler({ type: 'urlchange', url: client.bundlerURL });
await nextTick();
expect(wrapper.find('input[readonly]').element.value).toBe('/');
});
it('renders loading icon by default', () => {
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
it('removes loading icon when done event is fired', async () => {
listenHandler({ type: 'done' });
await nextTick();
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
});
it('does not count visiting same url multiple times', async () => {
listenHandler({ type: 'done' });
listenHandler({ type: 'done', url: `${TEST_HOST}/url1` });
listenHandler({ type: 'done', url: `${TEST_HOST}/url1` });
await nextTick();
expect(findBackButton().attributes('disabled')).toBe('disabled');
});
it('unsubscribes from listen on destroy', () => {
const unsubscribeFn = listen();
wrapper.destroy();
expect(unsubscribeFn).toHaveBeenCalled();
});
describe('back button', () => {
beforeEach(async () => {
listenHandler({ type: 'done' });
listenHandler({ type: 'urlchange', url: TEST_HOST });
await nextTick();
});
it('is disabled by default', () => {
expect(findBackButton().attributes('disabled')).toBe('disabled');
});
it('is enabled when there is previous entry', async () => {
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
await nextTick();
findBackButton().trigger('click');
expect(findBackButton().attributes()).not.toHaveProperty('disabled');
});
it('is disabled when there is no previous entry', async () => {
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
await nextTick();
findBackButton().trigger('click');
await nextTick();
expect(findBackButton().attributes('disabled')).toBe('disabled');
});
it('updates client iframe src', async () => {
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url2` });
await nextTick();
findBackButton().trigger('click');
expect(client.iframe.src).toBe(`${TEST_HOST}/url1`);
});
});
describe('forward button', () => {
beforeEach(async () => {
listenHandler({ type: 'done' });
listenHandler({ type: 'urlchange', url: TEST_HOST });
await nextTick();
});
it('is disabled by default', () => {
expect(findForwardButton().attributes('disabled')).toBe('disabled');
});
it('is enabled when there is next entry', async () => {
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
await nextTick();
findBackButton().trigger('click');
await nextTick();
expect(findForwardButton().attributes()).not.toHaveProperty('disabled');
});
it('is disabled when there is no next entry', async () => {
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
await nextTick();
findBackButton().trigger('click');
await nextTick();
findForwardButton().trigger('click');
await nextTick();
expect(findForwardButton().attributes('disabled')).toBe('disabled');
});
it('updates client iframe src', async () => {
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url2` });
await nextTick();
findBackButton().trigger('click');
expect(client.iframe.src).toBe(`${TEST_HOST}/url1`);
});
});
describe('refresh button', () => {
const url = `${TEST_HOST}/some_url`;
beforeEach(async () => {
listenHandler({ type: 'done' });
listenHandler({ type: 'urlchange', url });
await nextTick();
});
it('calls refresh with current path', () => {
client.iframe.src = 'something-other';
findRefreshButton().trigger('click');
expect(client.iframe.src).toBe(url);
});
});
});

View File

@ -294,18 +294,6 @@ describe('IDE store getters', () => {
});
});
describe('packageJson', () => {
it('returns package.json entry', () => {
localState.entries['package.json'] = {
name: 'package.json',
};
expect(getters.packageJson(localState)).toEqual({
name: 'package.json',
});
});
});
describe('canPushToBranch', () => {
it.each`
currentBranch | canPushCode | expectedValue

View File

@ -1,38 +0,0 @@
import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
import { PING_USAGE_PREVIEW_KEY } from '~/ide/constants';
import * as actions from '~/ide/stores/modules/clientside/actions';
import axios from '~/lib/utils/axios_utils';
const TEST_PROJECT_URL = `${TEST_HOST}/lorem/ipsum`;
const TEST_USAGE_URL = `${TEST_PROJECT_URL}/service_ping/${PING_USAGE_PREVIEW_KEY}`;
describe('IDE store module clientside actions', () => {
let rootGetters;
let mock;
beforeEach(() => {
rootGetters = {
currentProject: {
web_url: TEST_PROJECT_URL,
},
};
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('pingUsage', () => {
it('posts to usage endpoint', async () => {
const usageSpy = jest.fn(() => [200]);
mock.onPost(TEST_USAGE_URL).reply(() => usageSpy());
await testAction(actions.pingUsage, PING_USAGE_PREVIEW_KEY, rootGetters, [], []);
expect(usageSpy).toHaveBeenCalled();
});
});
});

View File

@ -82,10 +82,6 @@ describe('date_format_utility.js', () => {
);
});
it('defaults to 00:00 if no time is provided', () => {
expect(utils.dateAndTimeToISOString(new Date('2021-08-21'))).toBe('2021-08-21T00:00:00.000Z');
});
it('throws if date in invalid', () => {
expect(() => utils.dateAndTimeToISOString('Invalid date', '10:00')).toThrow(
'Argument should be a Date instance',

Some files were not shown because too many files have changed in this diff Show More