Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									9796aa22cd
								
							
						
					
					
						commit
						bf0d6692fc
					
				| 
						 | 
				
			
			@ -1,15 +0,0 @@
 | 
			
		|||
test-reliability-report:
 | 
			
		||||
  extends:
 | 
			
		||||
    - .qa:rules:reliable-reports:schedule
 | 
			
		||||
  image:
 | 
			
		||||
    name: ${CI_REGISTRY_IMAGE}/gitlab-ee-qa:${CI_DEFAULT_BRANCH}
 | 
			
		||||
    entrypoint: [""]
 | 
			
		||||
  before_script:
 | 
			
		||||
    - cd /home/gitlab/qa
 | 
			
		||||
  script:
 | 
			
		||||
    - echo "Generate report for 'staging-full' runs"
 | 
			
		||||
    - bundle exec rake "reliable_spec_report[staging-full,30,true]"
 | 
			
		||||
    - bundle exec rake "unreliable_spec_report[staging-full,30,true]"
 | 
			
		||||
    - echo "Generate report for 'package-and-qa' runs"
 | 
			
		||||
    - bundle exec rake "reliable_spec_report[package-and-qa,30,true]"
 | 
			
		||||
    - bundle exec rake "unreliable_spec_report[package-and-qa,30,true]"
 | 
			
		||||
| 
						 | 
				
			
			@ -766,11 +766,6 @@
 | 
			
		|||
      changes: *feature-flag-development-config-patterns
 | 
			
		||||
      allow_failure: true
 | 
			
		||||
 | 
			
		||||
.qa:rules:reliable-reports:schedule:
 | 
			
		||||
  rules:
 | 
			
		||||
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule" && $QA_RELIABLE_REPORT == "true"'
 | 
			
		||||
      allow_failure: true
 | 
			
		||||
 | 
			
		||||
###############
 | 
			
		||||
# Rails rules #
 | 
			
		||||
###############
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,10 +94,7 @@ _Consider adding links to check for Sentry errors, Production logs for 5xx, 302s
 | 
			
		|||
 | 
			
		||||
### Global rollout on production
 | 
			
		||||
 | 
			
		||||
For visibility, all `/chatops` commands that target production should be:
 | 
			
		||||
 | 
			
		||||
- Executed in the `#production` slack channel.
 | 
			
		||||
- Cross-posted (with the command results) to the responsible team's slack channel (`#g_TEAM_NAME`).
 | 
			
		||||
For visibility, all `/chatops` commands that target production should be executed in the `#production` slack channel and cross-posted (with the command results) to the responsible team's slack channel (`#g_TEAM_NAME`).
 | 
			
		||||
 | 
			
		||||
- [ ] [Incrementally roll out](https://docs.gitlab.com/ee/development/feature_flags/controls.html#process) the feature.
 | 
			
		||||
  - If the feature flag in code has [an actor](https://docs.gitlab.com/ee/development/feature_flags/#feature-actors), perform **actor-based** rollout.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2594,7 +2594,6 @@ Style/OpenStructUse:
 | 
			
		|||
    - 'spec/lib/gitlab/database/migrations/runner_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/grape_logging/loggers/exception_logger_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/graphql/pagination/keyset/connection_generic_keyset_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/graphql/pagination/keyset/connection_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/legacy_github_import/project_creator_spec.rb'
 | 
			
		||||
| 
						 | 
				
			
			@ -2604,7 +2603,6 @@ Style/OpenStructUse:
 | 
			
		|||
    - 'spec/models/design_management/design_at_version_spec.rb'
 | 
			
		||||
    - 'spec/models/user_spec.rb'
 | 
			
		||||
    - 'spec/presenters/packages/nuget/search_results_presenter_spec.rb'
 | 
			
		||||
    - 'spec/requests/api/import_github_spec.rb'
 | 
			
		||||
    - 'spec/services/packages/nuget/metadata_extraction_service_spec.rb'
 | 
			
		||||
    - 'spec/services/projects/import_service_spec.rb'
 | 
			
		||||
    - 'spec/services/system_note_service_spec.rb'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ export function getAllExperimentContexts() {
 | 
			
		|||
  return Object.values(getExperimentsData()).map(createGitlabExperimentContext);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function isExperimentVariant(experimentName, variantName) {
 | 
			
		||||
export function isExperimentVariant(experimentName, variantName = CANDIDATE_VARIANT) {
 | 
			
		||||
  return getExperimentData(experimentName)?.variant === variantName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ import {
 | 
			
		|||
  MEMBER_AREAS_OF_FOCUS,
 | 
			
		||||
  INVITE_MEMBERS_FOR_TASK,
 | 
			
		||||
  MODAL_LABELS,
 | 
			
		||||
  LEARN_GITLAB,
 | 
			
		||||
} from '../constants';
 | 
			
		||||
import eventHub from '../event_hub';
 | 
			
		||||
import {
 | 
			
		||||
| 
						 | 
				
			
			@ -200,7 +201,8 @@ export default {
 | 
			
		|||
    },
 | 
			
		||||
    tasksToBeDoneEnabled() {
 | 
			
		||||
      return (
 | 
			
		||||
        getParameterValues('open_modal')[0] === 'invite_members_for_task' &&
 | 
			
		||||
        (getParameterValues('open_modal')[0] === 'invite_members_for_task' ||
 | 
			
		||||
          this.isOnLearnGitlab) &&
 | 
			
		||||
        this.tasksToBeDoneOptions.length
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -221,11 +223,18 @@ export default {
 | 
			
		|||
        ? this.selectedTaskProject.id
 | 
			
		||||
        : '';
 | 
			
		||||
    },
 | 
			
		||||
    isOnLearnGitlab() {
 | 
			
		||||
      return this.source === LEARN_GITLAB;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    eventHub.$on('openModal', (options) => {
 | 
			
		||||
      this.openModal(options);
 | 
			
		||||
      if (this.isOnLearnGitlab) {
 | 
			
		||||
        this.trackEvent(INVITE_MEMBERS_FOR_TASK.name, this.source);
 | 
			
		||||
      } else {
 | 
			
		||||
        this.trackEvent(MEMBER_AREAS_OF_FOCUS.name, MEMBER_AREAS_OF_FOCUS.view);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (this.tasksToBeDoneEnabled) {
 | 
			
		||||
| 
						 | 
				
			
			@ -303,7 +312,7 @@ export default {
 | 
			
		|||
        : Api.groupShareWithGroup.bind(Api);
 | 
			
		||||
 | 
			
		||||
      apiShareWithGroup(this.id, this.shareWithGroupPostData(this.groupToBeSharedWith.id))
 | 
			
		||||
        .then(this.showToastMessageSuccess)
 | 
			
		||||
        .then(this.showSuccessMessage)
 | 
			
		||||
        .catch(this.showInvalidFeedbackMessage);
 | 
			
		||||
    },
 | 
			
		||||
    submitInviteMembers() {
 | 
			
		||||
| 
						 | 
				
			
			@ -332,7 +341,7 @@ export default {
 | 
			
		|||
      this.trackinviteMembersForTask();
 | 
			
		||||
 | 
			
		||||
      Promise.all(promises)
 | 
			
		||||
        .then(this.conditionallyShowToastSuccess)
 | 
			
		||||
        .then(this.conditionallyShowSuccessMessage)
 | 
			
		||||
        .catch(this.showInvalidFeedbackMessage);
 | 
			
		||||
    },
 | 
			
		||||
    inviteByEmailPostData(usersToInviteByEmail) {
 | 
			
		||||
| 
						 | 
				
			
			@ -364,11 +373,11 @@ export default {
 | 
			
		|||
        group_access: this.selectedAccessLevel,
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    conditionallyShowToastSuccess(response) {
 | 
			
		||||
    conditionallyShowSuccessMessage(response) {
 | 
			
		||||
      const message = this.unescapeMsg(responseMessageFromSuccess(response));
 | 
			
		||||
 | 
			
		||||
      if (message === '') {
 | 
			
		||||
        this.showToastMessageSuccess();
 | 
			
		||||
        this.showSuccessMessage();
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -376,8 +385,12 @@ export default {
 | 
			
		|||
      this.invalidFeedbackMessage = message;
 | 
			
		||||
      this.isLoading = false;
 | 
			
		||||
    },
 | 
			
		||||
    showToastMessageSuccess() {
 | 
			
		||||
    showSuccessMessage() {
 | 
			
		||||
      if (this.isOnLearnGitlab) {
 | 
			
		||||
        eventHub.$emit('showSuccessfulInvitationsAlert');
 | 
			
		||||
      } else {
 | 
			
		||||
        this.$toast.show(this.$options.labels.toastMessageSuccessful, this.toastOptions);
 | 
			
		||||
      }
 | 
			
		||||
      this.closeModal();
 | 
			
		||||
    },
 | 
			
		||||
    showInvalidFeedbackMessage(response) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -144,3 +144,5 @@ export const MODAL_LABELS = {
 | 
			
		|||
  headerCloseLabel: HEADER_CLOSE_LABEL,
 | 
			
		||||
  areasOfFocusLabel: AREAS_OF_FOCUS_LABEL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const LEARN_GITLAB = 'learn_gitlab';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +1,21 @@
 | 
			
		|||
<script>
 | 
			
		||||
import { GlProgressBar, GlSprintf } from '@gitlab/ui';
 | 
			
		||||
import { GlProgressBar, GlSprintf, GlAlert } from '@gitlab/ui';
 | 
			
		||||
import eventHub from '~/invite_members/event_hub';
 | 
			
		||||
import { s__ } from '~/locale';
 | 
			
		||||
import { ACTION_LABELS, ACTION_SECTIONS } from '../constants';
 | 
			
		||||
import LearnGitlabSectionCard from './learn_gitlab_section_card.vue';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  components: { GlProgressBar, GlSprintf, LearnGitlabSectionCard },
 | 
			
		||||
  components: { GlProgressBar, GlSprintf, GlAlert, LearnGitlabSectionCard },
 | 
			
		||||
  i18n: {
 | 
			
		||||
    title: s__('LearnGitLab|Learn GitLab'),
 | 
			
		||||
    description: s__(
 | 
			
		||||
      'LearnGitLab|Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project.',
 | 
			
		||||
    ),
 | 
			
		||||
    percentageCompleted: s__(`LearnGitLab|%{percentage}%{percentSymbol} completed`),
 | 
			
		||||
    successfulInvitations: s__(
 | 
			
		||||
      "LearnGitLab|Your team is growing! You've successfully invited new team members to the %{projectName} project.",
 | 
			
		||||
    ),
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    actions: {
 | 
			
		||||
| 
						 | 
				
			
			@ -28,12 +31,22 @@ export default {
 | 
			
		|||
      required: false,
 | 
			
		||||
      default: false,
 | 
			
		||||
    },
 | 
			
		||||
    project: {
 | 
			
		||||
      required: true,
 | 
			
		||||
      type: Object,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      showSuccessfulInvitationsAlert: false,
 | 
			
		||||
      actionsData: this.actions,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  maxValue: Object.keys(ACTION_LABELS).length,
 | 
			
		||||
  actionSections: Object.keys(ACTION_SECTIONS),
 | 
			
		||||
  computed: {
 | 
			
		||||
    progressValue() {
 | 
			
		||||
      return Object.values(this.actions).filter((a) => a.completed).length;
 | 
			
		||||
      return Object.values(this.actionsData).filter((a) => a.completed).length;
 | 
			
		||||
    },
 | 
			
		||||
    progressPercentage() {
 | 
			
		||||
      return Math.round((this.progressValue / this.$options.maxValue) * 100);
 | 
			
		||||
| 
						 | 
				
			
			@ -43,14 +56,23 @@ export default {
 | 
			
		|||
    if (this.inviteMembersOpen) {
 | 
			
		||||
      this.openInviteMembersModal('celebrate');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    eventHub.$on('showSuccessfulInvitationsAlert', this.handleShowSuccessfulInvitationsAlert);
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    eventHub.$off('showSuccessfulInvitationsAlert', this.handleShowSuccessfulInvitationsAlert);
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    openInviteMembersModal(mode) {
 | 
			
		||||
      eventHub.$emit('openModal', { mode, inviteeType: 'members', source: 'learn-gitlab' });
 | 
			
		||||
    },
 | 
			
		||||
    handleShowSuccessfulInvitationsAlert() {
 | 
			
		||||
      this.showSuccessfulInvitationsAlert = true;
 | 
			
		||||
      this.markActionAsCompleted('userAdded');
 | 
			
		||||
    },
 | 
			
		||||
    actionsFor(section) {
 | 
			
		||||
      const actions = Object.fromEntries(
 | 
			
		||||
        Object.entries(this.actions).filter(
 | 
			
		||||
        Object.entries(this.actionsData).filter(
 | 
			
		||||
          ([action]) => ACTION_LABELS[action].section === section,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
| 
						 | 
				
			
			@ -59,11 +81,34 @@ export default {
 | 
			
		|||
    svgFor(section) {
 | 
			
		||||
      return this.sections[section].svg;
 | 
			
		||||
    },
 | 
			
		||||
    markActionAsCompleted(completedAction) {
 | 
			
		||||
      Object.keys(this.actionsData).forEach((action) => {
 | 
			
		||||
        if (action === completedAction) {
 | 
			
		||||
          this.actionsData[action].completed = true;
 | 
			
		||||
          this.modifySidebarPercentage();
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    modifySidebarPercentage() {
 | 
			
		||||
      const el = document.querySelector('.sidebar-top-level-items .active .count');
 | 
			
		||||
      el.textContent = `${this.progressPercentage}%`;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <gl-alert
 | 
			
		||||
      v-if="showSuccessfulInvitationsAlert"
 | 
			
		||||
      class="gl-mt-5"
 | 
			
		||||
      @dismiss="showSuccessfulInvitationsAlert = false"
 | 
			
		||||
    >
 | 
			
		||||
      <gl-sprintf :message="$options.i18n.successfulInvitations">
 | 
			
		||||
        <template #projectName>
 | 
			
		||||
          <strong>{{ project.name }}</strong>
 | 
			
		||||
        </template>
 | 
			
		||||
      </gl-sprintf>
 | 
			
		||||
    </gl-alert>
 | 
			
		||||
    <div class="row">
 | 
			
		||||
      <div class="gl-mb-7 gl-ml-5">
 | 
			
		||||
        <h1 class="gl-font-size-h1">{{ $options.i18n.title }}</h1>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,7 @@
 | 
			
		|||
<script>
 | 
			
		||||
import { GlLink, GlIcon } from '@gitlab/ui';
 | 
			
		||||
import { isExperimentVariant } from '~/experimentation/utils';
 | 
			
		||||
import eventHub from '~/invite_members/event_hub';
 | 
			
		||||
import { s__ } from '~/locale';
 | 
			
		||||
import { ACTION_LABELS } from '../constants';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +26,20 @@ export default {
 | 
			
		|||
    trialOnly() {
 | 
			
		||||
      return ACTION_LABELS[this.action].trialRequired;
 | 
			
		||||
    },
 | 
			
		||||
    showInviteModalLink() {
 | 
			
		||||
      return (
 | 
			
		||||
        this.action === 'userAdded' && isExperimentVariant('invite_for_help_continuous_onboarding')
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    openModal() {
 | 
			
		||||
      eventHub.$emit('openModal', {
 | 
			
		||||
        inviteeType: 'members',
 | 
			
		||||
        source: 'learn_gitlab',
 | 
			
		||||
        tasksToBeDoneEnabled: true,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -33,8 +49,18 @@ export default {
 | 
			
		|||
      <gl-icon name="check-circle-filled" :size="16" data-testid="completed-icon" />
 | 
			
		||||
      {{ $options.i18n.ACTION_LABELS[action].title }}
 | 
			
		||||
    </span>
 | 
			
		||||
    <span v-else>
 | 
			
		||||
    <gl-link
 | 
			
		||||
      v-else-if="showInviteModalLink"
 | 
			
		||||
      data-track-action="click_link"
 | 
			
		||||
      :data-track-label="$options.i18n.ACTION_LABELS[action].title"
 | 
			
		||||
      data-track-property="Growth::Activation::Experiment::InviteForHelpContinuousOnboarding"
 | 
			
		||||
      data-testid="invite-for-help-continuous-onboarding-experiment-link"
 | 
			
		||||
      @click="openModal"
 | 
			
		||||
    >
 | 
			
		||||
      {{ $options.i18n.ACTION_LABELS[action].title }}
 | 
			
		||||
    </gl-link>
 | 
			
		||||
    <gl-link
 | 
			
		||||
      v-else
 | 
			
		||||
      target="_blank"
 | 
			
		||||
      :href="value.url"
 | 
			
		||||
      data-track-action="click_link"
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +70,6 @@ export default {
 | 
			
		|||
    >
 | 
			
		||||
      {{ $options.i18n.ACTION_LABELS[action].title }}
 | 
			
		||||
    </gl-link>
 | 
			
		||||
    </span>
 | 
			
		||||
    <span v-if="trialOnly" class="gl-font-style-italic gl-text-gray-500" data-testid="trial-only">
 | 
			
		||||
      - {{ $options.i18n.trialOnly }}
 | 
			
		||||
    </span>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,17 +12,18 @@ function initLearnGitlab() {
 | 
			
		|||
 | 
			
		||||
  const actions = convertObjectPropsToCamelCase(JSON.parse(el.dataset.actions));
 | 
			
		||||
  const sections = convertObjectPropsToCamelCase(JSON.parse(el.dataset.sections));
 | 
			
		||||
  const project = convertObjectPropsToCamelCase(JSON.parse(el.dataset.project));
 | 
			
		||||
  const { inviteMembersOpen } = el.dataset;
 | 
			
		||||
 | 
			
		||||
  return new Vue({
 | 
			
		||||
    el,
 | 
			
		||||
    render(createElement) {
 | 
			
		||||
      return createElement(LearnGitlab, {
 | 
			
		||||
        props: { actions, sections, inviteMembersOpen },
 | 
			
		||||
        props: { actions, sections, project, inviteMembersOpen },
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
initInviteMembersModal();
 | 
			
		||||
initLearnGitlab();
 | 
			
		||||
initInviteMembersModal();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@
 | 
			
		|||
class Projects::LearnGitlabController < Projects::ApplicationController
 | 
			
		||||
  before_action :authenticate_user!
 | 
			
		||||
  before_action :check_experiment_enabled?
 | 
			
		||||
  before_action :enable_invite_for_help_continuous_onboarding_experiment
 | 
			
		||||
 | 
			
		||||
  feature_category :users
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,4 +15,13 @@ class Projects::LearnGitlabController < Projects::ApplicationController
 | 
			
		|||
  def check_experiment_enabled?
 | 
			
		||||
    return access_denied! unless helpers.learn_gitlab_enabled?(project)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def enable_invite_for_help_continuous_onboarding_experiment
 | 
			
		||||
    return unless current_user.can?(:admin_group_member, project.namespace)
 | 
			
		||||
 | 
			
		||||
    experiment(:invite_for_help_continuous_onboarding, namespace: project.namespace) do |e|
 | 
			
		||||
      e.candidate {}
 | 
			
		||||
      e.record!
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ module InviteMembersHelper
 | 
			
		|||
      e.candidate { dataset.merge!(areas_of_focus_options: member_areas_of_focus_options.to_json, no_selection_areas_of_focus: ['no_selection']) }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if show_invite_members_for_task?
 | 
			
		||||
    if show_invite_members_for_task?(source)
 | 
			
		||||
      dataset.merge!(
 | 
			
		||||
        tasks_to_be_done_options: tasks_to_be_done_options.to_json,
 | 
			
		||||
        projects: projects_for_source(source).to_json,
 | 
			
		||||
| 
						 | 
				
			
			@ -80,10 +80,12 @@ module InviteMembersHelper
 | 
			
		|||
    {}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show_invite_members_for_task?
 | 
			
		||||
    return unless current_user && experiment(:invite_members_for_task).enabled?
 | 
			
		||||
  def show_invite_members_for_task?(source)
 | 
			
		||||
    return unless current_user
 | 
			
		||||
 | 
			
		||||
    params[:open_modal] == 'invite_members_for_task'
 | 
			
		||||
    invite_members_for_task_experiment = experiment(:invite_members_for_task).enabled? && params[:open_modal] == 'invite_members_for_task'
 | 
			
		||||
    invite_for_help_continuous_onboarding = source.is_a?(Project) && experiment(:invite_for_help_continuous_onboarding, namespace: source.namespace).variant.name == 'candidate'
 | 
			
		||||
    invite_members_for_task_experiment || invite_for_help_continuous_onboarding
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def tasks_to_be_done_options
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,8 @@ module LearnGitlabHelper
 | 
			
		|||
  def learn_gitlab_data(project)
 | 
			
		||||
    {
 | 
			
		||||
      actions: onboarding_actions_data(project).to_json,
 | 
			
		||||
      sections: onboarding_sections_data.to_json
 | 
			
		||||
      sections: onboarding_sections_data.to_json,
 | 
			
		||||
      project: onboarding_project_data(project).to_json
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +57,10 @@ module LearnGitlabHelper
 | 
			
		|||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def onboarding_project_data(project)
 | 
			
		||||
    { name: project.name }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def action_urls
 | 
			
		||||
    LearnGitlab::Onboarding::ACTION_ISSUE_IDS.transform_values { |id| project_issue_url(learn_gitlab_project, id) }
 | 
			
		||||
      .merge(LearnGitlab::Onboarding::ACTION_DOC_URLS)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,11 +12,7 @@ class U2fRegistration < ApplicationRecord
 | 
			
		|||
    converter = Gitlab::Auth::U2fWebauthnConverter.new(self)
 | 
			
		||||
    WebauthnRegistration.create!(converter.convert)
 | 
			
		||||
  rescue StandardError => ex
 | 
			
		||||
    Gitlab::AppJsonLogger.error(
 | 
			
		||||
      event: 'u2f_migration',
 | 
			
		||||
      error: ex.class.name,
 | 
			
		||||
      backtrace: ::Gitlab::BacktraceCleaner.clean_backtrace(ex.backtrace),
 | 
			
		||||
      message: "U2F to WebAuthn conversion failed")
 | 
			
		||||
    Gitlab::ErrorTracking.track_exception(ex, u2f_registration_id: self.id)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update_webauthn_registration
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1614,8 +1614,14 @@ class User < ApplicationRecord
 | 
			
		|||
        .joins(:runner)
 | 
			
		||||
        .select('ci_runners.*')
 | 
			
		||||
 | 
			
		||||
      base_and_descendants = if Feature.enabled?(:linear_user_ci_owned_runners, self, default_enabled: :yaml)
 | 
			
		||||
                               owned_groups.self_and_descendant_ids
 | 
			
		||||
                             else
 | 
			
		||||
                               Gitlab::ObjectHierarchy.new(owned_groups).base_and_descendants.select(:id)
 | 
			
		||||
                             end
 | 
			
		||||
 | 
			
		||||
      group_runners = Ci::RunnerNamespace
 | 
			
		||||
        .where(namespace_id: Gitlab::ObjectHierarchy.new(owned_groups).base_and_descendants.select(:id))
 | 
			
		||||
        .where(namespace_id: base_and_descendants)
 | 
			
		||||
        .joins(:runner)
 | 
			
		||||
        .select('ci_runners.*')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,9 +4,10 @@
 | 
			
		|||
- data = learn_gitlab_data(@project)
 | 
			
		||||
- invite_members_open = session.delete(:confetti_post_signup)
 | 
			
		||||
 | 
			
		||||
= render 'projects/invite_members_modal', project: @project
 | 
			
		||||
 | 
			
		||||
- experiment(:confetti_post_signup, actor: current_user) do |e|
 | 
			
		||||
  - e.control do
 | 
			
		||||
    #js-learn-gitlab-app{ data: data }
 | 
			
		||||
  - e.candidate do
 | 
			
		||||
    = render 'projects/invite_members_modal', project: @project
 | 
			
		||||
    #js-learn-gitlab-app{ data: data.merge(invite_members_open: invite_members_open) }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
---
 | 
			
		||||
name: linear_user_ci_owned_runners
 | 
			
		||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68848
 | 
			
		||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339435
 | 
			
		||||
milestone: '14.6'
 | 
			
		||||
type: development
 | 
			
		||||
group: group::access
 | 
			
		||||
default_enabled: false
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
---
 | 
			
		||||
name: invite_for_help_continuous_onboarding
 | 
			
		||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73846
 | 
			
		||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345708
 | 
			
		||||
milestone: '14.5'
 | 
			
		||||
type: experiment
 | 
			
		||||
group: group::activation
 | 
			
		||||
default_enabled: false
 | 
			
		||||
| 
						 | 
				
			
			@ -1,83 +1,9 @@
 | 
			
		|||
---
 | 
			
		||||
stage: Enablement
 | 
			
		||||
group: Distribution
 | 
			
		||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
 | 
			
		||||
redirect_to: 'supported_os.md'
 | 
			
		||||
remove_date: '2022-02-18'
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# OS Versions that are no longer supported **(FREE SELF)**
 | 
			
		||||
This document was moved to [another location](supported_os.md).
 | 
			
		||||
 | 
			
		||||
GitLab provides omnibus packages for operating systems only until their
 | 
			
		||||
EOL (End-Of-Life). After the EOL date of the OS, GitLab will stop releasing
 | 
			
		||||
official packages. The list of deprecated operating systems and the final GitLab
 | 
			
		||||
release for them can be found below:
 | 
			
		||||
 | 
			
		||||
| OS Version      | End Of Life                                                                        | Last supported GitLab version                                                                                                                                                                                                                              |
 | 
			
		||||
| --------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| Raspbian Wheezy | [May 2015](https://downloads.raspberrypi.org/raspbian/images/raspbian-2015-05-07/) | [GitLab CE](https://packages.gitlab.com/app/gitlab/raspberry-pi2/search?q=gitlab-ce_8.17&dist=debian%2Fwheezy) 8.17                                                                                                                                        |
 | 
			
		||||
| OpenSUSE 13.2   | [January 2017](https://en.opensuse.org/Lifetime#Discontinued_distributions)        | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-9.1&dist=opensuse%2F13.2) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-9.1&dist=opensuse%2F13.2) 9.1                                  |
 | 
			
		||||
| Ubuntu 12.04    | [April 2017](https://ubuntu.com/info/release-end-of-life)                          | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_9.1&dist=ubuntu%2Fprecise) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_9.1&dist=ubuntu%2Fprecise) 9.1                                |
 | 
			
		||||
| OpenSUSE 42.1   | [May 2017](https://en.opensuse.org/Lifetime#Discontinued_distributions)            | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-9.3&dist=opensuse%2F42.1) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-9.3&dist=opensuse%2F42.1) 9.3                                  |
 | 
			
		||||
| OpenSUSE 42.2   | [January 2018](https://en.opensuse.org/Lifetime#Discontinued_distributions)        | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-10.4&dist=opensuse%2F42.2) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-10.4&dist=opensuse%2F42.2) 10.4                               |
 | 
			
		||||
| Debian Wheezy   | [May 2018](https://www.debian.org/News/2018/20180601)                              | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_11.6&dist=debian%2Fwheezy) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_11.6&dist=debian%2Fwheezy) 11.6                               |
 | 
			
		||||
| Raspbian Jessie | [May 2017](https://downloads.raspberrypi.org/raspbian/images/raspbian-2017-07-05/) | [GitLab CE](https://packages.gitlab.com/app/gitlab/raspberry-pi2/search?q=gitlab-ce_11.7&dist=debian%2Fjessie) 11.7                                                                                                                                        |
 | 
			
		||||
| Ubuntu 14.04    | [April 2019](https://ubuntu.com/info/release-end-of-life)                          | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_11.10&dist=ubuntu%2Ftrusty) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_11.10&dist=ubuntu%2Ftrusty) 11.10                            |
 | 
			
		||||
| OpenSUSE 42.3   | [July 2019](https://en.opensuse.org/Lifetime#Discontinued_distributions)           | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-12.1&dist=opensuse%2F42.3) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-12.1&dist=opensuse%2F42.3) 12.1                               |
 | 
			
		||||
| OpenSUSE 15.0   | [December 2019](https://en.opensuse.org/Lifetime#Discontinued_distributions)       | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-12.5&dist=opensuse%2F15.0) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-12.5&dist=opensuse%2F15.0) 12.5                               |
 | 
			
		||||
| Raspbian Stretch | [June 2020](https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/)  | [GitLab CE](https://packages.gitlab.com/app/gitlab/raspberry-pi2/search?q=gitlab-ce_13.2&dist=raspbian%2Fstretch) 13.3                                                                                                                                  |
 | 
			
		||||
| Debian Jessie    | [June 2020](https://www.debian.org/News/2020/20200709)                               | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_13.2&dist=debian%2Fjessie) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_13.2&dist=debian%2Fjessie) 13.3                            |
 | 
			
		||||
| CentOS 6         | [November 2020](https://wiki.centos.org/About/Product)                               | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=13.6&filter=all&filter=all&dist=el%2F6) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=13.6&filter=all&filter=all&dist=el%2F6) 13.6              |
 | 
			
		||||
| OpenSUSE 15.1   | [November 2020](https://en.opensuse.org/Lifetime#Discontinued_distributions)          | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-13.12&dist=opensuse%2F15.1) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-13.12&dist=opensuse%2F15.2) 13.12                 |
 | 
			
		||||
| Ubuntu 16.04    | [April 2021](https://ubuntu.com/info/release-end-of-life)                          | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_13.12&dist=ubuntu%2Fxenial) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_13.12&dist=ubuntu%2Fxenial) 13.12                                |
 | 
			
		||||
 | 
			
		||||
NOTE:
 | 
			
		||||
An exception to this deprecation policy is when we are unable to provide
 | 
			
		||||
packages for the next version of the operating system. The most common reason
 | 
			
		||||
for this our package repository provider, Packagecloud, not supporting newer
 | 
			
		||||
versions and hence we can't upload packages to it.
 | 
			
		||||
 | 
			
		||||
## Update GitLab package sources after upgrading the OS
 | 
			
		||||
 | 
			
		||||
After upgrading the Operating System (OS) as per its own documentation,
 | 
			
		||||
it may be necessary to also update the GitLab package source URL
 | 
			
		||||
in your package manager configuration.
 | 
			
		||||
If your package manager reports that no further updates are available,
 | 
			
		||||
although [new versions have been released](https://about.gitlab.com/releases/categories/releases/), repeat the
 | 
			
		||||
"Add the GitLab package repository" instructions
 | 
			
		||||
of the [Linux package install guide](https://about.gitlab.com/install/#content).
 | 
			
		||||
Future GitLab upgrades will now be fetched according to your upgraded OS.
 | 
			
		||||
 | 
			
		||||
## Supported Operating Systems
 | 
			
		||||
 | 
			
		||||
GitLab officially supports LTS versions of operating systems. While OSs like
 | 
			
		||||
Ubuntu have a clear distinction between LTS and non-LTS versions, there are
 | 
			
		||||
other OSs, openSUSE for example, that don't follow the LTS concept. Hence to
 | 
			
		||||
avoid confusion, the official policy is that at any point of time, all the
 | 
			
		||||
operating systems supported by GitLab are listed in the [installation
 | 
			
		||||
page](https://about.gitlab.com/install/).
 | 
			
		||||
 | 
			
		||||
The following lists the currently supported OSs and their possible EOL dates.
 | 
			
		||||
 | 
			
		||||
| OS Version       | First supported GitLab version | Arch            | OS EOL        | Details                                                      |
 | 
			
		||||
| ---------------- | ------------------------------ | --------------- | ------------- | ------------------------------------------------------------ |
 | 
			
		||||
| CentOS 7         | GitLab CE / GitLab EE 7.10.0   | x86_64          | June 2024     | <https://wiki.centos.org/About/Product>                      |
 | 
			
		||||
| CentOS 8         | GitLab CE / GitLab EE 12.8.1   | x86_64, aarch64 | Dec 2021      | <https://wiki.centos.org/About/Product>                      |
 | 
			
		||||
| Debian 9         | GitLab CE / GitLab EE 9.3.0    | amd64           | 2022          | <https://wiki.debian.org/DebianReleases#Production_Releases> |
 | 
			
		||||
| Debian 10        | GitLab CE / GitLab EE 12.2.0   | amd64, arm64    | TBD           | <https://wiki.debian.org/DebianReleases#Production_Releases> |
 | 
			
		||||
| OpenSUSE 15.2    | GitLab CE / GitLab EE 13.11.0  | x86_64, aarch64 | Dec 2021      | <https://en.opensuse.org/Lifetime>                           |
 | 
			
		||||
| OpenSUSE 15.3    | GitLab CE / GitLab EE 14.5.0   | x86_64, aarch64 | Nov 2022      | <https://en.opensuse.org/Lifetime>                           |
 | 
			
		||||
| SLES 12          | GitLab EE 9.0.0                | x86_64          | Oct 2027      | <https://www.suse.com/lifecycle/>                            |
 | 
			
		||||
| Ubuntu 18.04     | GitLab CE / GitLab EE 10.7.0   | amd64           | April 2023    | <https://wiki.ubuntu.com/Releases>                           |
 | 
			
		||||
| Ubuntu 20.04     | GitLab CE / GitLab EE 13.2.0   | amd64, arm64    | April 2025    | <https://wiki.ubuntu.com/Releases>                           |
 | 
			
		||||
| Raspbian Buster  | GitLab CE 12.2.0               | armhf           | 2022          | <https://wiki.debian.org/DebianReleases#Production_Releases> |
 | 
			
		||||
 | 
			
		||||
### Packages for ARM64
 | 
			
		||||
 | 
			
		||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-omnibus-builder/-/issues/27) in GitLab 13.4.
 | 
			
		||||
 | 
			
		||||
GitLab provides arm64/aarch64 packages for some supported operating systems.
 | 
			
		||||
You can see if your operating system architecture is supported in the table
 | 
			
		||||
above.
 | 
			
		||||
 | 
			
		||||
WARNING:
 | 
			
		||||
There are currently still some [known issues and limitation](https://gitlab.com/groups/gitlab-org/-/epics/4397)
 | 
			
		||||
running GitLab on ARM.
 | 
			
		||||
<!-- This redirect file can be deleted after <2022-02-18>. -->
 | 
			
		||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,89 @@
 | 
			
		|||
---
 | 
			
		||||
stage: Enablement
 | 
			
		||||
group: Distribution
 | 
			
		||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Supported Operating Systems
 | 
			
		||||
 | 
			
		||||
GitLab officially supports LTS versions of operating systems. While OSs like
 | 
			
		||||
Ubuntu have a clear distinction between LTS and non-LTS versions, there are
 | 
			
		||||
other OSs, openSUSE for example, that don't follow the LTS concept. Hence to
 | 
			
		||||
avoid confusion, the official policy is that at any point of time, all the
 | 
			
		||||
operating systems supported by GitLab are listed in the [installation
 | 
			
		||||
page](https://about.gitlab.com/install/).
 | 
			
		||||
 | 
			
		||||
The following lists the currently supported OSs and their possible EOL dates.
 | 
			
		||||
 | 
			
		||||
| OS Version       | First supported GitLab version | Arch            | OS EOL        | Details                                                      |
 | 
			
		||||
| ---------------- | ------------------------------ | --------------- | ------------- | ------------------------------------------------------------ |
 | 
			
		||||
| CentOS 7         | GitLab CE / GitLab EE 7.10.0   | x86_64          | June 2024     | <https://wiki.centos.org/About/Product>                      |
 | 
			
		||||
| CentOS 8         | GitLab CE / GitLab EE 12.8.1   | x86_64, aarch64 | Dec 2021      | <https://wiki.centos.org/About/Product>                      |
 | 
			
		||||
| Debian 9         | GitLab CE / GitLab EE 9.3.0    | amd64           | 2022          | <https://wiki.debian.org/DebianReleases#Production_Releases> |
 | 
			
		||||
| Debian 10        | GitLab CE / GitLab EE 12.2.0   | amd64, arm64    | TBD           | <https://wiki.debian.org/DebianReleases#Production_Releases> |
 | 
			
		||||
| OpenSUSE 15.2    | GitLab CE / GitLab EE 13.11.0  | x86_64, aarch64 | Dec 2021      | <https://en.opensuse.org/Lifetime>                           |
 | 
			
		||||
| OpenSUSE 15.3    | GitLab CE / GitLab EE 14.5.0   | x86_64, aarch64 | Nov 2022      | <https://en.opensuse.org/Lifetime>                           |
 | 
			
		||||
| SLES 12          | GitLab EE 9.0.0                | x86_64          | Oct 2027      | <https://www.suse.com/lifecycle/>                            |
 | 
			
		||||
| Ubuntu 18.04     | GitLab CE / GitLab EE 10.7.0   | amd64           | April 2023    | <https://wiki.ubuntu.com/Releases>                           |
 | 
			
		||||
| Ubuntu 20.04     | GitLab CE / GitLab EE 13.2.0   | amd64, arm64    | April 2025    | <https://wiki.ubuntu.com/Releases>                           |
 | 
			
		||||
| Raspbian Buster  | GitLab CE 12.2.0               | armhf           | 2022          | <https://wiki.debian.org/DebianReleases#Production_Releases> |
 | 
			
		||||
 | 
			
		||||
NOTE:
 | 
			
		||||
CentOS 8 will be EOL on December 31, 2021. In GitLab 14.5 and later,
 | 
			
		||||
[CentOS builds work in AlmaLinux](https://gitlab.com/gitlab-org/distribution/team-tasks/-/issues/954#note_730198505).
 | 
			
		||||
We will officially support all distributions that are binary compatible with Red Hat Enterprise Linux.
 | 
			
		||||
This gives users a path forward for their CentOS 8 builds at its end of life.
 | 
			
		||||
 | 
			
		||||
## Update GitLab package sources after upgrading the OS
 | 
			
		||||
 | 
			
		||||
After upgrading the Operating System (OS) as per its own documentation,
 | 
			
		||||
it may be necessary to also update the GitLab package source URL
 | 
			
		||||
in your package manager configuration.
 | 
			
		||||
If your package manager reports that no further updates are available,
 | 
			
		||||
although [new versions have been released](https://about.gitlab.com/releases/categories/releases/), repeat the
 | 
			
		||||
"Add the GitLab package repository" instructions
 | 
			
		||||
of the [Linux package install guide](https://about.gitlab.com/install/#content).
 | 
			
		||||
Future GitLab upgrades will now be fetched according to your upgraded OS.
 | 
			
		||||
 | 
			
		||||
## Packages for ARM64
 | 
			
		||||
 | 
			
		||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-omnibus-builder/-/issues/27) in GitLab 13.4.
 | 
			
		||||
 | 
			
		||||
GitLab provides arm64/aarch64 packages for some supported operating systems.
 | 
			
		||||
You can see if your operating system architecture is supported in the table
 | 
			
		||||
above.
 | 
			
		||||
 | 
			
		||||
WARNING:
 | 
			
		||||
There are currently still some [known issues and limitation](https://gitlab.com/groups/gitlab-org/-/epics/4397)
 | 
			
		||||
running GitLab on ARM.
 | 
			
		||||
 | 
			
		||||
## OS Versions that are no longer supported **(FREE SELF)**
 | 
			
		||||
 | 
			
		||||
GitLab provides omnibus packages for operating systems only until their
 | 
			
		||||
EOL (End-Of-Life). After the EOL date of the OS, GitLab will stop releasing
 | 
			
		||||
official packages. The list of deprecated operating systems and the final GitLab
 | 
			
		||||
release for them can be found below:
 | 
			
		||||
 | 
			
		||||
| OS Version      | End Of Life                                                                        | Last supported GitLab version                                                                                                                                                                                                      |
 | 
			
		||||
| --------------- | ---------------------------------------------------------------------------------- | -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
 | 
			
		||||
| Raspbian Wheezy | [May 2015](https://downloads.raspberrypi.org/raspbian/images/raspbian-2015-05-07/) | [GitLab CE](https://packages.gitlab.com/app/gitlab/raspberry-pi2/search?q=gitlab-ce_8.17&dist=debian%2Fwheezy) 8.17                                                                                                                |
 | 
			
		||||
| OpenSUSE 13.2   | [January 2017](https://en.opensuse.org/Lifetime#Discontinued_distributions)        | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-9.1&dist=opensuse%2F13.2) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-9.1&dist=opensuse%2F13.2) 9.1          |
 | 
			
		||||
| Ubuntu 12.04    | [April 2017](https://ubuntu.com/info/release-end-of-life)                          | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_9.1&dist=ubuntu%2Fprecise) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_9.1&dist=ubuntu%2Fprecise) 9.1        |
 | 
			
		||||
| OpenSUSE 42.1   | [May 2017](https://en.opensuse.org/Lifetime#Discontinued_distributions)            | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-9.3&dist=opensuse%2F42.1) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-9.3&dist=opensuse%2F42.1) 9.3          |
 | 
			
		||||
| OpenSUSE 42.2   | [January 2018](https://en.opensuse.org/Lifetime#Discontinued_distributions)        | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-10.4&dist=opensuse%2F42.2) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-10.4&dist=opensuse%2F42.2) 10.4       |
 | 
			
		||||
| Debian Wheezy   | [May 2018](https://www.debian.org/News/2018/20180601)                              | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_11.6&dist=debian%2Fwheezy) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_11.6&dist=debian%2Fwheezy) 11.6       |
 | 
			
		||||
| Raspbian Jessie | [May 2017](https://downloads.raspberrypi.org/raspbian/images/raspbian-2017-07-05/) | [GitLab CE](https://packages.gitlab.com/app/gitlab/raspberry-pi2/search?q=gitlab-ce_11.7&dist=debian%2Fjessie) 11.7                                                                                                                |
 | 
			
		||||
| Ubuntu 14.04    | [April 2019](https://ubuntu.com/info/release-end-of-life)                          | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_11.10&dist=ubuntu%2Ftrusty) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_11.10&dist=ubuntu%2Ftrusty) 11.10    |
 | 
			
		||||
| OpenSUSE 42.3   | [July 2019](https://en.opensuse.org/Lifetime#Discontinued_distributions)           | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-12.1&dist=opensuse%2F42.3) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-12.1&dist=opensuse%2F42.3) 12.1       |
 | 
			
		||||
| OpenSUSE 15.0   | [December 2019](https://en.opensuse.org/Lifetime#Discontinued_distributions)       | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-12.5&dist=opensuse%2F15.0) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-12.5&dist=opensuse%2F15.0) 12.5       |
 | 
			
		||||
| Raspbian Stretch | [June 2020](https://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/) | [GitLab CE](https://packages.gitlab.com/app/gitlab/raspberry-pi2/search?q=gitlab-ce_13.2&dist=raspbian%2Fstretch) 13.3                                                                                                           |
 | 
			
		||||
| Debian Jessie   | [June 2020](https://www.debian.org/News/2020/20200709)                             | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_13.2&dist=debian%2Fjessie) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_13.2&dist=debian%2Fjessie) 13.3       |
 | 
			
		||||
| CentOS 6        | [November 2020](https://wiki.centos.org/About/Product)                             | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=13.6&filter=all&filter=all&dist=el%2F6) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=13.6&filter=all&filter=all&dist=el%2F6) 13.6 |
 | 
			
		||||
| OpenSUSE 15.1   | [November 2020](https://en.opensuse.org/Lifetime#Discontinued_distributions)       | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce-13.12&dist=opensuse%2F15.1) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee-13.12&dist=opensuse%2F15.2) 13.12    |
 | 
			
		||||
| Ubuntu 16.04    | [April 2021](https://ubuntu.com/info/release-end-of-life)                          | [GitLab CE](https://packages.gitlab.com/app/gitlab/gitlab-ce/search?q=gitlab-ce_13.12&dist=ubuntu%2Fxenial) / [GitLab EE](https://packages.gitlab.com/app/gitlab/gitlab-ee/search?q=gitlab-ee_13.12&dist=ubuntu%2Fxenial) 13.12    |
 | 
			
		||||
 | 
			
		||||
NOTE:
 | 
			
		||||
An exception to this deprecation policy is when we are unable to provide
 | 
			
		||||
packages for the next version of the operating system. The most common reason
 | 
			
		||||
for this our package repository provider, PackageCloud, not supporting newer
 | 
			
		||||
versions and hence we can't upload packages to it.
 | 
			
		||||
| 
						 | 
				
			
			@ -1281,7 +1281,7 @@ in all of your GitLab Pages instances.
 | 
			
		|||
 | 
			
		||||
### 500 error with `securecookie: failed to generate random iv` and `Failed to save the session`
 | 
			
		||||
 | 
			
		||||
This problem most likely results from an [out-dated operating system](../package_information/deprecated_os.md).
 | 
			
		||||
This problem most likely results from an [out-dated operating system](../package_information/supported_os.md#os-versions-that-are-no-longer-supported).
 | 
			
		||||
The [Pages daemon uses the `securecookie` library](https://gitlab.com/search?group_id=9970&project_id=734943&repository_ref=master&scope=blobs&search=securecookie&snippets=false) to get random strings via [`crypto/rand` in Go](https://golang.org/pkg/crypto/rand/#pkg-variables).
 | 
			
		||||
This requires the `getrandom` system call or `/dev/urandom` to be available on the host OS.
 | 
			
		||||
Upgrading to an [officially supported operating system](https://about.gitlab.com/install/) is recommended.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -618,7 +618,7 @@ users.count
 | 
			
		|||
# If that count looks sane:
 | 
			
		||||
 | 
			
		||||
# You can either block the users:
 | 
			
		||||
users.each { |user| user.block! }
 | 
			
		||||
users.each { |user|  user.blocked? ? nil  : user.block! }
 | 
			
		||||
 | 
			
		||||
# Or you can delete them:
 | 
			
		||||
  # need 'current user' (your user) for auditing purposes
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ For the installation options, see [the main installation page](index.md).
 | 
			
		|||
Installation of GitLab on these operating systems is possible, but not supported.
 | 
			
		||||
Please see the [installation from source guide](installation.md) and the [installation guides](https://about.gitlab.com/install/) for more information.
 | 
			
		||||
 | 
			
		||||
Please see [OS versions that are no longer supported](../administration/package_information/deprecated_os.md) for Omnibus installs page
 | 
			
		||||
Please see [OS versions that are no longer supported](../administration/package_information/supported_os.md#os-versions-that-are-no-longer-supported) for Omnibus installs page
 | 
			
		||||
for a list of supported and unsupported OS versions as well as the last support GitLab version for that OS.
 | 
			
		||||
 | 
			
		||||
### Microsoft Windows
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,15 +20,15 @@ NOTE:
 | 
			
		|||
GitLab submits all issues to Akismet.
 | 
			
		||||
 | 
			
		||||
Akismet configuration is available to users on self-managed GitLab. Akismet is already enabled on
 | 
			
		||||
GitLab SaaS (GitLab.com), where it's configuration and management are handled by GitLab Inc.
 | 
			
		||||
GitLab SaaS (GitLab.com), where its configuration and management are handled by GitLab Inc.
 | 
			
		||||
 | 
			
		||||
## Configuration **(FREE SELF)**
 | 
			
		||||
## Configure Akismet **(FREE SELF)**
 | 
			
		||||
 | 
			
		||||
To use Akismet:
 | 
			
		||||
 | 
			
		||||
1. Go to the [Akismet sign-in page](https://akismet.com/account/).
 | 
			
		||||
1. Sign in or create a new account.
 | 
			
		||||
1. Click **Show** to reveal the API key, and copy the API key's value.
 | 
			
		||||
1. Select **Show** to reveal the API key, and copy the API key's value.
 | 
			
		||||
1. Sign in to GitLab as an administrator.
 | 
			
		||||
1. On the top bar, select **Menu > Admin**.
 | 
			
		||||
1. On the left sidebar, select **Settings > Reporting** (`/admin/application_settings/reporting`).
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ To use Akismet:
 | 
			
		|||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## Training **(FREE SELF)**
 | 
			
		||||
## Train the Akismet filter **(FREE SELF)**
 | 
			
		||||
 | 
			
		||||
To better differentiate between spam and ham, you can train the Akismet
 | 
			
		||||
filter whenever there is a false positive or false negative.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -317,39 +317,65 @@ main quota. You can find pricing for additional CI/CD minutes on the
 | 
			
		|||
- Are only used after the shared quota included in your subscription runs out.
 | 
			
		||||
- Roll over month to month.
 | 
			
		||||
 | 
			
		||||
To purchase additional minutes for your group on GitLab SaaS:
 | 
			
		||||
 | 
			
		||||
1. From your group, go to **Settings > Usage Quotas**.
 | 
			
		||||
1. Select **Buy additional minutes** and GitLab directs you to the Customers Portal.
 | 
			
		||||
1. Locate the subscription card that's linked to your group on GitLab SaaS, click **Buy more CI minutes**, and complete the details about the transaction.
 | 
			
		||||
1. Once we have processed your payment, the extra CI minutes are synced to your group namespace.
 | 
			
		||||
1. To confirm the available CI minutes, go to your group, then **Settings > Usage Quotas**.
 | 
			
		||||
 | 
			
		||||
   The **Additional minutes** displayed now includes the purchased additional CI minutes, plus any minutes rolled over from last month.
 | 
			
		||||
 | 
			
		||||
To purchase additional minutes for your personal namespace:
 | 
			
		||||
 | 
			
		||||
1. In the top-right corner, select your avatar.
 | 
			
		||||
1. Select **Edit profile**.
 | 
			
		||||
1. On the left sidebar, select **Usage Quotas**.
 | 
			
		||||
1. Select **Buy additional minutes** and GitLab redirects you to the Customers Portal.
 | 
			
		||||
1. Locate the subscription card that's linked to your personal namespace on GitLab SaaS, click **Buy more CI minutes**, and complete the details about the transaction. Once we have processed your payment, the extra CI minutes are synced to your personal namespace.
 | 
			
		||||
1. To confirm the available CI minutes for your personal projects, go to the **Usage Quotas** settings again.
 | 
			
		||||
1. Locate the subscription card that's linked to your personal namespace on GitLab SaaS, click **Buy more CI minutes**, and complete the details about the transaction. 
 | 
			
		||||
 | 
			
		||||
   The **Additional minutes** displayed now includes the purchased additional CI minutes, plus any minutes rolled over from last month.
 | 
			
		||||
After we process your payment, the extra CI minutes are synced to your group
 | 
			
		||||
namespace.
 | 
			
		||||
 | 
			
		||||
To confirm the available CI minutes for your personal projects, go to the **Usage Quotas** settings again.
 | 
			
		||||
 | 
			
		||||
The **Additional minutes** displayed now includes the purchased additional CI
 | 
			
		||||
minutes, plus any minutes rolled over from last month.
 | 
			
		||||
 | 
			
		||||
Be aware that:
 | 
			
		||||
 | 
			
		||||
- If you have purchased extra CI minutes before the purchase of a paid plan,
 | 
			
		||||
  we calculate a pro-rated charge for your paid plan. That means you may
 | 
			
		||||
  be charged for less than one year because your subscription was previously
 | 
			
		||||
  created with the extra CI minutes.
 | 
			
		||||
- After the extra CI minutes have been assigned to a Group, they can't be transferred
 | 
			
		||||
  to a different Group by themselves, but they will transfer along with a subscription when
 | 
			
		||||
  changing the linked namespace for the subscription.
 | 
			
		||||
- If you have used more minutes than your default quota, these minutes will
 | 
			
		||||
  be deducted from your Additional Minutes quota immediately after your purchase of additional
 | 
			
		||||
  minutes.
 | 
			
		||||
- Extra CI minutes assigned to one group cannot be transferred to a different
 | 
			
		||||
  group.
 | 
			
		||||
- If you have used more minutes than your default quota, those minutes are
 | 
			
		||||
  deducted from your Additional Minutes quota immediately after your purchase of
 | 
			
		||||
  additional minutes.
 | 
			
		||||
 | 
			
		||||
### Purchase additional CI minutes on GitLab SaaS
 | 
			
		||||
 | 
			
		||||
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6574) in GitLab 14.5.
 | 
			
		||||
 | 
			
		||||
If you're using GitLab SaaS, you can purchase additional CI minutes so your
 | 
			
		||||
pipelines aren't blocked after you have used all your CI minutes from your
 | 
			
		||||
main quota. You can find pricing for additional CI/CD minutes on the
 | 
			
		||||
[GitLab Pricing page](https://about.gitlab.com/pricing/). Additional minutes:
 | 
			
		||||
 | 
			
		||||
- Are only used after the shared quota included in your subscription runs out.
 | 
			
		||||
- Roll over month to month.
 | 
			
		||||
 | 
			
		||||
To purchase additional minutes for your group on GitLab SaaS:
 | 
			
		||||
 | 
			
		||||
1. On the top bar, select **Menu > Groups** and find your group.
 | 
			
		||||
1. On the left sidebar, select **Settings > Usage Quotas**.
 | 
			
		||||
1. Select **Buy additional minutes**.
 | 
			
		||||
1. Complete the details about the transaction.
 | 
			
		||||
 | 
			
		||||
After we process your payment, the extra CI minutes are synced to your group
 | 
			
		||||
namespace.
 | 
			
		||||
 | 
			
		||||
To confirm the available CI minutes, go to your group, and then select
 | 
			
		||||
**Settings > Usage Quotas**.
 | 
			
		||||
 | 
			
		||||
The **Additional minutes** displayed now includes the purchased additional CI
 | 
			
		||||
minutes, plus any minutes rolled over from last month.
 | 
			
		||||
 | 
			
		||||
Be aware that:
 | 
			
		||||
 | 
			
		||||
- Extra CI minutes assigned to one group cannot be transferred to a different
 | 
			
		||||
  group.
 | 
			
		||||
- If you have used more minutes than your default quota, those minutes are
 | 
			
		||||
  deducted from your Additional Minutes quota immediately after your purchase of
 | 
			
		||||
  additional minutes.
 | 
			
		||||
 | 
			
		||||
## Storage subscription
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,13 +82,18 @@ See the guide to [plan your GitLab upgrade](plan_your_upgrade.md).
 | 
			
		|||
## Checking for background migrations before upgrading
 | 
			
		||||
 | 
			
		||||
Certain releases may require different migrations to be
 | 
			
		||||
finished before you update to the newer version. Additionally check
 | 
			
		||||
[batched migrations](#batched-background-migrations) from GitLab 14.0.
 | 
			
		||||
finished before you update to the newer version. 
 | 
			
		||||
 | 
			
		||||
[Batched migrations](#batched-background-migrations) are a migration type available in GitLab 14.0 and later.
 | 
			
		||||
Background migrations and batched migrations not the same, so you should check that both are 
 | 
			
		||||
complete before updating.
 | 
			
		||||
 | 
			
		||||
Decrease the time required to complete these migrations by increasing the number of
 | 
			
		||||
[Sidekiq workers](../administration/operations/extra_sidekiq_processes.md)
 | 
			
		||||
that can process jobs in the `background_migration` queue.
 | 
			
		||||
 | 
			
		||||
### Background migrations
 | 
			
		||||
 | 
			
		||||
**For Omnibus installations:**
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -188,7 +188,7 @@ For the GitLab Community Edition, replace `gitlab-ee` with
 | 
			
		|||
 | 
			
		||||
### GitLab 13.7 and later unavailable on Amazon Linux 2
 | 
			
		||||
 | 
			
		||||
Amazon Linux 2 is not an [officially supported operating system](../../administration/package_information/deprecated_os.md#supported-operating-systems).
 | 
			
		||||
Amazon Linux 2 is not an [officially supported operating system](../../administration/package_information/supported_os.md).
 | 
			
		||||
However, in past the [official package installation script](https://packages.gitlab.com/gitlab/gitlab-ee/install)
 | 
			
		||||
installed the `el/6` package repository if run on Amazon Linux. From GitLab 13.7, we no longer
 | 
			
		||||
provide `el/6` packages so administrators must run the [installation script](https://packages.gitlab.com/gitlab/gitlab-ee/install)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ General notes:
 | 
			
		|||
  to create your plan, share details of your architecture, including:
 | 
			
		||||
  - How is GitLab installed?
 | 
			
		||||
  - What is the operating system of the node?
 | 
			
		||||
    (check [OS versions that are no longer supported](../administration/package_information/deprecated_os.md) to confirm that later updates are available).
 | 
			
		||||
    (check [OS versions that are no longer supported](../administration/package_information/supported_os.md#os-versions-that-are-no-longer-supported) to confirm that later updates are available).
 | 
			
		||||
  - Is it a single-node or a multi-node setup? If multi-node, share any architectural details about each node with us.
 | 
			
		||||
  - Are you using [GitLab Geo](../administration/geo/index.md)? If so, share any architectural details about each secondary node.
 | 
			
		||||
  - What else might be unique or interesting in your setup that might be important for us to understand?
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +112,7 @@ to your instance and then upgrade it for any relevant features you're using.
 | 
			
		|||
  - [Determine what upgrade path](index.md#upgrade-paths) to follow.
 | 
			
		||||
  - Account for any [version-specific update instructions](index.md#version-specific-upgrading-instructions).
 | 
			
		||||
  - Account for any [version-specific changes](package/index.md#version-specific-changes).
 | 
			
		||||
  - Check the [OS compatibility with the target GitLab version](../administration/package_information/deprecated_os.md).
 | 
			
		||||
  - Check the [OS compatibility with the target GitLab version](../administration/package_information/supported_os.md).
 | 
			
		||||
- Due to background migrations, plan to pause any further upgrades after upgrading
 | 
			
		||||
  to a new major version.
 | 
			
		||||
  [All migrations must finish running](index.md#checking-for-background-migrations-before-upgrading)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,15 +29,15 @@ Prerequisites:
 | 
			
		|||
- You need to [authenticate with the API](../../../api/index.md#authentication). If authenticating with a deploy token, it must be configured with the `write_package_registry` scope.
 | 
			
		||||
 | 
			
		||||
```plaintext
 | 
			
		||||
PUT /projects/:id/packages/terraform/modules/:module_name/:module_system/:module_version/file
 | 
			
		||||
PUT /projects/:id/packages/terraform/modules/:module-name/:module-system/:module-version/file
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
| Attribute          | Type            | Required | Description                                                                                                                      |
 | 
			
		||||
| -------------------| --------------- | ---------| -------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| `id`               | integer/string  | yes      | The ID or [URL-encoded path of the project](../../../api/index.md#namespaced-path-encoding).                                    |
 | 
			
		||||
| `module_name`      | string          | yes      | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), or hyphens (`-`) and cannot exceed 64 characters.
 | 
			
		||||
| `module_system`    | string          | yes      | The package system. It can contain only lowercase letters (`a-z`) and numbers (`0-9`), and cannot exceed 64 characters.
 | 
			
		||||
| `module_version`   | string          | yes      | The package version. It must be valid according to the [Semantic Versioning Specification](https://semver.org/).
 | 
			
		||||
| `module-name`      | string          | yes      | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), or hyphens (`-`) and cannot exceed 64 characters.
 | 
			
		||||
| `module-system`    | string          | yes      | The package system. It can contain only lowercase letters (`a-z`) and numbers (`0-9`), and cannot exceed 64 characters.
 | 
			
		||||
| `module-version`   | string          | yes      | The package version. It must be valid according to the [Semantic Versioning Specification](https://semver.org/).
 | 
			
		||||
 | 
			
		||||
Provide the file content in the request body.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +97,7 @@ You can then reference your Terraform Module from a downstream Terraform project
 | 
			
		|||
 | 
			
		||||
```plaintext
 | 
			
		||||
module "<module>" {
 | 
			
		||||
  source = "gitlab.com/<namespace>/<module_name>/<module_system>"
 | 
			
		||||
  source = "gitlab.com/<namespace>/<module-name>/<module-system>"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ a self-managed instance from an old server to a new server.
 | 
			
		|||
 | 
			
		||||
The backups produced don't depend on the operating system running GitLab. You can therefore use
 | 
			
		||||
the restore method to switch between different operating system distributions or versions, as long
 | 
			
		||||
as the same GitLab version [is available for installation](../../../administration/package_information/deprecated_os.md).
 | 
			
		||||
as the same GitLab version [is available for installation](../../../administration/package_information/supported_os.md).
 | 
			
		||||
 | 
			
		||||
To instead merge two self-managed GitLab instances together, use the instructions in
 | 
			
		||||
[Migrate from self-managed GitLab to GitLab.com](#migrate-from-self-managed-gitlab-to-gitlabcom).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20583,6 +20583,9 @@ msgstr ""
 | 
			
		|||
msgid "LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "LearnGitLab|Your team is growing! You've successfully invited new team members to the %{projectName} project."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "LearnGitlab|Creating your onboarding experience..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,9 +55,9 @@
 | 
			
		|||
    "@babel/preset-env": "^7.10.1",
 | 
			
		||||
    "@gitlab/at.js": "1.5.7",
 | 
			
		||||
    "@gitlab/favicon-overlay": "2.0.0",
 | 
			
		||||
    "@gitlab/svgs": "1.220.0",
 | 
			
		||||
    "@gitlab/svgs": "1.221.0",
 | 
			
		||||
    "@gitlab/tributejs": "1.0.0",
 | 
			
		||||
    "@gitlab/ui": "32.36.0",
 | 
			
		||||
    "@gitlab/ui": "32.38.0",
 | 
			
		||||
    "@gitlab/visual-review-tools": "1.6.1",
 | 
			
		||||
    "@rails/actioncable": "6.1.4-1",
 | 
			
		||||
    "@rails/ujs": "6.1.4-1",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -199,7 +199,7 @@ module QA
 | 
			
		|||
          Page::Project::Artifact::Show.perform do |artifacts|
 | 
			
		||||
            artifacts.go_to_directory('node_modules')
 | 
			
		||||
            artifacts.go_to_directory("@#{registry_scope}")
 | 
			
		||||
            expect(artifacts).to have_content( "#{project.name}")
 | 
			
		||||
            expect(artifacts).to have_content("#{project.name}")
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          project.visit!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,7 +91,7 @@ module QA
 | 
			
		|||
          file_path: 'package.json',
 | 
			
		||||
          content: <<~JSON
 | 
			
		||||
            {
 | 
			
		||||
              "name": "@#{registry_scope}/mypackage",
 | 
			
		||||
              "name": "#{package.name}",
 | 
			
		||||
              "version": "1.0.0",
 | 
			
		||||
              "description": "Example package for GitLab npm registry",
 | 
			
		||||
              "publishConfig": {
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +133,7 @@ module QA
 | 
			
		|||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        it "push and pull a npm package via CI using a #{params[:token_name]}", quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/344537', type: :investigating } do
 | 
			
		||||
        it "push and pull a npm package via CI using a #{params[:token_name]}" do
 | 
			
		||||
          Resource::Repository::Commit.fabricate_via_api! do |commit|
 | 
			
		||||
            commit.project = project
 | 
			
		||||
            commit.commit_message = 'Add .gitlab-ci.yml'
 | 
			
		||||
| 
						 | 
				
			
			@ -168,7 +168,7 @@ module QA
 | 
			
		|||
          Page::Project::Artifact::Show.perform do |artifacts|
 | 
			
		||||
            artifacts.go_to_directory('node_modules')
 | 
			
		||||
            artifacts.go_to_directory("@#{registry_scope}")
 | 
			
		||||
            expect(artifacts).to have_content("mypackage")
 | 
			
		||||
            expect(artifacts).to have_content('mypackage')
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          project.visit!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,14 +5,15 @@ require 'spec_helper'
 | 
			
		|||
RSpec.describe Projects::LearnGitlabController do
 | 
			
		||||
  describe 'GET #index' do
 | 
			
		||||
    let_it_be(:user) { create(:user) }
 | 
			
		||||
    let_it_be(:project) { create(:project, namespace: user.namespace) }
 | 
			
		||||
    let_it_be(:project) { create(:project, namespace: create(:group)) }
 | 
			
		||||
 | 
			
		||||
    let(:learn_gitlab_enabled) { true }
 | 
			
		||||
    let(:params) { { namespace_id: project.namespace.to_param, project_id: project } }
 | 
			
		||||
 | 
			
		||||
    subject { get :index, params: params }
 | 
			
		||||
    subject(:action) { get :index, params: params }
 | 
			
		||||
 | 
			
		||||
    before do
 | 
			
		||||
      project.namespace.add_owner(user)
 | 
			
		||||
      allow(controller.helpers).to receive(:learn_gitlab_enabled?).and_return(learn_gitlab_enabled)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +33,10 @@ RSpec.describe Projects::LearnGitlabController do
 | 
			
		|||
 | 
			
		||||
        it { is_expected.to have_gitlab_http_status(:not_found) }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it_behaves_like 'tracks assignment and records the subject', :invite_for_help_continuous_onboarding, :namespace do
 | 
			
		||||
        subject { project.namespace }
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,6 +100,7 @@ describe('experiment Utilities', () => {
 | 
			
		|||
  describe('isExperimentVariant', () => {
 | 
			
		||||
    describe.each`
 | 
			
		||||
      experiment   | variant              | input                            | output
 | 
			
		||||
      ${ABC_KEY}   | ${CANDIDATE_VARIANT} | ${[ABC_KEY]}                     | ${true}
 | 
			
		||||
      ${ABC_KEY}   | ${DEFAULT_VARIANT}   | ${[ABC_KEY, DEFAULT_VARIANT]}    | ${true}
 | 
			
		||||
      ${ABC_KEY}   | ${'_variant_name'}   | ${[ABC_KEY, '_variant_name']}    | ${true}
 | 
			
		||||
      ${ABC_KEY}   | ${'_variant_name'}   | ${[ABC_KEY, '_bogus_name']}      | ${false}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@ import {
 | 
			
		|||
  MEMBERS_MODAL_DEFAULT_TITLE,
 | 
			
		||||
  MEMBERS_PLACEHOLDER,
 | 
			
		||||
  MEMBERS_TO_PROJECT_CELEBRATE_INTRO_TEXT,
 | 
			
		||||
  LEARN_GITLAB,
 | 
			
		||||
} from '~/invite_members/constants';
 | 
			
		||||
import eventHub from '~/invite_members/event_hub';
 | 
			
		||||
import axios from '~/lib/utils/axios_utils';
 | 
			
		||||
| 
						 | 
				
			
			@ -268,6 +269,14 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
 | 
			
		||||
        expect(findTasksToBeDone().exists()).toBe(false);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      describe('when opened from the Learn GitLab page', () => {
 | 
			
		||||
        it('does render the tasks to be done', () => {
 | 
			
		||||
          setupComponent({ source: LEARN_GITLAB }, {}, []);
 | 
			
		||||
 | 
			
		||||
          expect(findTasksToBeDone().exists()).toBe(true);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('rendering the tasks', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -465,7 +474,6 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
 | 
			
		||||
          wrapper.vm.$toast = { show: jest.fn() };
 | 
			
		||||
          jest.spyOn(Api, 'addGroupMembersByUserId').mockResolvedValue({ data: postData });
 | 
			
		||||
          jest.spyOn(wrapper.vm, 'showToastMessageSuccess');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('includes the non-default selected areas of focus', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -492,7 +500,23 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
          });
 | 
			
		||||
 | 
			
		||||
          it('displays the successful toastMessage', () => {
 | 
			
		||||
            expect(wrapper.vm.showToastMessageSuccess).toHaveBeenCalled();
 | 
			
		||||
            expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('Members were successfully added', {
 | 
			
		||||
              onComplete: expect.any(Function),
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('when opened from a Learn GitLab page', () => {
 | 
			
		||||
          it('emits the `showSuccessfulInvitationsAlert` event', async () => {
 | 
			
		||||
            eventHub.$emit('openModal', { inviteeType: 'members', source: LEARN_GITLAB });
 | 
			
		||||
 | 
			
		||||
            jest.spyOn(eventHub, '$emit').mockImplementation();
 | 
			
		||||
 | 
			
		||||
            clickInviteButton();
 | 
			
		||||
 | 
			
		||||
            await waitForPromises();
 | 
			
		||||
 | 
			
		||||
            expect(eventHub.$emit).toHaveBeenCalledWith('showSuccessfulInvitationsAlert');
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -649,7 +673,6 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
 | 
			
		||||
          wrapper.vm.$toast = { show: jest.fn() };
 | 
			
		||||
          jest.spyOn(Api, 'inviteGroupMembersByEmail').mockResolvedValue({ data: postData });
 | 
			
		||||
          jest.spyOn(wrapper.vm, 'showToastMessageSuccess');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('includes the non-default selected areas of focus', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -672,7 +695,9 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
          });
 | 
			
		||||
 | 
			
		||||
          it('displays the successful toastMessage', () => {
 | 
			
		||||
            expect(wrapper.vm.showToastMessageSuccess).toHaveBeenCalled();
 | 
			
		||||
            expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('Members were successfully added', {
 | 
			
		||||
              onComplete: expect.any(Function),
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -711,13 +736,14 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
        it('displays the successful toast message when email has already been invited', async () => {
 | 
			
		||||
          mockInvitationsApi(httpStatus.CREATED, invitationsApiResponse.EMAIL_TAKEN);
 | 
			
		||||
          wrapper.vm.$toast = { show: jest.fn() };
 | 
			
		||||
          jest.spyOn(wrapper.vm, 'showToastMessageSuccess');
 | 
			
		||||
 | 
			
		||||
          clickInviteButton();
 | 
			
		||||
 | 
			
		||||
          await waitForPromises();
 | 
			
		||||
 | 
			
		||||
          expect(wrapper.vm.showToastMessageSuccess).toHaveBeenCalled();
 | 
			
		||||
          expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('Members were successfully added', {
 | 
			
		||||
            onComplete: expect.any(Function),
 | 
			
		||||
          });
 | 
			
		||||
          expect(findMembersSelect().props('validationState')).toBe(null);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -782,7 +808,6 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
          wrapper.vm.$toast = { show: jest.fn() };
 | 
			
		||||
          jest.spyOn(Api, 'inviteGroupMembersByEmail').mockResolvedValue({ data: postData });
 | 
			
		||||
          jest.spyOn(Api, 'addGroupMembersByUserId').mockResolvedValue({ data: postData });
 | 
			
		||||
          jest.spyOn(wrapper.vm, 'showToastMessageSuccess');
 | 
			
		||||
          jest.spyOn(wrapper.vm, 'trackInvite');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -800,7 +825,9 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
          });
 | 
			
		||||
 | 
			
		||||
          it('displays the successful toastMessage', () => {
 | 
			
		||||
            expect(wrapper.vm.showToastMessageSuccess).toHaveBeenCalled();
 | 
			
		||||
            expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('Members were successfully added', {
 | 
			
		||||
              onComplete: expect.any(Function),
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -855,7 +882,6 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
          wrapper.setData({ inviteeType: 'group' });
 | 
			
		||||
          wrapper.vm.$toast = { show: jest.fn() };
 | 
			
		||||
          jest.spyOn(Api, 'groupShareWithGroup').mockResolvedValue({ data: groupPostData });
 | 
			
		||||
          jest.spyOn(wrapper.vm, 'showToastMessageSuccess');
 | 
			
		||||
 | 
			
		||||
          clickInviteButton();
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			@ -865,7 +891,9 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
        });
 | 
			
		||||
 | 
			
		||||
        it('displays the successful toastMessage', () => {
 | 
			
		||||
          expect(wrapper.vm.showToastMessageSuccess).toHaveBeenCalled();
 | 
			
		||||
          expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('Members were successfully added', {
 | 
			
		||||
            onComplete: expect.any(Function),
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -930,6 +958,13 @@ describe('InviteMembersModal', () => {
 | 
			
		|||
        expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith(MEMBER_AREAS_OF_FOCUS.view);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('tracks the view for learn_gitlab source', () => {
 | 
			
		||||
        eventHub.$emit('openModal', { inviteeType: 'members', source: LEARN_GITLAB });
 | 
			
		||||
 | 
			
		||||
        expect(ExperimentTracking).toHaveBeenCalledWith(INVITE_MEMBERS_FOR_TASK.name);
 | 
			
		||||
        expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith(LEARN_GITLAB);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('tracks the invite for areas_of_focus', () => {
 | 
			
		||||
        eventHub.$emit('openModal', { inviteeType: 'members' });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,8 @@
 | 
			
		|||
 | 
			
		||||
exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		||||
<div>
 | 
			
		||||
  <!---->
 | 
			
		||||
   
 | 
			
		||||
  <div
 | 
			
		||||
    class="row"
 | 
			
		||||
  >
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +133,6 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
          <div
 | 
			
		||||
            class="gl-mb-4"
 | 
			
		||||
          >
 | 
			
		||||
            <span>
 | 
			
		||||
            <a
 | 
			
		||||
              class="gl-link"
 | 
			
		||||
              data-track-action="click_link"
 | 
			
		||||
| 
						 | 
				
			
			@ -146,14 +147,12 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
    Set up CI/CD
 | 
			
		||||
  
 | 
			
		||||
            </a>
 | 
			
		||||
            </span>
 | 
			
		||||
             
 | 
			
		||||
            <!---->
 | 
			
		||||
          </div>
 | 
			
		||||
          <div
 | 
			
		||||
            class="gl-mb-4"
 | 
			
		||||
          >
 | 
			
		||||
            <span>
 | 
			
		||||
            <a
 | 
			
		||||
              class="gl-link"
 | 
			
		||||
              data-track-action="click_link"
 | 
			
		||||
| 
						 | 
				
			
			@ -168,14 +167,12 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
    Start a free Ultimate trial
 | 
			
		||||
  
 | 
			
		||||
            </a>
 | 
			
		||||
            </span>
 | 
			
		||||
             
 | 
			
		||||
            <!---->
 | 
			
		||||
          </div>
 | 
			
		||||
          <div
 | 
			
		||||
            class="gl-mb-4"
 | 
			
		||||
          >
 | 
			
		||||
            <span>
 | 
			
		||||
            <a
 | 
			
		||||
              class="gl-link"
 | 
			
		||||
              data-track-action="click_link"
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +187,6 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
    Add code owners
 | 
			
		||||
  
 | 
			
		||||
            </a>
 | 
			
		||||
            </span>
 | 
			
		||||
             
 | 
			
		||||
            <span
 | 
			
		||||
              class="gl-font-style-italic gl-text-gray-500"
 | 
			
		||||
| 
						 | 
				
			
			@ -204,7 +200,6 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
          <div
 | 
			
		||||
            class="gl-mb-4"
 | 
			
		||||
          >
 | 
			
		||||
            <span>
 | 
			
		||||
            <a
 | 
			
		||||
              class="gl-link"
 | 
			
		||||
              data-track-action="click_link"
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +214,6 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
    Add merge request approval
 | 
			
		||||
  
 | 
			
		||||
            </a>
 | 
			
		||||
            </span>
 | 
			
		||||
             
 | 
			
		||||
            <span
 | 
			
		||||
              class="gl-font-style-italic gl-text-gray-500"
 | 
			
		||||
| 
						 | 
				
			
			@ -269,7 +263,6 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
          <div
 | 
			
		||||
            class="gl-mb-4"
 | 
			
		||||
          >
 | 
			
		||||
            <span>
 | 
			
		||||
            <a
 | 
			
		||||
              class="gl-link"
 | 
			
		||||
              data-track-action="click_link"
 | 
			
		||||
| 
						 | 
				
			
			@ -284,14 +277,12 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
    Create an issue
 | 
			
		||||
  
 | 
			
		||||
            </a>
 | 
			
		||||
            </span>
 | 
			
		||||
             
 | 
			
		||||
            <!---->
 | 
			
		||||
          </div>
 | 
			
		||||
          <div
 | 
			
		||||
            class="gl-mb-4"
 | 
			
		||||
          >
 | 
			
		||||
            <span>
 | 
			
		||||
            <a
 | 
			
		||||
              class="gl-link"
 | 
			
		||||
              data-track-action="click_link"
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +297,6 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
    Submit a merge request
 | 
			
		||||
  
 | 
			
		||||
            </a>
 | 
			
		||||
            </span>
 | 
			
		||||
             
 | 
			
		||||
            <!---->
 | 
			
		||||
          </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -349,7 +339,6 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
          <div
 | 
			
		||||
            class="gl-mb-4"
 | 
			
		||||
          >
 | 
			
		||||
            <span>
 | 
			
		||||
            <a
 | 
			
		||||
              class="gl-link"
 | 
			
		||||
              data-track-action="click_link"
 | 
			
		||||
| 
						 | 
				
			
			@ -364,7 +353,6 @@ exports[`Learn GitLab renders correctly 1`] = `
 | 
			
		|||
    Run a Security scan using CI/CD
 | 
			
		||||
  
 | 
			
		||||
            </a>
 | 
			
		||||
            </span>
 | 
			
		||||
             
 | 
			
		||||
            <!---->
 | 
			
		||||
          </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
import { shallowMount } from '@vue/test-utils';
 | 
			
		||||
import { stubExperiments } from 'helpers/experimentation_helper';
 | 
			
		||||
import { mockTracking, triggerEvent, unmockTracking } from 'helpers/tracking_helper';
 | 
			
		||||
import eventHub from '~/invite_members/event_hub';
 | 
			
		||||
import LearnGitlabSectionLink from '~/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue';
 | 
			
		||||
 | 
			
		||||
const defaultAction = 'gitWrite';
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +26,9 @@ describe('Learn GitLab Section Link', () => {
 | 
			
		|||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const openInviteMembesrModalLink = () =>
 | 
			
		||||
    wrapper.find('[data-testid="invite-for-help-continuous-onboarding-experiment-link"]');
 | 
			
		||||
 | 
			
		||||
  it('renders no icon when not completed', () => {
 | 
			
		||||
    createWrapper(undefined, { completed: false });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -46,4 +52,54 @@ describe('Learn GitLab Section Link', () => {
 | 
			
		|||
 | 
			
		||||
    expect(wrapper.find('[data-testid="trial-only"]').exists()).toBe(true);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('rendering a link to open the invite_members modal instead of a regular link', () => {
 | 
			
		||||
    it.each`
 | 
			
		||||
      action           | experimentVariant | showModal
 | 
			
		||||
      ${'userAdded'}   | ${'candidate'}    | ${true}
 | 
			
		||||
      ${'userAdded'}   | ${'control'}      | ${false}
 | 
			
		||||
      ${defaultAction} | ${'candidate'}    | ${false}
 | 
			
		||||
      ${defaultAction} | ${'control'}      | ${false}
 | 
			
		||||
    `(
 | 
			
		||||
      'when the invite_for_help_continuous_onboarding experiment has variant: $experimentVariant and action is $action, the modal link is shown: $showModal',
 | 
			
		||||
      ({ action, experimentVariant, showModal }) => {
 | 
			
		||||
        stubExperiments({ invite_for_help_continuous_onboarding: experimentVariant });
 | 
			
		||||
        createWrapper(action);
 | 
			
		||||
 | 
			
		||||
        expect(openInviteMembesrModalLink().exists()).toBe(showModal);
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('clicking the link to open the invite_members modal', () => {
 | 
			
		||||
    beforeEach(() => {
 | 
			
		||||
      jest.spyOn(eventHub, '$emit').mockImplementation();
 | 
			
		||||
 | 
			
		||||
      stubExperiments({ invite_for_help_continuous_onboarding: 'candidate' });
 | 
			
		||||
      createWrapper('userAdded');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('calls the eventHub', () => {
 | 
			
		||||
      openInviteMembesrModalLink().vm.$emit('click');
 | 
			
		||||
 | 
			
		||||
      expect(eventHub.$emit).toHaveBeenCalledWith('openModal', {
 | 
			
		||||
        inviteeType: 'members',
 | 
			
		||||
        source: 'learn_gitlab',
 | 
			
		||||
        tasksToBeDoneEnabled: true,
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('tracks the click', async () => {
 | 
			
		||||
      const trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
 | 
			
		||||
 | 
			
		||||
      triggerEvent(openInviteMembesrModalLink().element);
 | 
			
		||||
 | 
			
		||||
      expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_link', {
 | 
			
		||||
        label: 'Invite your colleagues',
 | 
			
		||||
        property: 'Growth::Activation::Experiment::InviteForHelpContinuousOnboarding',
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      unmockTracking();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +1,35 @@
 | 
			
		|||
import { GlProgressBar } from '@gitlab/ui';
 | 
			
		||||
import { GlProgressBar, GlAlert } from '@gitlab/ui';
 | 
			
		||||
import { mount } from '@vue/test-utils';
 | 
			
		||||
import LearnGitlab from '~/pages/projects/learn_gitlab/components/learn_gitlab.vue';
 | 
			
		||||
import eventHub from '~/invite_members/event_hub';
 | 
			
		||||
import { testActions, testSections } from './mock_data';
 | 
			
		||||
import { testActions, testSections, testProject } from './mock_data';
 | 
			
		||||
 | 
			
		||||
describe('Learn GitLab', () => {
 | 
			
		||||
  let wrapper;
 | 
			
		||||
  let sidebar;
 | 
			
		||||
  let inviteMembersOpen = false;
 | 
			
		||||
 | 
			
		||||
  const createWrapper = () => {
 | 
			
		||||
    wrapper = mount(LearnGitlab, {
 | 
			
		||||
      propsData: { actions: testActions, sections: testSections, inviteMembersOpen },
 | 
			
		||||
      propsData: {
 | 
			
		||||
        actions: testActions,
 | 
			
		||||
        sections: testSections,
 | 
			
		||||
        project: testProject,
 | 
			
		||||
        inviteMembersOpen,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    sidebar = document.createElement('div');
 | 
			
		||||
    sidebar.innerHTML = `
 | 
			
		||||
    <div class="sidebar-top-level-items">
 | 
			
		||||
      <div class="active">
 | 
			
		||||
        <div class="count"></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    `;
 | 
			
		||||
    document.body.appendChild(sidebar);
 | 
			
		||||
    createWrapper();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +37,7 @@ describe('Learn GitLab', () => {
 | 
			
		|||
    wrapper.destroy();
 | 
			
		||||
    wrapper = null;
 | 
			
		||||
    inviteMembersOpen = false;
 | 
			
		||||
    sidebar.remove();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('renders correctly', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -66,4 +82,26 @@ describe('Learn GitLab', () => {
 | 
			
		|||
      expect(spy).not.toHaveBeenCalled();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('when the showSuccessfulInvitationsAlert event is fired', () => {
 | 
			
		||||
    const findAlert = () => wrapper.findComponent(GlAlert);
 | 
			
		||||
 | 
			
		||||
    beforeEach(() => {
 | 
			
		||||
      eventHub.$emit('showSuccessfulInvitationsAlert');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('displays the successful invitations alert', () => {
 | 
			
		||||
      expect(findAlert().exists()).toBe(true);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('displays a message with the project name', () => {
 | 
			
		||||
      expect(findAlert().text()).toBe(
 | 
			
		||||
        "Your team is growing! You've successfully invited new team members to the test-project project.",
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('modifies the sidebar percentage', () => {
 | 
			
		||||
      expect(sidebar.textContent.trim()).toBe('22%');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,3 +57,7 @@ export const testSections = {
 | 
			
		|||
    svg: 'plan.svg',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const testProject = {
 | 
			
		||||
  name: 'test-project',
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ RSpec.describe InviteMembersHelper do
 | 
			
		|||
  include Devise::Test::ControllerHelpers
 | 
			
		||||
 | 
			
		||||
  let_it_be(:project) { create(:project) }
 | 
			
		||||
  let_it_be(:group) { create(:group, projects: [project]) }
 | 
			
		||||
  let_it_be(:developer) { create(:user, developer_projects: [project]) }
 | 
			
		||||
 | 
			
		||||
  let(:owner) { project.owner }
 | 
			
		||||
| 
						 | 
				
			
			@ -64,48 +65,13 @@ RSpec.describe InviteMembersHelper do
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    context 'tasks_to_be_done' do
 | 
			
		||||
      using RSpec::Parameterized::TableSyntax
 | 
			
		||||
 | 
			
		||||
      subject(:output) { helper.common_invite_modal_dataset(source) }
 | 
			
		||||
 | 
			
		||||
      let_it_be(:source) { project }
 | 
			
		||||
 | 
			
		||||
      before do
 | 
			
		||||
        stub_experiments(invite_members_for_task: true)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      context 'when not logged in' do
 | 
			
		||||
        before do
 | 
			
		||||
          allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' })
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        it "doesn't have the tasks to be done attributes" do
 | 
			
		||||
          expect(output[:tasks_to_be_done_options]).to be_nil
 | 
			
		||||
          expect(output[:projects]).to be_nil
 | 
			
		||||
          expect(output[:new_project_path]).to be_nil
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      context 'when logged in but the open_modal param is not present' do
 | 
			
		||||
        before do
 | 
			
		||||
          allow(helper).to receive(:current_user).and_return(developer)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        it "doesn't have the tasks to be done attributes" do
 | 
			
		||||
          expect(output[:tasks_to_be_done_options]).to be_nil
 | 
			
		||||
          expect(output[:projects]).to be_nil
 | 
			
		||||
          expect(output[:new_project_path]).to be_nil
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      context 'when logged in and the open_modal param is present' do
 | 
			
		||||
        before do
 | 
			
		||||
          allow(helper).to receive(:current_user).and_return(developer)
 | 
			
		||||
          allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' })
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        context 'for a group' do
 | 
			
		||||
          let_it_be(:source) { create(:group, projects: [project]) }
 | 
			
		||||
 | 
			
		||||
          it 'has the expected attributes', :aggregate_failures do
 | 
			
		||||
      shared_examples_for 'including the tasks to be done attributes' do
 | 
			
		||||
        it 'includes the tasks to be done attributes when expected' do
 | 
			
		||||
          if expected?
 | 
			
		||||
            expect(output[:tasks_to_be_done_options]).to eq(
 | 
			
		||||
              [
 | 
			
		||||
                { value: :code, text: 'Create/import code into a project (repository)' },
 | 
			
		||||
| 
						 | 
				
			
			@ -117,24 +83,75 @@ RSpec.describe InviteMembersHelper do
 | 
			
		|||
              [{ id: project.id, title: project.title }].to_json
 | 
			
		||||
            )
 | 
			
		||||
            expect(output[:new_project_path]).to eq(
 | 
			
		||||
              new_project_path(namespace_id: source.id)
 | 
			
		||||
              source.is_a?(Project) ? '' : new_project_path(namespace_id: group.id)
 | 
			
		||||
            )
 | 
			
		||||
          else
 | 
			
		||||
            expect(output[:tasks_to_be_done_options]).to be_nil
 | 
			
		||||
            expect(output[:projects]).to be_nil
 | 
			
		||||
            expect(output[:new_project_path]).to be_nil
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
        context 'for a project' do
 | 
			
		||||
          it 'has the expected attributes', :aggregate_failures do
 | 
			
		||||
            expect(output[:tasks_to_be_done_options]).to eq(
 | 
			
		||||
              [
 | 
			
		||||
                { value: :code, text: 'Create/import code into a project (repository)' },
 | 
			
		||||
                { value: :ci, text: 'Set up CI/CD pipelines to build, test, deploy, and monitor code' },
 | 
			
		||||
                { value: :issues, text: 'Create/import issues (tickets) to collaborate on ideas and plan work' }
 | 
			
		||||
              ].to_json
 | 
			
		||||
            )
 | 
			
		||||
            expect(output[:projects]).to eq(
 | 
			
		||||
              [{ id: project.id, title: project.title }].to_json
 | 
			
		||||
            )
 | 
			
		||||
            expect(output[:new_project_path]).to eq('')
 | 
			
		||||
      context 'the invite_members_for_task experiment' do
 | 
			
		||||
        where(:invite_members_for_task_enabled?, :open_modal_param_present?, :logged_in?, :expected?) do
 | 
			
		||||
          true  | true  | true  | true
 | 
			
		||||
          true  | true  | false | false
 | 
			
		||||
          true  | false | true  | false
 | 
			
		||||
          true  | false | false | false
 | 
			
		||||
          false | true  | true  | false
 | 
			
		||||
          false | true  | false | false
 | 
			
		||||
          false | false | true  | false
 | 
			
		||||
          false | false | false | false
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        with_them do
 | 
			
		||||
          before do
 | 
			
		||||
            allow(helper).to receive(:current_user).and_return(developer) if logged_in?
 | 
			
		||||
            stub_experiments(invite_members_for_task: true) if invite_members_for_task_enabled?
 | 
			
		||||
            allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' }) if open_modal_param_present?
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          context 'when the source is a project' do
 | 
			
		||||
            let_it_be(:source) { project }
 | 
			
		||||
 | 
			
		||||
            it_behaves_like 'including the tasks to be done attributes'
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          context 'when the source is a group' do
 | 
			
		||||
            let_it_be(:source) { group }
 | 
			
		||||
 | 
			
		||||
            it_behaves_like 'including the tasks to be done attributes'
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      context 'the invite_for_help_continuous_onboarding experiment' do
 | 
			
		||||
        where(:invite_for_help_continuous_onboarding?, :logged_in?, :expected?) do
 | 
			
		||||
          true  | true  | true
 | 
			
		||||
          true  | false | false
 | 
			
		||||
          false | true  | false
 | 
			
		||||
          false | false | false
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        with_them do
 | 
			
		||||
          before do
 | 
			
		||||
            allow(helper).to receive(:current_user).and_return(developer) if logged_in?
 | 
			
		||||
            stub_experiments(invite_for_help_continuous_onboarding: :candidate) if invite_for_help_continuous_onboarding?
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          context 'when the source is a project' do
 | 
			
		||||
            let_it_be(:source) { project }
 | 
			
		||||
 | 
			
		||||
            it_behaves_like 'including the tasks to be done attributes'
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          context 'when the source is a group' do
 | 
			
		||||
            let_it_be(:source) { group }
 | 
			
		||||
 | 
			
		||||
            let(:expected?) { false }
 | 
			
		||||
 | 
			
		||||
            it_behaves_like 'including the tasks to be done attributes'
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,6 +60,7 @@ RSpec.describe LearnGitlabHelper do
 | 
			
		|||
 | 
			
		||||
    let(:onboarding_actions_data) { Gitlab::Json.parse(learn_gitlab_data[:actions]).deep_symbolize_keys }
 | 
			
		||||
    let(:onboarding_sections_data) { Gitlab::Json.parse(learn_gitlab_data[:sections]).deep_symbolize_keys }
 | 
			
		||||
    let(:onboarding_project_data) { Gitlab::Json.parse(learn_gitlab_data[:project]).deep_symbolize_keys }
 | 
			
		||||
 | 
			
		||||
    shared_examples 'has all data' do
 | 
			
		||||
      it 'has all actions' do
 | 
			
		||||
| 
						 | 
				
			
			@ -82,6 +83,11 @@ RSpec.describe LearnGitlabHelper do
 | 
			
		|||
        expect(onboarding_sections_data.keys).to contain_exactly(:deploy, :plan, :workspace)
 | 
			
		||||
        expect(onboarding_sections_data.values.map { |section| section.keys }).to match_array([[:svg]] * 3)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'has all project data', :aggregate_failures do
 | 
			
		||||
        expect(onboarding_project_data.keys).to contain_exactly(:name)
 | 
			
		||||
        expect(onboarding_project_data.values).to match_array([project.name])
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'has all data'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
require 'spec_helper'
 | 
			
		||||
 | 
			
		||||
RSpec.describe Gitlab::GrapeLogging::Loggers::ExceptionLogger do
 | 
			
		||||
  let(:mock_request) { OpenStruct.new(env: {}) }
 | 
			
		||||
  let(:mock_request) { double('env', env: {}) }
 | 
			
		||||
  let(:response_body) { nil }
 | 
			
		||||
 | 
			
		||||
  describe ".parameters" do
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ RSpec.describe Gitlab::GrapeLogging::Loggers::ExceptionLogger do
 | 
			
		|||
    describe 'when an exception is available' do
 | 
			
		||||
      let(:exception) { RuntimeError.new('This is a test') }
 | 
			
		||||
      let(:mock_request) do
 | 
			
		||||
        OpenStruct.new(
 | 
			
		||||
        double('env',
 | 
			
		||||
          env: {
 | 
			
		||||
            ::API::Helpers::API_EXCEPTION_ENV => exception
 | 
			
		||||
          }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,9 +20,9 @@ RSpec.describe U2fRegistration do
 | 
			
		|||
    describe '#create_webauthn_registration' do
 | 
			
		||||
      shared_examples_for 'creates webauthn registration' do
 | 
			
		||||
        it 'creates webauthn registration' do
 | 
			
		||||
          u2f_registration.save!
 | 
			
		||||
          created_record = u2f_registration
 | 
			
		||||
 | 
			
		||||
          webauthn_registration = WebauthnRegistration.where(u2f_registration_id: u2f_registration.id)
 | 
			
		||||
          webauthn_registration = WebauthnRegistration.where(u2f_registration_id: created_record.id)
 | 
			
		||||
          expect(webauthn_registration).to exist
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			@ -43,13 +43,16 @@ RSpec.describe U2fRegistration do
 | 
			
		|||
 | 
			
		||||
      it 'logs error' do
 | 
			
		||||
        allow(Gitlab::Auth::U2fWebauthnConverter).to receive(:new).and_raise('boom!')
 | 
			
		||||
        expect(Gitlab::AppJsonLogger).to(
 | 
			
		||||
          receive(:error).with(a_hash_including(event: 'u2f_migration',
 | 
			
		||||
                                                error: 'RuntimeError',
 | 
			
		||||
                                                message: 'U2F to WebAuthn conversion failed'))
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        u2f_registration.save!
 | 
			
		||||
        allow_next_instance_of(U2fRegistration) do |u2f_registration|
 | 
			
		||||
          allow(u2f_registration).to receive(:id).and_return(123)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        expect(Gitlab::ErrorTracking).to(
 | 
			
		||||
          receive(:track_exception).with(kind_of(StandardError),
 | 
			
		||||
                                             u2f_registration_id: 123))
 | 
			
		||||
 | 
			
		||||
        u2f_registration
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3673,6 +3673,7 @@ RSpec.describe User do
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  describe '#ci_owned_runners' do
 | 
			
		||||
    shared_examples 'ci_owned_runners examples' do
 | 
			
		||||
      let(:user) { create(:user) }
 | 
			
		||||
 | 
			
		||||
      shared_examples :nested_groups_owner do
 | 
			
		||||
| 
						 | 
				
			
			@ -3979,6 +3980,17 @@ RSpec.describe User do
 | 
			
		|||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'ci_owned_runners examples'
 | 
			
		||||
 | 
			
		||||
    context 'when feature flag :linear_user_ci_owned_runners is disabled' do
 | 
			
		||||
      before do
 | 
			
		||||
        stub_feature_flags(linear_user_ci_owned_runners: false)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it_behaves_like 'ci_owned_runners examples'
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe '#projects_with_reporter_access_limited_to' do
 | 
			
		||||
    let(:project1) { create(:project) }
 | 
			
		||||
    let(:project2) { create(:project) }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,12 +11,12 @@ RSpec.describe API::ImportGithub do
 | 
			
		|||
    let(:user) { create(:user) }
 | 
			
		||||
    let(:project) { create(:project) }
 | 
			
		||||
    let(:provider_username) { user.username }
 | 
			
		||||
    let(:provider_user) { OpenStruct.new(login: provider_username) }
 | 
			
		||||
    let(:provider_user) { double('provider', login: provider_username) }
 | 
			
		||||
    let(:provider_repo) do
 | 
			
		||||
      OpenStruct.new(
 | 
			
		||||
      double('provider',
 | 
			
		||||
        name: 'vim',
 | 
			
		||||
        full_name: "#{provider_username}/vim",
 | 
			
		||||
        owner: OpenStruct.new(login: provider_username)
 | 
			
		||||
        owner: double('provider', login: provider_username)
 | 
			
		||||
      )
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,16 @@ RSpec.describe Groups::CreateService, '#execute' do
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'when `setup_for_company:true` is passed' do
 | 
			
		||||
    let(:params) { group_params.merge(setup_for_company: true) }
 | 
			
		||||
    let(:service) { described_class.new(user, params) }
 | 
			
		||||
    let(:created_group) { service.execute }
 | 
			
		||||
 | 
			
		||||
    it 'creates group with the specified setup_for_company' do
 | 
			
		||||
      expect(created_group.setup_for_company).to eq(true)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'creating a group with `default_branch_protection` attribute' do
 | 
			
		||||
    let(:params) { group_params.merge(default_branch_protection: Gitlab::Access::PROTECTION_NONE) }
 | 
			
		||||
    let(:service) { described_class.new(user, params) }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								yarn.lock
								
								
								
								
							
							
						
						
									
										16
									
								
								yarn.lock
								
								
								
								
							| 
						 | 
				
			
			@ -914,20 +914,20 @@
 | 
			
		|||
    stylelint-declaration-strict-value "1.7.7"
 | 
			
		||||
    stylelint-scss "3.18.0"
 | 
			
		||||
 | 
			
		||||
"@gitlab/svgs@1.220.0":
 | 
			
		||||
  version "1.220.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.220.0.tgz#188bdefe86cdbf8be1faa7a92dbac31c728066c7"
 | 
			
		||||
  integrity sha512-9QRXQG6IrQoviU86g2Y4l19yE81UyEg/iMoGetMfUdQ64NW6unLN7uNbUaO1ws1J0p7uG0dKwR6ohD7tEUPLFA==
 | 
			
		||||
"@gitlab/svgs@1.221.0":
 | 
			
		||||
  version "1.221.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.221.0.tgz#1804d181b09672d13005d49818eb2da040d67488"
 | 
			
		||||
  integrity sha512-Xn29eer39uVqeuefL/3hVuxo2tazHoEFIXC0F7DnESmBggrcjueNM2tuBUk40oaX6kCzM2Bn4Qn9ESIR+V0PgQ==
 | 
			
		||||
 | 
			
		||||
"@gitlab/tributejs@1.0.0":
 | 
			
		||||
  version "1.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@gitlab/tributejs/-/tributejs-1.0.0.tgz#672befa222aeffc83e7d799b0500a7a4418e59b8"
 | 
			
		||||
  integrity sha512-nmKw1+hB6MHvlmPz63yPwVs1qQkycHwsKgxpEbzmky16Y6mL4EJMk3w1b8QlOAF/AIAzjCERPhe/R4MJiohbZw==
 | 
			
		||||
 | 
			
		||||
"@gitlab/ui@32.36.0":
 | 
			
		||||
  version "32.36.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.36.0.tgz#f3fb6f86dc51a6941bd230c047f0014364732efd"
 | 
			
		||||
  integrity sha512-cX/+P011FD6TrD9/tKuG5xX/tSx9oRwb/bRA45RG1zbkmRh/ohr5zQMuNK2utrHFl4OqrcPirqXMyFl+kKnCdg==
 | 
			
		||||
"@gitlab/ui@32.38.0":
 | 
			
		||||
  version "32.38.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-32.38.0.tgz#580bda8daacdf23c1f6a75d77f6df44b1dbe1726"
 | 
			
		||||
  integrity sha512-BS0+4JicfuiCbaWTTok0dQUzUCI8m8t5T7//DQUQqqwCZLYeJlb1AxMatd6IjwcdE0m+AhST3iOZi2x+hDrkbQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/standalone" "^7.0.0"
 | 
			
		||||
    bootstrap-vue "2.20.1"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue