Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d22c6f7410
commit
bfa34fc19c
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
export const VARIABLE_TYPE = 'env_var';
|
||||
export const FILE_TYPE = '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,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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. |
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
1. Select **Save**.
|
||||
|
||||
The source is displayed in your list.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
1. Select **Save**.
|
||||
|
||||
The source is displayed in your list.
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 -->
|
||||
|
|
|
|||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue