Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-12-16 00:09:40 +00:00
parent d22c6f7410
commit bfa34fc19c
35 changed files with 1216 additions and 228 deletions

View File

@ -22,4 +22,4 @@ Please read the below documentations for a workflow of triaging and resolving br
Please refer to the [Resolution guidance](https://about.gitlab.com/handbook/engineering/workflow/#resolution-of-broken-master) to learn more about resolution of broken master.
/label ~"failure::flaky-test" ~"Engineering Productivity" ~"priority::2" ~"severity::2"
/label ~"failure::flaky-test" ~"Engineering Productivity" ~"priority::2" ~"severity::3" ~"type::bug" ~"bug::transient"

View File

@ -21,4 +21,4 @@ Please read the below documentations for a workflow of triaging and resolving br
Please refer to the [Resolution guidance](https://about.gitlab.com/handbook/engineering/workflow/#resolution-of-broken-master) to learn more about resolution of broken master.
/label ~"master:broken" ~"Engineering Productivity" ~"priority::1" ~"severity::1"
/label ~"master:broken" ~"Engineering Productivity" ~"priority::1" ~"severity::1" ~"type::bug" ~"bug::transient"

View File

@ -1,18 +1,321 @@
<script>
import { GlForm } from '@gitlab/ui';
import {
GlButton,
GlDropdown,
GlDropdownItem,
GlFormCheckbox,
GlForm,
GlFormGroup,
GlFormInput,
GlFormTextarea,
GlLink,
GlSprintf,
} from '@gitlab/ui';
import { uniqueId } from 'lodash';
import Vue from 'vue';
import { __, s__ } from '~/locale';
import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants';
import RefSelector from '~/ref/components/ref_selector.vue';
import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown/timezone_dropdown.vue';
import IntervalPatternInput from '~/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue';
import { VARIABLE_TYPE, FILE_TYPE } from '../constants';
export default {
components: {
GlButton,
GlDropdown,
GlDropdownItem,
GlForm,
GlFormCheckbox,
GlFormGroup,
GlFormInput,
GlFormTextarea,
GlLink,
GlSprintf,
RefSelector,
TimezoneDropdown,
IntervalPatternInput,
},
inject: {
fullPath: {
inject: [
'fullPath',
'projectId',
'defaultBranch',
'cron',
'cronTimezone',
'dailyLimit',
'settingsLink',
],
props: {
timezoneData: {
type: Array,
required: true,
},
refParam: {
type: String,
required: false,
default: '',
},
},
data() {
return {
refValue: {
shortName: this.refParam,
// this is needed until we add support for ref type in url query strings
// ensure default branch is called with full ref on load
// https://gitlab.com/gitlab-org/gitlab/-/issues/287815
fullName: this.refParam === this.defaultBranch ? `refs/heads/${this.refParam}` : undefined,
},
description: '',
scheduleRef: this.defaultBranch,
activated: true,
timezone: this.cronTimezone,
formCiVariables: {},
// TODO: Add the GraphQL query to help populate the predefined variables
// app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue#131
predefinedValueOptions: {},
};
},
i18n: {
activated: __('Activated'),
cronTimezone: s__('PipelineSchedules|Cron timezone'),
description: s__('PipelineSchedules|Description'),
shortDescriptionPipeline: s__(
'PipelineSchedules|Provide a short description for this pipeline',
),
savePipelineSchedule: s__('PipelineSchedules|Save pipeline schedule'),
cancel: __('Cancel'),
targetBranchTag: __('Select target branch or tag'),
intervalPattern: s__('PipelineSchedules|Interval Pattern'),
variablesDescription: s__(
'Pipeline|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used by default.',
),
removeVariableLabel: s__('CiVariables|Remove variable'),
variables: s__('Pipeline|Variables'),
},
typeOptions: {
[VARIABLE_TYPE]: __('Variable'),
[FILE_TYPE]: __('File'),
},
formElementClasses: 'gl-md-mr-3 gl-mb-3 gl-flex-basis-quarter gl-flex-shrink-0 gl-flex-grow-0',
computed: {
dropdownTranslations() {
return {
dropdownHeader: this.$options.i18n.targetBranchTag,
};
},
refFullName() {
return this.refValue.fullName;
},
variables() {
return this.formCiVariables[this.refFullName]?.variables ?? [];
},
descriptions() {
return this.formCiVariables[this.refFullName]?.descriptions ?? {};
},
typeOptionsListbox() {
return [
{
text: __('Variable'),
value: VARIABLE_TYPE,
},
{
text: __('File'),
value: FILE_TYPE,
},
];
},
getEnabledRefTypes() {
return [REF_TYPE_BRANCHES, REF_TYPE_TAGS];
},
},
created() {
Vue.set(this.formCiVariables, this.refFullName, {
variables: [],
descriptions: {},
});
this.addEmptyVariable(this.refFullName);
},
methods: {
addEmptyVariable(refValue) {
const { variables } = this.formCiVariables[refValue];
const lastVar = variables[variables.length - 1];
if (lastVar?.key === '' && lastVar?.value === '') {
return;
}
variables.push({
uniqueId: uniqueId(`var-${refValue}`),
variable_type: VARIABLE_TYPE,
key: '',
value: '',
});
},
setVariableAttribute(key, attribute, value) {
const { variables } = this.formCiVariables[this.refFullName];
const variable = variables.find((v) => v.key === key);
variable[attribute] = value;
},
shouldShowValuesDropdown(key) {
return this.predefinedValueOptions[key]?.length > 1;
},
removeVariable(index) {
this.variables.splice(index, 1);
},
canRemove(index) {
return index < this.variables.length - 1;
},
},
};
</script>
<template>
<gl-form />
<div class="col-lg-8">
<gl-form>
<!--Description-->
<gl-form-group :label="$options.i18n.description" label-for="schedule-description">
<gl-form-input
id="schedule-description"
v-model="description"
type="text"
:placeholder="$options.i18n.shortDescriptionPipeline"
data-testid="schedule-description"
/>
</gl-form-group>
<!--Interval Pattern-->
<gl-form-group :label="$options.i18n.intervalPattern" label-for="schedule-interval">
<interval-pattern-input
id="schedule-interval"
:initial-cron-interval="cron"
:daily-limit="dailyLimit"
:send-native-errors="false"
/>
</gl-form-group>
<!--Timezone-->
<gl-form-group :label="$options.i18n.cronTimezone" label-for="schedule-timezone">
<timezone-dropdown
id="schedule-timezone"
:value="timezone"
:timezone-data="timezoneData"
name="schedule-timezone"
/>
</gl-form-group>
<!--Branch/Tag Selector-->
<gl-form-group :label="$options.i18n.targetBranchTag" label-for="schedule-target-branch-tag">
<ref-selector
id="schedule-target-branch-tag"
:enabled-ref-types="getEnabledRefTypes"
:project-id="projectId"
:value="scheduleRef"
:use-symbolic-ref-names="true"
:translations="dropdownTranslations"
class="gl-w-full"
/>
</gl-form-group>
<!--Variable List-->
<gl-form-group :label="$options.i18n.variables">
<div
v-for="(variable, index) in variables"
:key="variable.uniqueId"
class="gl-mb-3 gl-pb-2"
data-testid="ci-variable-row"
data-qa-selector="ci_variable_row_container"
>
<div
class="gl-display-flex gl-align-items-stretch gl-flex-direction-column gl-md-flex-direction-row"
>
<gl-dropdown
:text="$options.typeOptions[variable.variable_type]"
:class="$options.formElementClasses"
data-testid="pipeline-form-ci-variable-type"
>
<gl-dropdown-item
v-for="type in Object.keys($options.typeOptions)"
:key="type"
@click="setVariableAttribute(variable.key, 'variable_type', type)"
>
{{ $options.typeOptions[type] }}
</gl-dropdown-item>
</gl-dropdown>
<gl-form-input
v-model="variable.key"
:placeholder="s__('CiVariables|Input variable key')"
:class="$options.formElementClasses"
data-testid="pipeline-form-ci-variable-key"
data-qa-selector="ci_variable_key_field"
@change="addEmptyVariable(refFullName)"
/>
<gl-dropdown
v-if="shouldShowValuesDropdown(variable.key)"
:text="variable.value"
:class="$options.formElementClasses"
class="gl-flex-grow-1 gl-mr-0!"
data-testid="pipeline-form-ci-variable-value-dropdown"
>
<gl-dropdown-item
v-for="value in predefinedValueOptions[variable.key]"
:key="value"
data-testid="pipeline-form-ci-variable-value-dropdown-items"
@click="setVariableAttribute(variable.key, 'value', value)"
>
{{ value }}
</gl-dropdown-item>
</gl-dropdown>
<gl-form-textarea
v-else
v-model="variable.value"
:placeholder="s__('CiVariables|Input variable value')"
class="gl-mb-3 gl-h-7!"
:style="$options.textAreaStyle"
:no-resize="false"
data-testid="pipeline-form-ci-variable-value"
data-qa-selector="ci_variable_value_field"
/>
<template v-if="variables.length > 1">
<gl-button
v-if="canRemove(index)"
class="gl-md-ml-3 gl-mb-3"
data-testid="remove-ci-variable-row"
variant="danger"
category="secondary"
icon="clear"
:aria-label="$options.i18n.removeVariableLabel"
@click="removeVariable(index)"
/>
<gl-button
v-else
class="gl-md-ml-3 gl-mb-3 gl-display-none gl-md-display-block gl-visibility-hidden"
icon="clear"
:aria-label="$options.i18n.removeVariableLabel"
/>
</template>
</div>
<div v-if="descriptions[variable.key]" class="gl-text-gray-500 gl-mb-3">
{{ descriptions[variable.key] }}
</div>
</div>
<template #description
><gl-sprintf :message="$options.i18n.variablesDescription">
<template #link="{ content }">
<gl-link :href="settingsLink">{{ content }}</gl-link>
</template>
</gl-sprintf></template
>
</gl-form-group>
<!--Activated-->
<gl-form-checkbox id="schedule-active" v-model="activated" class="gl-mb-3">{{
$options.i18n.activated
}}</gl-form-checkbox>
<gl-button type="submit" variant="confirm" data-testid="schedule-submit-button">{{
$options.i18n.savePipelineSchedule
}}</gl-button>
<gl-button type="reset" data-testid="schedule-cancel-button">{{
$options.i18n.cancel
}}</gl-button>
</gl-form>
</div>
</template>

View File

@ -0,0 +1,2 @@
export const VARIABLE_TYPE = 'env_var';
export const FILE_TYPE = 'file';

View File

@ -16,7 +16,16 @@ export default (selector) => {
return false;
}
const { fullPath } = containerEl.dataset;
const {
fullPath,
cron,
dailyLimit,
timezoneData,
cronTimezone,
projectId,
defaultBranch,
settingsLink,
} = containerEl.dataset;
return new Vue({
el: containerEl,
@ -24,9 +33,20 @@ export default (selector) => {
apolloProvider,
provide: {
fullPath,
projectId,
defaultBranch,
dailyLimit: dailyLimit ?? '',
cronTimezone: cronTimezone ?? '',
cron: cron ?? '',
settingsLink,
},
render(createElement) {
return createElement(PipelineSchedulesForm);
return createElement(PipelineSchedulesForm, {
props: {
timezoneData: JSON.parse(timezoneData),
refParam: defaultBranch,
},
});
},
});
};

View File

@ -3,6 +3,7 @@ import { __ } from '~/locale';
import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_action';
import { createAndSubmitForm } from '~/lib/utils/create_and_submit_form';
import csrf from '~/lib/utils/csrf';
import { getBaseConfig } from './lib/gitlab_web_ide/get_base_config';
import { setupRootElement } from './lib/gitlab_web_ide/setup_root_element';
import { GITLAB_WEB_IDE_FEEDBACK_ISSUE } from './constants';
@ -27,9 +28,15 @@ export const initGitlabWebIDE = async (el) => {
const rootEl = setupRootElement(el);
// See ClientOnlyConfig https://gitlab.com/gitlab-org/gitlab-web-ide/-/blob/main/packages/web-ide-types/src/config.ts#L17
start(rootEl, {
...getBaseConfig(),
nonce,
// Use same headers as defined in axios_utils
httpHeaders: {
[csrf.headerKey]: csrf.token,
'X-Requested-With': 'XMLHttpRequest',
},
projectPath,
ref,
links: {

View File

@ -39,6 +39,11 @@ export default {
required: false,
default: '',
},
sendNativeErrors: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
@ -114,9 +119,11 @@ export default {
cronInterval() {
// updates field validation state when model changes, as
// glFieldError only updates on input.
this.$nextTick(() => {
gl.pipelineScheduleFieldErrors.updateFormValidityState();
});
if (this.sendNativeErrors) {
this.$nextTick(() => {
gl.pipelineScheduleFieldErrors.updateFormValidityState();
});
}
},
radioValue: {
immediate: true,

View File

@ -1,8 +1,8 @@
import $ from 'jquery';
import GLForm from '~/gl_form';
import RefSelectDropdown from '~/ref_select_dropdown';
import ZenMode from '~/zen_mode';
import initNewTagRefSelector from '~/tags/init_new_tag_ref_selector';
initNewTagRefSelector();
new ZenMode(); // eslint-disable-line no-new
new GLForm($('.tag-form')); // eslint-disable-line no-new
new RefSelectDropdown($('.js-branch-select')); // eslint-disable-line no-new

View File

@ -0,0 +1,23 @@
import Vue from 'vue';
import RefSelector from '~/ref/components/ref_selector.vue';
export default function initNewTagRefSelector() {
const el = document.querySelector('.js-new-tag-ref-selector');
if (el) {
const { projectId, defaultBranchName, hiddenInputName } = el.dataset;
// eslint-disable-next-line no-new
new Vue({
el,
render(createComponent) {
return createComponent(RefSelector, {
props: {
value: defaultBranchName,
name: hiddenInputName,
projectId,
},
});
},
});
}
}

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Resolvers
module Projects
class ForkDetailsResolver < BaseResolver
type Types::Projects::ForkDetailsType, null: true
argument :ref, GraphQL::Types::String,
required: false,
description: 'Ref of the fork. Default value is HEAD.'
alias_method :project, :object
def resolve(**args)
return unless project.forked?
::Projects::Forks::DivergenceCounts.new(project, args[:ref]).counts
end
end
end
end

View File

@ -539,6 +539,13 @@ module Types
resolver: Resolvers::Projects::ForkTargetsResolver,
description: 'Namespaces in which the current user can fork the project into.'
field :fork_details, Types::Projects::ForkDetailsType,
calls_gitaly: true,
alpha: { milestone: '15.7' },
authorize: :read_code,
resolver: Resolvers::Projects::ForkDetailsResolver,
description: 'Details of the fork project compared to its upstream project.'
field :branch_rules,
Types::Projects::BranchRuleType.connection_type,
null: true,

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
module Types
module Projects
# rubocop: disable Graphql/AuthorizeTypes
class ForkDetailsType < BaseObject
graphql_name 'ForkDetails'
description 'Details of the fork project compared to its upstream project.'
field :ahead, GraphQL::Types::Int,
null: true,
description: 'Number of commits ahead of upstream.'
field :behind, GraphQL::Types::Int,
null: true,
description: 'Number of commits behind upstream.'
end
# rubocop: enable Graphql/AuthorizeTypes
end
end

View File

@ -9,6 +9,6 @@
= _("Schedule a new pipeline")
- if Feature.enabled?(:pipeline_schedules_vue, @project)
#pipeline-schedules-form-new{ data: { full_path: @project.full_path } }
#pipeline-schedules-form-new{ data: { full_path: @project.full_path, cron: @schedule.cron, daily_limit: @schedule.daily_limit, timezone_data: timezone_data.to_json, cron_timezone: @schedule.cron_timezone, project_id: @project.id, default_branch: @project.default_branch, settings_link: project_settings_ci_cd_path(@project), } }
- else
= render "form"

View File

@ -20,14 +20,9 @@
= label_tag :tag_name, nil
= text_field_tag :tag_name, params[:tag_name], required: true, autofocus: true, class: 'form-control', data: { qa_selector: "tag_name_field" }
.form-group.row
.col-sm-12.create-from
.col-sm-auto.create-from
= label_tag :ref, 'Create from'
.dropdown
= hidden_field_tag :ref, default_ref
= button_tag type: 'button', title: default_ref, class: 'dropdown-menu-toggle wide js-branch-select monospace', required: true, data: { toggle: 'dropdown', selected: default_ref, field_name: 'ref' } do
.text-left.dropdown-toggle-text= default_ref
= sprite_icon('chevron-down', css_class: 'dropdown-menu-toggle-icon gl-top-3')
= render 'shared/ref_dropdown', dropdown_class: 'wide'
.js-new-tag-ref-selector{ data: { project_id: @project.id, default_branch_name: default_ref, hidden_input_name: 'ref' } }
.form-text.text-muted
= s_('TagsPage|Existing branch name, tag, or commit SHA')
.form-group.row
@ -42,5 +37,4 @@
= s_('TagsPage|Create tag')
= render Pajamas::ButtonComponent.new(href: project_tags_path(@project)) do
= s_('TagsPage|Cancel')
-# haml-lint:disable InlineJavaScript
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe

View File

@ -0,0 +1,25 @@
- title: "Support for periods (`.`) in Terraform state names might break existing states"
announcement_milestone: "15.7"
announcement_date: "2022-12-22"
removal_milestone: "16.0"
removal_date: "2023-05-22"
breaking_change: true
reporter: nagyv-gitlab
stage: configure
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/385564
body: |
Previously, Terraform state names containing periods were not supported. However, you could still use state names with periods via a workaround.
GitLab 15.7 [adds full support](https://docs.gitlab.com/ee/user/infrastructure/iac/troubleshooting.html#state-not-found-if-the-state-name-contains-a-period) for state names that contain periods. If you used a workaround to handle these state names, your jobs might fail, or it might look like you've run Terraform for the first time.
To resolve the issue:
1. Change any references to the state file by excluding the period and any characters that follow.
- For example, if your state name is `state.name`, change all references to `state`.
1. Run your Terraform commands.
To use the full state name, including the period, [migrate to the full state file](https://docs.gitlab.com/ee/user/infrastructure/iac/terraform_state.html#migrate-to-a-gitlab-managed-terraform-state).
end_of_support_milestone: 16.0
end_of_support_date: 2023-05-22
tiers: [Free, Silver, Gold, Core, Premium, Ultimate]
documentation_url: 'https://docs.gitlab.com/ee/user/infrastructure/iac/troubleshooting.html#troubleshooting-terraform-state'

View File

@ -31239,6 +31239,8 @@ CREATE INDEX index_user_statuses_on_user_id ON user_statuses USING btree (user_i
CREATE UNIQUE INDEX index_user_synced_attributes_metadata_on_user_id ON user_synced_attributes_metadata USING btree (user_id);
CREATE INDEX index_users_for_active_billable ON users USING btree (id) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = ANY (ARRAY[NULL::integer, 6, 4]))) AND ((user_type IS NULL) OR (user_type <> ALL ('{1,2,3,4,5,6,7,8,9,11}'::smallint[]))));
CREATE INDEX index_users_on_accepted_term_id ON users USING btree (accepted_term_id);
CREATE INDEX index_users_on_admin ON users USING btree (admin);
@ -31471,8 +31473,6 @@ CREATE INDEX index_web_hooks_on_integration_id ON web_hooks USING btree (integra
CREATE INDEX index_web_hooks_on_project_id ON web_hooks USING btree (project_id);
CREATE INDEX index_users_for_active_billable ON users USING btree (id) WHERE (((state)::text = 'active'::text) AND ((user_type IS NULL) OR (user_type = ANY (ARRAY[NULL::integer, 6, 4]))) AND ((user_type IS NULL) OR (user_type <> ALL ('{1,2,3,4,5,6,7,8,9,11}'::smallint[]))));
CREATE INDEX index_web_hooks_on_project_id_recent_failures ON web_hooks USING btree (project_id, recent_failures);
CREATE INDEX index_web_hooks_on_type ON web_hooks USING btree (type);

View File

@ -55,7 +55,9 @@ use a [crontab generator](http://www.crontabgenerator.com).
The example below shows how to set LDAP user
sync to run once every 12 hours at the top of the hour.
**Omnibus installations**
::Tabs
:::TabTitle Linux package (Omnibus)
1. Edit `/etc/gitlab/gitlab.rb`:
@ -63,19 +65,77 @@ sync to run once every 12 hours at the top of the hour.
gitlab_rails['ldap_sync_worker_cron'] = "0 */12 * * *"
```
1. [Reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Save the file and reconfigure GitLab:
**Source installations**
1. Edit `config/gitlab.yaml`:
```yaml
cron_jobs:
ldap_sync_worker_cron:
"0 */12 * * *"
```shell
sudo gitlab-ctl reconfigure
```
1. [Restart GitLab](../../restart_gitlab.md#installations-from-source) for the changes to take effect.
:::TabTitle Helm chart (Kubernetes)
1. Export the Helm values:
```shell
helm get values gitlab > gitlab_values.yaml
```
1. Edit `gitlab_values.yaml`:
```yaml
global:
appConfig:
cron_jobs:
ldap_sync_worker:
cron: "0 */12 * * *"
```
1. Save the file and apply the new values:
```shell
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
```
:::TabTitle Docker
1. Edit `docker-compose.yml`:
```yaml
version: "3.6"
services:
gitlab:
environment:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['ldap_sync_worker_cron'] = "0 */12 * * *"
```
1. Save the file and restart GitLab:
```shell
docker compose up -d
```
:::TabTitle Self-compiled (source)
1. Edit `/home/git/gitlab/config/gitlab.yml`:
```yaml
production: &base
ee_cron_jobs:
ldap_sync_worker:
cron: "0 */12 * * *"
```
1. Save the file and restart GitLab:
```shell
# For systems running systemd
sudo systemctl restart gitlab.target
# For systems running SysV init
sudo service gitlab restart
```
::EndTabs
## Group sync
@ -91,41 +151,103 @@ GitLab group membership to be automatically updated based on LDAP group members.
The `group_base` configuration should be a base LDAP 'container', such as an
'organization' or 'organizational unit', that contains LDAP groups that should
be available to GitLab. For example, `group_base` could be
`ou=groups,dc=example,dc=com`. In the configuration file it looks like the
`ou=groups,dc=example,dc=com`. In the configuration file, it looks like the
following.
**Omnibus configuration**
::Tabs
:::TabTitle Linux package (Omnibus)
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_rails['ldap_servers'] = {
'main' => {
# snip...
'group_base' => 'ou=groups,dc=example,dc=com',
}
'main' => {
'group_base' => 'ou=groups,dc=example,dc=com',
}
}
```
1. [Apply your changes to GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Save the file and reconfigure GitLab:
**Source configuration**
```shell
sudo gitlab-ctl reconfigure
```
:::TabTitle Helm chart (Kubernetes)
1. Export the Helm values:
```shell
helm get values gitlab > gitlab_values.yaml
```
1. Edit `gitlab_values.yaml`:
```yaml
global:
appConfig:
ldap:
servers:
main:
group_base: ou=groups,dc=example,dc=com
```
1. Save the file and apply the new values:
```shell
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
```
:::TabTitle Docker
1. Edit `docker-compose.yml`:
```yaml
version: "3.6"
services:
gitlab:
environment:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['ldap_servers'] = {
'main' => {
'group_base' => 'ou=groups,dc=example,dc=com',
}
}
```
1. Save the file and restart GitLab:
```shell
docker compose up -d
```
:::TabTitle Self-compiled (source)
1. Edit `/home/git/gitlab/config/gitlab.yml`:
```yaml
production:
production: &base
ldap:
servers:
main:
# snip...
group_base: ou=groups,dc=example,dc=com
```
1. [Restart GitLab](../../restart_gitlab.md#installations-from-source) for the changes to take effect.
1. Save the file and restart GitLab:
```shell
# For systems running systemd
sudo systemctl restart gitlab.target
# For systems running SysV init
sudo service gitlab restart
```
::EndTabs
To take advantage of group sync, group Owners or users with the [Maintainer role](../../../user/permissions.md) must
[create one or more LDAP group links](#add-group-links).
[create one or more LDAP group links](../../../user/group/access_and_permissions.md#manage-group-memberships-via-ldap).
### Add group links
@ -146,37 +268,101 @@ as opposed to the full DN.
Additionally, if an LDAP user has an `admin` role, but is not a member of the `admin_group`
group, GitLab revokes their `admin` role when syncing.
**Omnibus configuration**
::Tabs
:::TabTitle Linux package (Omnibus)
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_rails['ldap_servers'] = {
'main' => {
# snip...
'group_base' => 'ou=groups,dc=example,dc=com',
'admin_group' => 'my_admin_group',
}
'main' => {
'group_base' => 'ou=groups,dc=example,dc=com',
'admin_group' => 'my_admin_group',
}
}
```
1. [Apply your changes to GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Save the file and reconfigure GitLab:
**Source configuration**
```shell
sudo gitlab-ctl reconfigure
```
:::TabTitle Helm chart (Kubernetes)
1. Export the Helm values:
```shell
helm get values gitlab > gitlab_values.yaml
```
1. Edit `gitlab_values.yaml`:
```yaml
global:
appConfig:
ldap:
servers:
main:
group_base: ou=groups,dc=example,dc=com
admin_group: my_admin_group
```
1. Save the file and apply the new values:
```shell
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
```
:::TabTitle Docker
1. Edit `docker-compose.yml`:
```yaml
version: "3.6"
services:
gitlab:
environment:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['ldap_servers'] = {
'main' => {
'group_base' => 'ou=groups,dc=example,dc=com',
'admin_group' => 'my_admin_group',
}
}
```
1. Save the file and restart GitLab:
```shell
docker compose up -d
```
:::TabTitle Self-compiled (source)
1. Edit `/home/git/gitlab/config/gitlab.yml`:
```yaml
production:
production: &base
ldap:
servers:
main:
# snip...
group_base: ou=groups,dc=example,dc=com
admin_group: my_admin_group
```
1. [Restart GitLab](../../restart_gitlab.md#installations-from-source) for the changes to take effect.
1. Save the file and restart GitLab:
```shell
# For systems running systemd
sudo systemctl restart gitlab.target
# For systems running SysV init
sudo service gitlab restart
```
::EndTabs
### Global group memberships lock
@ -218,7 +404,9 @@ You can manually configure LDAP group sync times by setting the
following configuration values. The example below shows how to set group
sync to run once every two hours at the top of the hour.
**Omnibus installations**
::Tabs
:::TabTitle Linux package (Omnibus)
1. Edit `/etc/gitlab/gitlab.rb`:
@ -226,19 +414,77 @@ sync to run once every two hours at the top of the hour.
gitlab_rails['ldap_group_sync_worker_cron'] = "0 */2 * * * *"
```
1. [Reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Save the file and reconfigure GitLab:
**Source installations**
1. Edit `config/gitlab.yaml`:
```yaml
cron_jobs:
ldap_group_sync_worker_cron:
"*/30 * * * *"
```shell
sudo gitlab-ctl reconfigure
```
1. [Restart GitLab](../../restart_gitlab.md#installations-from-source) for the changes to take effect.
:::TabTitle Helm chart (Kubernetes)
1. Export the Helm values:
```shell
helm get values gitlab > gitlab_values.yaml
```
1. Edit `gitlab_values.yaml`:
```yaml
global:
appConfig:
cron_jobs:
ldap_group_sync_worker:
cron: "*/30 * * * *"
```
1. Save the file and apply the new values:
```shell
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
```
:::TabTitle Docker
1. Edit `docker-compose.yml`:
```yaml
version: "3.6"
services:
gitlab:
environment:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['ldap_group_sync_worker_cron'] = "0 */2 * * * *"
```
1. Save the file and restart GitLab:
```shell
docker compose up -d
```
:::TabTitle Self-compiled (source)
1. Edit `/home/git/gitlab/config/gitlab.yml`:
```yaml
production: &base
ee_cron_jobs:
ldap_group_sync_worker:
cron: "*/30 * * * *"
```
1. Save the file and restart GitLab:
```shell
# For systems running systemd
sudo systemctl restart gitlab.target
# For systems running SysV init
sudo service gitlab restart
```
::EndTabs
### External groups
@ -247,35 +493,97 @@ to these groups as [external users](../../../user/admin_area/external_users.md).
Group membership is checked periodically through the `LdapGroupSync` background
task.
**Omnibus configuration**
::Tabs
:::TabTitle Linux package (Omnibus)
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_rails['ldap_servers'] = {
'main' => {
# snip...
'external_groups' => ['interns', 'contractors'],
}
'main' => {
'external_groups' => ['interns', 'contractors'],
}
}
```
1. [Apply your changes to GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Save the file and reconfigure GitLab:
**Source configuration**
```shell
sudo gitlab-ctl reconfigure
```
1. Edit `config/gitlab.yaml`:
:::TabTitle Helm chart (Kubernetes)
1. Export the Helm values:
```shell
helm get values gitlab > gitlab_values.yaml
```
1. Edit `gitlab_values.yaml`:
```yaml
production:
global:
appConfig:
ldap:
servers:
main:
external_groups: ['interns', 'contractors']
```
1. Save the file and apply the new values:
```shell
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
```
:::TabTitle Docker
1. Edit `docker-compose.yml`:
```yaml
version: "3.6"
services:
gitlab:
environment:
GITLAB_OMNIBUS_CONFIG: |
gitlab_rails['ldap_servers'] = {
'main' => {
'external_groups' => ['interns', 'contractors'],
}
}
```
1. Save the file and restart GitLab:
```shell
docker compose up -d
```
:::TabTitle Self-compiled (source)
1. Edit `/home/git/gitlab/config/gitlab.yml`:
```yaml
production: &base
ldap:
servers:
main:
# snip...
external_groups: ['interns', 'contractors']
```
1. [Restart GitLab](../../restart_gitlab.md#installations-from-source) for the changes to take effect.
1. Save the file and restart GitLab:
```shell
# For systems running systemd
sudo systemctl restart gitlab.target
# For systems running SysV init
sudo service gitlab restart
```
::EndTabs
### Group sync technical details

View File

@ -7,7 +7,8 @@ disqus_identifier: 'https://docs.gitlab.com/ee/workflow/lfs/lfs_administration.h
# GitLab Git Large File Storage (LFS) Administration **(FREE SELF)**
Documentation about how to use Git LFS are under [Managing large binary files with Git LFS doc](../../topics/git/lfs/index.md).
This page contains information about configuring Git LFS in self-managed GitLab instances.
For user documentation about Git LFS, see [Git Large File Storage](../../topics/git/lfs/index.md).
LFS is enabled in GitLab self-managed instances by default.
@ -217,6 +218,12 @@ You can see the total storage used for LFS objects on groups and projects:
- In the administration area.
- In the [groups](../../api/groups.md) and [projects APIs](../../api/projects.md).
## Related topics
- Blog post: [Getting started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
- User documentation: [Git Large File Storage (LFS)](../../topics/git/lfs/index.md)
- [Git LFS developer information](../../development/lfs.md)
## Troubleshooting
### Missing LFS objects

View File

@ -13112,6 +13112,17 @@ Describes an external status check.
| <a id="fileuploadpath"></a>`path` | [`String!`](#string) | Path of the upload. |
| <a id="fileuploadsize"></a>`size` | [`Int!`](#int) | Size of the upload in bytes. |
### `ForkDetails`
Details of the fork project compared to its upstream project.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="forkdetailsahead"></a>`ahead` | [`Int`](#int) | Number of commits ahead of upstream. |
| <a id="forkdetailsbehind"></a>`behind` | [`Int`](#int) | Number of commits behind upstream. |
### `GeoNode`
#### Fields
@ -17457,6 +17468,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectenvironmentsstates"></a>`states` | [`[String!]`](#string) | States of environments that should be included in result. |
| <a id="projectenvironmentstype"></a>`type` | [`String`](#string) | Search query for environment type. |
##### `Project.forkDetails`
Details of the fork project compared to its upstream project.
WARNING:
**Introduced** in 15.7.
This feature is in Alpha. It can be changed or removed at any time.
Returns [`ForkDetails`](#forkdetails).
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectforkdetailsref"></a>`ref` | [`String`](#string) | Ref of the fork. Default value is HEAD. |
##### `Project.forkTargets`
Namespaces in which the current user can fork the project into.

View File

@ -4,7 +4,10 @@ group: Source Code
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Git LFS **(FREE)**
# Git LFS developer information **(FREE)**
This page contains developer-centric information for GitLab team members. For the
user documentation, see [Git Large File Storage](../topics/git/lfs/index.md).
## Deep Dive
@ -86,3 +89,9 @@ request is not preserved for the internal API requests made by Gitaly
correlation IDs for those API requests are random values until
[this Workhorse issue](https://gitlab.com/gitlab-org/gitlab-workhorse/-/issues/309) is
resolved.
## Related topics
- Blog post: [Getting started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
- User documentation: [Git Large File Storage (LFS)](../topics/git/lfs/index.md)
- [GitLab Git Large File Storage (LFS) Administration](../administration/lfs/index.md) for self-managed instances

View File

@ -36,7 +36,7 @@ The following table describes the version types and their release cadence:
| Version type | Description | Cadence |
|:-------------|:------------|:--------|
| Major | For significant changes, or when any backward-incompatible changes are introduced to the public API. | Yearly. The next major release is GitLab 15.0 on May 22, 2022. GitLab schedules major releases on May 22 each year, by default. |
| Major | For significant changes, or when any backward-incompatible changes are introduced to the public API. | Yearly. The next major release is GitLab 16.0 on May 22, 2023. GitLab schedules major releases on May 22 each year, by default. |
| Minor | For when new backward-compatible functionality is introduced to the public API, a minor feature is introduced, or when a set of smaller features is rolled out. | Monthly on the 22nd. |
| Patch | For backward-compatible bug fixes that fix incorrect behavior. See [Patch releases](#patch-releases). | As needed. |

View File

@ -148,6 +148,12 @@ LFS object.
Technical details about how this works can be found in the [development documentation for LFS](../../../development/lfs.md#including-lfs-blobs-in-project-archives).
## Related topics
- Blog post: [Getting started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
- [Git LFS developer information](../../../development/lfs.md)
- [GitLab Git Large File Storage (LFS) Administration](../../../administration/lfs/index.md) for self-managed instances
## Troubleshooting
### Encountered `n` files that should have been pointers, but weren't

View File

@ -191,6 +191,31 @@ From GitLab 16.0 and later, the runner registration methods implemented by the n
<div class="deprecation removal-160 breaking-change">
### Support for periods (`.`) in Terraform state names might break existing states
End of Support: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)<br />
Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
Previously, Terraform state names containing periods were not supported. However, you could still use state names with periods via a workaround.
GitLab 15.7 [adds full support](https://docs.gitlab.com/ee/user/infrastructure/iac/troubleshooting.html#state-not-found-if-the-state-name-contains-a-period) for state names that contain periods. If you used a workaround to handle these state names, your jobs might fail, or it might look like you've run Terraform for the first time.
To resolve the issue:
1. Change any references to the state file by excluding the period and any characters that follow.
- For example, if your state name is `state.name`, change all references to `state`.
1. Run your Terraform commands.
To use the full state name, including the period, [migrate to the full state file](https://docs.gitlab.com/ee/user/infrastructure/iac/terraform_state.html#migrate-to-a-gitlab-managed-terraform-state).
</div>
<div class="deprecation removal-160 breaking-change">
### The Phabricator task importer is deprecated
Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)

View File

@ -309,7 +309,7 @@ table.supported-languages ul {
<li>
<a id="notes-regarding-supported-languages-and-package-managers-3"></a>
<p>
npm is only supported when <code>lockfileVersion = 1</code> or <code>lockfileVersion = 2</code>. Work to add support for <code>lockfileVersion = 3</code> is being tracked in issue <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/365176">GitLab#365176</a>.
npm is supported for <code>lockfileVersion = 1</code>, <code>lockfileVersion = 2</code>, and <code>lockfileVersion = 3</code>. Support for <code>lockfileVersion = 3</code> was <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/365176">introduced</a> in GitLab 15.7</a>.
</p>
</li>
<li>

View File

@ -123,7 +123,7 @@ It can also help to compare the XML response from your provider with our [exampl
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/215155) in GitLab 15.5 [with a flag](../../../administration/feature_flags.md) named `transparent_sso_enforcement` to include transparent enforcement even when SSO enforcement is not enabled. Disabled on GitLab.com.
FLAG:
On self-managed GitLab, transparent SSO enforcement is unavailable. On GitLab.com, transparent SSO enforcement is unavailable and can be configured by GitLab.com administrators only.
On self-managed GitLab, transparent SSO enforcement is unavailable. On GitLab.com, see the [Transparent SSO rollout](https://gitlab.com/gitlab-org/gitlab/-/issues/375788) issue for the current status.
SSO is enforced when users access groups and projects in the organization's group hierarchy. Users can view other groups and projects without SSO sign in.
@ -177,6 +177,17 @@ When SSO is enforced, users are not immediately revoked. If the user:
- Has an active session, they can continue accessing the group for up to 24 hours until the identity
provider session times out.
### Selectively enable and disable transparent SSO enforcement
There are two feature flags associated with this feature to allow precise control. If a customer has a problem with transparent SSO on GitLab.com, GitLab can help troubleshoot and override the feature flag as necessary.
**`transparent_sso_enforcement`:** This feature flag should only be enabled or disabled by the Authentication and Authorization group
or in the case of a serious and widespread issue affecting many groups or users. See [issue 375788](https://gitlab.com/gitlab-org/gitlab/-/issues/375788) for the current GitLab.com rollout status.
**`transparent_sso_enforcement_override`:** When the `transparent_sso_enforcement` feature flag is enabled, support or production teams can
turn off transparent SSO by enabling this feature flag for a specific customer group. **Enabling** this feature flag
disables transparent SSO enforcement.
## Providers
The SAML standard means that you can use a wide range of identity providers with GitLab. Your identity provider might have relevant documentation. It can be generic SAML documentation or specifically targeted for GitLab.
@ -337,11 +348,14 @@ When a user tries to sign in with Group SSO, GitLab attempts to find or create a
### Linking SAML to your existing GitLab.com account
> **Remember me** checkbox [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/121569) in GitLab 15.7.
To link SAML to your existing GitLab.com account:
1. Sign in to your GitLab.com account. [Reset your password](https://gitlab.com/users/password/new) if necessary.
1. Locate and visit the **GitLab single sign-on URL** for the group you're signing in to. A group owner can find this on the group's **Settings > SAML SSO** page. If the sign-in URL is configured, users can connect to the GitLab app from the identity provider.
1. Optional. Select the **Remember me** checkbox to stay signed in to GitLab for 2 weeks. You may still be asked to re-authenticate with your SAML provider more frequently.
1. Optional. Select the **Remember me** checkbox to stay signed in to GitLab for 2 weeks. You may still be asked to re-authenticate with your SAML provider
more frequently.
1. Select **Authorize**.
1. Enter your credentials on the identity provider if prompted.
1. You are then redirected back to GitLab.com and should now have access to the group. In the future, you can use SAML to sign in to GitLab.com.

View File

@ -269,3 +269,15 @@ Pay particular attention to the following 403 errors:
- `app_not_configured`
- `app_not_configured_for_user`
## SAML Name ID and email address do not match your user account **(PREMIUM SAAS)**
If users encounter the error `SAML Name ID and email address do not match your user account. Contact an administrator.`
this means:
- The NameID value sent by SAML does not match the existing SAML identity `extern_uid` value.
- Either the SAML response did not include an email address or the email address did not match the user's GitLab email address.
A GitLab group Owner can use the [SAML API](../../../api/saml.md) to update the user's SAML `extern_uid`.
The `extern_uid` value must match the Name ID value sent by the SAML identity provider (IdP). Depending on the IdP configuration
this may be a generated unique ID, an email address, or other value.

View File

@ -118,27 +118,25 @@ A project-level endpoint is also required to install NuGet packages from a proje
To use the [project-level](#use-the-gitlab-endpoint-for-nuget-packages) NuGet endpoint, add the Package Registry as a source with Visual Studio:
1. Open [Visual Studio](https://visualstudio.microsoft.com/vs/).
1. In Windows, select **File > Options**. On macOS, select **Visual Studio > Preferences**.
1. In Windows, select **Tools > Options**. On macOS, select **Visual Studio > Preferences**.
1. In the **NuGet** section, select **Sources** to view a list of all your NuGet sources.
1. Select **Add**.
1. Complete the following fields:
- **Name**: Name for the source.
- **Location**: `https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/nuget/index.json`,
- **Source**: `https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/nuget/index.json`,
where `<your_project_id>` is your project ID, and `gitlab.example.com` is
your domain name.
1. Select **Save**.
1. When you access the package, you must enter your **Username** and **Password**:
- **Username**: Your GitLab username or deploy token username.
- **Password**: Your personal access token or deploy token.
![Visual Studio Adding a NuGet source](img/visual_studio_adding_nuget_source.png)
1. Select **Save**.
The source is displayed in your list.
![Visual Studio NuGet source added](img/visual_studio_nuget_source_added.png)
If you get a warning, ensure that the **Location**, **Username**, and
If you get a warning, ensure that the **Source**, **Username**, and
**Password** are correct.
#### Group-level endpoint
@ -148,27 +146,25 @@ To install a package from a group, use a group-level endpoint.
To use the [group-level](#use-the-gitlab-endpoint-for-nuget-packages) NuGet endpoint, add the Package Registry as a source with Visual Studio:
1. Open [Visual Studio](https://visualstudio.microsoft.com/vs/).
1. In Windows, select **File > Options**. On macOS, select **Visual Studio > Preferences**.
1. In Windows, select **Tools > Options**. On macOS, select **Visual Studio > Preferences**.
1. In the **NuGet** section, select **Sources** to view a list of all your NuGet sources.
1. Select **Add**.
1. Complete the following fields:
- **Name**: Name for the source.
- **Location**: `https://gitlab.example.com/api/v4/groups/<your_group_id>/-/packages/nuget/index.json`,
- **Source**: `https://gitlab.example.com/api/v4/groups/<your_group_id>/-/packages/nuget/index.json`,
where `<your_group_id>` is your group ID, and `gitlab.example.com` is
your domain name.
1. Select **Save**.
1. When you access the package, you must enter your **Username** and **Password**.
- **Username**: Your GitLab username or deploy token username.
- **Password**: Your personal access token or deploy token.
![Visual Studio Adding a NuGet source](img/visual_studio_adding_nuget_source.png)
1. Select **Save**.
The source is displayed in your list.
![Visual Studio NuGet source added](img/visual_studio_nuget_source_added.png)
If you get a warning, ensure that the **Location**, **Username**, and
If you get a warning, ensure that the **Source**, **Username**, and
**Password** are correct.
### Add a source with the .NET CLI

View File

@ -18,7 +18,7 @@ See these documents to migrate to GitLab:
- [From GitLab.com](gitlab_com.md)
- [From Gitea](gitea.md)
- [From Perforce](perforce.md)
- [From SVN](svn.md)
- [From SVN](https://git-scm.com/book/en/v2/Git-and-Other-Systems-Git-as-a-Client)
- [From TFVC](tfvc.md)
- [From repository by URL](repo_by_url.md)
- [By uploading a manifest file (AOSP)](manifest.md)

View File

@ -1,91 +1,11 @@
---
type: howto
stage: Manage
group: Import
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
redirect_to: 'index.md'
remove_date: '2023-03-15'
---
# Migrate from Subversion to GitLab **(FREE)**
This document was moved to [another location](index.md).
GitLab uses Git as its version control system. If you're using Subversion (SVN) as your version control system,
you can migrate to using a Git repository in GitLab using `svn2git`.
You can follow the steps on this page to migrate to Git if your SVN repository:
- Has a standard format (trunk, branches, and tags).
- Is not nested.
For a non-standard repository see the [`svn2git` documentation](https://github.com/nirvdrum/svn2git).
We recommend a hard cut over from SVN to Git and GitLab. Run the migration command once and then have all users use the
new GitLab repository immediately.
## Install `svn2git`
Install `svn2git` on a local workstation rather than the GitLab server:
- On all systems you can install as a Ruby gem if you already have Ruby and Git installed:
```shell
sudo gem install svn2git
```
- On Debian-based Linux distributions you can install the native packages:
```shell
sudo apt-get install git-core git-svn ruby
```
## Prepare an authors file (recommended)
Prepare an authors file so `svn2git` can map SVN authors to Git authors. If you choose not to create the authors file,
commits are not attributed to the correct GitLab user.
To map authors, you must map every author present on changes in the SVN repository. If you don't, the
migration fails and you have to update the author file accordingly.
1. Search through the SVN repository and output a list of authors:
```shell
svn log --quiet | grep -E "r[0-9]+ \| .+ \|" | cut -d'|' -f2 | sed 's/ //g' | sort | uniq
```
1. Use the output from the last command to construct the authors file. Create a file called `authors.txt` and add one
mapping per line. For example:
```plaintext
sidneyjones = Sidney Jones <sidneyjones@example.com>
```
## Migrate SVN repository to Git repository
`svn2git` supports excluding certain file paths, branches, tags, and more. See
the [`svn2git` documentation](https://github.com/nirvdrum/svn2git) or run `svn2git --help` for full documentation on all of
the available options.
For each repository to migrate:
1. Create a new directory and change into it.
1. For repositories that:
- Don't require a username and password, run:
```shell
svn2git https://svn.example.com/path/to/repo --authors /path/to/authors.txt
```
- Do require a username and password, run:
```shell
svn2git https://svn.example.com/path/to/repo --authors /path/to/authors.txt --username <username> --password <password>
```
1. Create a new GitLab project for your migrated code.
1. Copy the SSH or HTTP(S) repository URL from the GitLab project page.
1. Add the GitLab repository as a Git remote and push all the changes. This pushes all commits, branches, and tags.
```shell
git remote add origin git@gitlab.example.com:<group>/<project>.git
git push --all origin
git push --tags origin
```
<!-- This redirect file can be deleted after <2023-03-15>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -2128,6 +2128,9 @@ msgstr ""
msgid "Activate Service Desk"
msgstr ""
msgid "Activated"
msgstr ""
msgid "Active"
msgstr ""
@ -30289,6 +30292,9 @@ msgstr ""
msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
msgstr ""
msgid "PipelineSchedules|Cron timezone"
msgstr ""
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@ -30301,6 +30307,9 @@ msgstr ""
msgid "PipelineSchedules|Inactive"
msgstr ""
msgid "PipelineSchedules|Interval Pattern"
msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
@ -30328,6 +30337,9 @@ msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
msgid "PipelineSchedules|Save pipeline schedule"
msgstr ""
msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
msgstr ""
@ -40829,15 +40841,6 @@ msgstr ""
msgid "TemporaryStorageIncrease|can only be set with more than %{percentage}%% usage"
msgstr ""
msgid "TemporaryStorage|GitLab allows you a %{strongStart}free, one-time storage increase%{strongEnd}. For 30 days your storage will be unlimited. This gives you time to reduce your storage usage. After 30 days, your original storage limit of %{limit} applies. If you are at maximum storage capacity, your account will be read-only. To continue using GitLab you'll have to purchase additional storage or decrease storage usage."
msgstr ""
msgid "TemporaryStorage|Increase storage temporarily"
msgstr ""
msgid "TemporaryStorage|Temporarily increase storage now?"
msgstr ""
msgid "Terminal"
msgstr ""
@ -42727,7 +42730,7 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
msgstr ""
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
@ -44475,9 +44478,6 @@ msgstr ""
msgid "UsageQuota|Includes artifacts, repositories, wiki, uploads, and other items."
msgstr ""
msgid "UsageQuota|Increase storage temporarily"
msgstr ""
msgid "UsageQuota|LFS storage"
msgstr ""

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe 'Developer creates tag', feature_category: :source_code_management do
RSpec.describe 'Developer creates tag', :js, feature_category: :source_code_management do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: group) }
@ -15,6 +15,8 @@ RSpec.describe 'Developer creates tag', feature_category: :source_code_managemen
context 'from tag list' do
before do
visit project_tags_path(project)
click_link 'New tag'
wait_for_requests
end
it 'with an invalid name displays an error' do
@ -23,10 +25,17 @@ RSpec.describe 'Developer creates tag', feature_category: :source_code_managemen
expect(page).to have_content 'Tag name invalid'
end
it 'with an invalid reference displays an error' do
create_tag_in_form(tag: 'v2.0', ref: 'foo')
expect(page).to have_content 'Target foo is invalid'
it "doesn't allow to select invalid ref" do
ref_name = 'foo'
fill_in 'tag_name', with: 'v2.0'
ref_selector = '.ref-selector'
find(ref_selector).click
wait_for_requests
page.within(ref_selector) do
fill_in _('Search by Git revision'), with: ref_name
wait_for_requests
expect(find('.gl-dropdown-contents')).not_to have_content(ref_name)
end
end
it 'that already exists displays an error' do
@ -46,27 +55,34 @@ RSpec.describe 'Developer creates tag', feature_category: :source_code_managemen
end
end
it 'opens dropdown for ref', :js do
click_link 'New tag'
ref_row = find('.form-group:nth-of-type(2) .col-sm-12')
it 'opens dropdown for ref' do
ref_row = find('.form-group:nth-of-type(2) .col-sm-auto')
page.within ref_row do
ref_input = find('[name="ref"]', visible: false)
expect(ref_input.value).to eq 'master'
expect(find('.dropdown-toggle-text')).to have_content 'master'
find('.js-branch-select').click
expect(find('.dropdown-menu')).to have_content 'empty-branch'
expect(find('.gl-dropdown-button-text')).to have_content 'master'
find('.ref-selector').click
expect(find('.dropdown-menu')).to have_content 'test'
end
end
end
def create_tag_in_form(tag:, ref:, message: nil, desc: nil)
click_link 'New tag'
fill_in 'tag_name', with: tag
find('#ref', visible: false).set(ref)
select_ref(ref: ref)
fill_in 'message', with: message unless message.nil?
fill_in 'release_description', with: desc unless desc.nil?
click_button 'Create tag'
end
def select_ref(ref:)
ref_selector = '.ref-selector'
find(ref_selector).click
wait_for_requests
page.within(ref_selector) do
fill_in _('Search by Git revision'), with: ref
wait_for_requests
find('li', text: ref, match: :prefer_exact).click
end
end
end

View File

@ -1,25 +1,160 @@
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { GlForm } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import axios from '~/lib/utils/axios_utils';
import PipelineSchedulesForm from '~/ci/pipeline_schedules/components/pipeline_schedules_form.vue';
import RefSelector from '~/ref/components/ref_selector.vue';
import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants';
import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown/timezone_dropdown.vue';
import IntervalPatternInput from '~/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue';
import { timezoneDataFixture } from '../../../vue_shared/components/timezone_dropdown/helpers';
describe('Pipeline schedules form', () => {
let wrapper;
const defaultBranch = 'main';
const projectId = '1';
const cron = '';
const dailyLimit = '';
const createComponent = () => {
wrapper = shallowMount(PipelineSchedulesForm);
const createComponent = (mountFn = shallowMountExtended, stubs = {}) => {
wrapper = mountFn(PipelineSchedulesForm, {
propsData: {
timezoneData: timezoneDataFixture,
refParam: 'master',
},
provide: {
fullPath: 'gitlab-org/gitlab',
projectId,
defaultBranch,
cron,
cronTimezone: '',
dailyLimit,
settingsLink: '',
},
stubs,
});
};
const findForm = () => wrapper.findComponent(GlForm);
const findDescription = () => wrapper.findByTestId('schedule-description');
const findIntervalComponent = () => wrapper.findComponent(IntervalPatternInput);
const findTimezoneDropdown = () => wrapper.findComponent(TimezoneDropdown);
const findRefSelector = () => wrapper.findComponent(RefSelector);
const findSubmitButton = () => wrapper.findByTestId('schedule-submit-button');
const findCancelButton = () => wrapper.findByTestId('schedule-cancel-button');
// Variables
const findVariableRows = () => wrapper.findAllByTestId('ci-variable-row');
const findKeyInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-key');
const findValueInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-value');
const findRemoveIcons = () => wrapper.findAllByTestId('remove-ci-variable-row');
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
describe('Form elements', () => {
it('displays form', () => {
expect(findForm().exists()).toBe(true);
});
it('displays the description input', () => {
expect(findDescription().exists()).toBe(true);
});
it('displays the interval pattern component', () => {
const intervalPattern = findIntervalComponent();
expect(intervalPattern.exists()).toBe(true);
expect(intervalPattern.props()).toMatchObject({
initialCronInterval: cron,
dailyLimit,
sendNativeErrors: false,
});
});
it('displays the Timezone dropdown', () => {
const timezoneDropdown = findTimezoneDropdown();
expect(timezoneDropdown.exists()).toBe(true);
expect(timezoneDropdown.props()).toMatchObject({
value: '',
name: 'schedule-timezone',
timezoneData: timezoneDataFixture,
});
});
it('displays the branch/tag selector', () => {
const refSelector = findRefSelector();
expect(refSelector.exists()).toBe(true);
expect(refSelector.props()).toMatchObject({
enabledRefTypes: [REF_TYPE_BRANCHES, REF_TYPE_TAGS],
value: defaultBranch,
projectId,
translations: { dropdownHeader: 'Select target branch or tag' },
useSymbolicRefNames: true,
state: true,
name: '',
});
});
it('displays the submit and cancel buttons', () => {
expect(findSubmitButton().exists()).toBe(true);
expect(findCancelButton().exists()).toBe(true);
});
});
it('displays form', () => {
expect(findForm().exists()).toBe(true);
describe('CI variables', () => {
let mock;
const addVariableToForm = () => {
const input = findKeyInputs().at(0);
input.element.value = 'test_var_2';
input.trigger('change');
};
beforeEach(() => {
mock = new MockAdapter(axios);
createComponent(mountExtended);
});
afterEach(() => {
mock.restore();
});
it('creates blank variable on input change event', async () => {
expect(findVariableRows()).toHaveLength(1);
addVariableToForm();
await nextTick();
expect(findVariableRows()).toHaveLength(2);
expect(findKeyInputs().at(1).element.value).toBe('');
expect(findValueInputs().at(1).element.value).toBe('');
});
it('does not display remove icon for last row', async () => {
addVariableToForm();
await nextTick();
expect(findRemoveIcons()).toHaveLength(1);
});
it('removes ci variable row on remove icon button click', async () => {
addVariableToForm();
await nextTick();
expect(findVariableRows()).toHaveLength(2);
findRemoveIcons().at(0).trigger('click');
await nextTick();
expect(findVariableRows()).toHaveLength(1);
});
});
});

View File

@ -9,6 +9,10 @@ import waitForPromises from 'helpers/wait_for_promises';
jest.mock('@gitlab/web-ide');
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_action');
jest.mock('~/lib/utils/create_and_submit_form');
jest.mock('~/lib/utils/csrf', () => ({
token: 'mock-csrf-token',
headerKey: 'mock-csrf-header',
}));
const ROOT_ELEMENT_ID = 'ide';
const TEST_NONCE = 'test123nonce';
@ -77,6 +81,10 @@ describe('ide/init_gitlab_web_ide', () => {
ref: TEST_BRANCH_NAME,
gitlabUrl: TEST_GITLAB_URL,
nonce: TEST_NONCE,
httpHeaders: {
'mock-csrf-header': 'mock-csrf-token',
'X-Requested-With': 'XMLHttpRequest',
},
links: {
userPreferences: TEST_USER_PREFERENCES_PATH,
feedbackIssue: GITLAB_WEB_IDE_FEEDBACK_ISSUE,

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['ForkDetails'], feature_category: :source_code_management do
specify { expect(described_class.graphql_name).to eq('ForkDetails') }
it 'has specific fields' do
fields = %i[
ahead
behind
]
expect(described_class).to have_graphql_fields(*fields)
end
end

View File

@ -0,0 +1,60 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'getting project fork details', feature_category: :source_code_management do
include GraphqlHelpers
include ProjectForksHelper
let_it_be(:project) { create(:project, :public, :repository_private, :repository) }
let_it_be(:current_user) { create(:user, maintainer_projects: [project]) }
let_it_be(:forked_project) { fork_project(project, current_user, repository: true) }
let(:queried_project) { forked_project }
let(:query) do
graphql_query_for(:project,
{ full_path: queried_project.full_path }, <<~QUERY
forkDetails(ref: "feature"){
ahead
behind
}
QUERY
)
end
it 'returns fork details' do
post_graphql(query, current_user: current_user)
expect(graphql_data['project']['forkDetails']).to eq(
{ 'ahead' => 1, 'behind' => 29 }
)
end
context 'when a project is not a fork' do
let(:queried_project) { project }
it 'does not return fork details' do
post_graphql(query, current_user: current_user)
expect(graphql_data['project']['forkDetails']).to be_nil
end
end
context 'when a user cannot read the code' do
let_it_be(:current_user) { create(:user) }
before do
forked_project.update!({
repository_access_level: 'private',
merge_requests_access_level: 'private'
})
end
it 'does not return fork details' do
post_graphql(query, current_user: current_user)
expect(graphql_data['project']['forkDetails']).to be_nil
end
end
end