Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-02-05 12:09:31 +00:00
parent 315243f877
commit 64f7eb2b37
189 changed files with 2082 additions and 1173 deletions

View File

@ -112,6 +112,7 @@
.workhorse-patterns: &workhorse-patterns
- "GITLAB_WORKHORSE_VERSION"
- "workhorse/**/*"
- ".gitlab/ci/workhorse.gitlab-ci.yml"
.yaml-lint-patterns: &yaml-lint-patterns
- ".gitlab-ci.yml"

View File

@ -8,3 +8,39 @@ workhorse:
- git checkout .
- scripts/update-workhorse check
- make -C workhorse
workhorse:verify:
extends: .workhorse:rules:workhorse
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.15
stage: test
needs: []
script:
- make -C workhorse verify
.workhorse:test:
extends: .workhorse:rules:workhorse
services:
- name: registry.gitlab.com/gitlab-org/build/cng/gitaly:latest
# Disable the hooks so we don't have to stub the GitLab API
command: ["/usr/bin/env", "GITALY_TESTING_NO_GIT_HOOKS=1", "/scripts/process-wrapper"]
alias: gitaly
variables:
GITALY_ADDRESS: "tcp://gitaly:8075"
stage: test
needs: []
script:
- go version
- apt-get update && apt-get -y install libimage-exiftool-perl
- make -C workhorse test
workhorse:test using go 1.13:
extends: .workhorse:test
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.13
workhorse:test using go 1.14:
extends: .workhorse:test
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.14
workhorse:test using go 1.15:
extends: .workhorse:test
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.15

View File

@ -1,20 +1,20 @@
<!-- Actionable insights must recommend an action that needs to take place. An actionable insight both defines the _insight_ and clearly calls out _action_ or next step required to improve based on the result of the research observation or data. Actionable insights are tracked over time and will include follow-up. Learn more in the handbook here: https://about.gitlab.com/handbook/engineering/ux/ux-research-training/research-insights/#actionable-insights -->
<!-- Actionable insights must recommend an action that needs to take place. An actionable insight both defines the insight and clearly calls out action or next step required to improve based on the result of the research observation or data. Actionable insights are tracked over time and will include follow-up. Learn more in the handbook here: https://about.gitlab.com/handbook/engineering/ux/ux-research-training/research-insights/#actionable-insights -->
### Insight
<!-- Describe the insight itself: often the problem, finding, or observation. _What_ is currently happening? -->
<!-- Describe the insight itself: often the problem, finding, or observation. -->
### Supporting evidence
<!-- Describe _why_ the problem is happening, or more details behind the finding or observation. Try to include quotes or specific data collected. Feel free to link the Actionable insight from Dovetail here if applicable instead of retyping details. -->
<!-- Describe why the problem is happening, or more details behind the finding or observation. Try to include quotes or specific data collected. Feel free to link the Actionable insight from Dovetail here if applicable instead of retyping details. -->
### Action
<!--Describe the next step or action that needs to take place as a result of the research. The action should be clearly defined, achievable, and directly tied back to the insight. Make sure to use directive terminology, such as: conduct, explore, redesign, etc. _How_ do we take a step toward improving the experience? -->
<!--Describe the next step or action that needs to take place as a result of the research. The action should be clearly defined, achievable, and directly tied back to the insight. Make sure to use directive terminology, such as: conduct, explore, redesign, etc. -->
### Resources
<!--Add resources as links below or as related issues. -->
- **Dovetail link:** [{Paste URL here}](url)
- **Research issue link:** [{Paste URL here}](url)
- **Follow-up issue:** [{Paste URL here}](url)
- :dove: [Dovetail project](Paste URL for Dovetail project here)
- :mag: [Research issue](Paste URL for research issue here)
- :footprints: [Follow-up issue or epic](Paste URL for follow-up issue or epic here)
### Tasks
- [ ] Assign this issue to the appropriate Product Manager, Product Designer, or UX Researcher.

View File

@ -2648,87 +2648,6 @@ Style/FrozenStringLiteralComment:
- 'bin/secpick'
- 'danger/changes_size/Dangerfile'
- 'danger/metadata/Dangerfile'
- 'ee/lib/tasks/geo.rake'
- 'ee/lib/tasks/geo/git.rake'
- 'ee/lib/tasks/geo/replication.rake'
- 'ee/lib/tasks/gitlab/db.rake'
- 'ee/lib/tasks/gitlab/elastic.rake'
- 'ee/lib/tasks/gitlab/elastic/test.rake'
- 'ee/lib/tasks/gitlab/geo.rake'
- 'ee/lib/tasks/gitlab/indexer.rake'
- 'ee/lib/tasks/gitlab/ldap.rake'
- 'ee/lib/tasks/gitlab/seed/insights.rake'
- 'ee/lib/tasks/gitlab/seed/metrics.rake'
- 'ee/lib/tasks/migrate/ldap.rake'
- 'lib/tasks/brakeman.rake'
- 'lib/tasks/cache.rake'
- 'lib/tasks/ci/cleanup.rake'
- 'lib/tasks/cleanup.rake'
- 'lib/tasks/config_lint.rake'
- 'lib/tasks/db_obsolete_ignored_columns.rake'
- 'lib/tasks/dev.rake'
- 'lib/tasks/downtime_check.rake'
- 'lib/tasks/eslint.rake'
- 'lib/tasks/file_hooks.rake'
- 'lib/tasks/frontend.rake'
- 'lib/tasks/gemojione.rake'
- 'lib/tasks/gitlab/artifacts/check.rake'
- 'lib/tasks/gitlab/artifacts/migrate.rake'
- 'lib/tasks/gitlab/backup.rake'
- 'lib/tasks/gitlab/bulk_add_permission.rake'
- 'lib/tasks/gitlab/check.rake'
- 'lib/tasks/gitlab/container_registry.rake'
- 'lib/tasks/gitlab/db.rake'
- 'lib/tasks/gitlab/doctor/secrets.rake'
- 'lib/tasks/gitlab/exclusive_lease.rake'
- 'lib/tasks/gitlab/external_diffs.rake'
- 'lib/tasks/gitlab/features.rake'
- 'lib/tasks/gitlab/generate_sample_prometheus_data.rake'
- 'lib/tasks/gitlab/git.rake'
- 'lib/tasks/gitlab/gitaly.rake'
- 'lib/tasks/gitlab/helpers.rake'
- 'lib/tasks/gitlab/import.rake'
- 'lib/tasks/gitlab/import_export.rake'
- 'lib/tasks/gitlab/info.rake'
- 'lib/tasks/gitlab/ldap.rake'
- 'lib/tasks/gitlab/lfs/check.rake'
- 'lib/tasks/gitlab/lfs/migrate.rake'
- 'lib/tasks/gitlab/list_repos.rake'
- 'lib/tasks/gitlab/packages/events.rake'
- 'lib/tasks/gitlab/packages/migrate.rake'
- 'lib/tasks/gitlab/pages.rake'
- 'lib/tasks/gitlab/praefect.rake'
- 'lib/tasks/gitlab/seed.rake'
- 'lib/tasks/gitlab/setup.rake'
- 'lib/tasks/gitlab/shell.rake'
- 'lib/tasks/gitlab/storage.rake'
- 'lib/tasks/gitlab/tcp_check.rake'
- 'lib/tasks/gitlab/test.rake'
- 'lib/tasks/gitlab/two_factor.rake'
- 'lib/tasks/gitlab/update_templates.rake'
- 'lib/tasks/gitlab/uploads/check.rake'
- 'lib/tasks/gitlab/uploads/migrate.rake'
- 'lib/tasks/gitlab/uploads/sanitize.rake'
- 'lib/tasks/gitlab/usage_data.rake'
- 'lib/tasks/gitlab/user_management.rake'
- 'lib/tasks/gitlab/web_hook.rake'
- 'lib/tasks/gitlab/workhorse.rake'
- 'lib/tasks/gitlab/x509/update.rake'
- 'lib/tasks/gitlab_danger.rake'
- 'lib/tasks/grape.rake'
- 'lib/tasks/haml-lint.rake'
- 'lib/tasks/import.rake'
- 'lib/tasks/karma.rake'
- 'lib/tasks/lint.rake'
- 'lib/tasks/migrate/composite_primary_keys.rake'
- 'lib/tasks/migrate/migrate_iids.rake'
- 'lib/tasks/migrate/setup_postgresql.rake'
- 'lib/tasks/pngquant.rake'
- 'lib/tasks/rubocop.rake'
- 'lib/tasks/scss-lint.rake'
- 'lib/tasks/setup.rake'
- 'lib/tasks/test.rake'
- 'lib/tasks/tokens.rake'
- 'qa/Gemfile'
- 'qa/Rakefile'
- 'qa/bin/qa'

View File

@ -2,7 +2,7 @@ import Vue from 'vue';
import StatisticsPanelApp from './components/app.vue';
import createStore from './store';
export default function (el) {
export default function initStatisticsPanel(el) {
if (!el) {
return false;
}

View File

@ -117,7 +117,6 @@ const boardsStore = {
},
updateNewListDropdown(listId) {
// eslint-disable-next-line no-unused-expressions
document
.querySelector(`.js-board-list-${getIdFromGraphQLId(listId)}`)
?.classList.remove('is-active');

View File

@ -5,7 +5,7 @@ import App from './components/app.vue';
Vue.use(VueApollo);
export default function () {
export default function initIssuableSuggestions() {
const el = document.getElementById('js-suggestions');
const issueTitle = document.getElementById('issue_title');
const { projectPath } = el.dataset;

View File

@ -71,7 +71,7 @@ if (gon?.disable_animations) {
// inject test utilities if necessary
if (process.env.NODE_ENV !== 'production' && gon?.test_env) {
disableJQueryAnimations();
import(/* webpackMode: "eager" */ './test_utils/'); // eslint-disable-line no-unused-expressions
import(/* webpackMode: "eager" */ './test_utils/');
}
document.addEventListener('beforeunload', () => {

View File

@ -739,9 +739,13 @@ export const updateConfidentialityOnIssuable = (
})
.then(({ data }) => {
const {
issueSetConfidential: { issue },
issueSetConfidential: { issue, errors },
} = data;
setConfidentiality({ commit }, issue.confidential);
if (errors?.length) {
Flash(errors[0], 'alert');
} else {
setConfidentiality({ commit }, issue.confidential);
}
});
};

View File

@ -1,13 +1,20 @@
<script>
import { GlSprintf, GlLink } from '@gitlab/ui';
import createFlash from '~/flash';
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
import MavenSettings from '~/packages_and_registries/settings/group/components/maven_settings.vue';
import {
PACKAGE_SETTINGS_HEADER,
PACKAGE_SETTINGS_DESCRIPTION,
PACKAGES_DOCS_PATH,
} from '../constants';
import getGroupPackagesSettingsQuery from '../graphql/queries/get_group_packages_settings.query.graphql';
ERROR_UPDATING_SETTINGS,
SUCCESS_UPDATING_SETTINGS,
} from '~/packages_and_registries/settings/group/constants';
import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update';
import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses';
import getGroupPackagesSettingsQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql';
import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
export default {
name: 'GroupSettingsApp',
@ -22,18 +29,9 @@ export default {
GlSprintf,
GlLink,
SettingsBlock,
MavenSettings,
},
inject: {
defaultExpanded: {
type: Boolean,
default: false,
required: true,
},
groupPath: {
type: String,
required: true,
},
},
inject: ['defaultExpanded', 'groupPath'],
apollo: {
packageSettings: {
query: getGroupPackagesSettingsQuery,
@ -50,8 +48,55 @@ export default {
data() {
return {
packageSettings: {},
errors: {},
};
},
computed: {
isLoading() {
return this.$apollo.queries.packageSettings.loading;
},
},
methods: {
updateSettings(payload) {
this.errors = {};
return this.$apollo
.mutate({
mutation: updateNamespacePackageSettings,
variables: {
input: {
namespacePath: this.groupPath,
...payload,
},
},
update: updateGroupPackageSettings(this.groupPath),
optimisticResponse: updateGroupPackagesSettingsOptimisticResponse({
...this.packageSettings,
...payload,
}),
})
.then(({ data }) => {
if (data.updateNamespacePackageSettings?.errors?.length > 0) {
createFlash({ message: ERROR_UPDATING_SETTINGS, type: 'warning' });
} else {
createFlash({ message: SUCCESS_UPDATING_SETTINGS, type: 'success' });
}
})
.catch((e) => {
if (e.graphQLErrors) {
e.graphQLErrors.forEach((error) => {
const [
{
path: [key],
message,
},
] = error.extensions.problems;
this.errors = { ...this.errors, [key]: message };
});
}
createFlash({ message: ERROR_UPDATING_SETTINGS, type: 'warning' });
});
},
},
};
</script>
@ -70,6 +115,15 @@ export default {
</gl-sprintf>
</span>
</template>
<template #default>
<maven-settings
:maven-duplicates-allowed="packageSettings.mavenDuplicatesAllowed"
:maven-duplicate-exception-regex="packageSettings.mavenDuplicateExceptionRegex"
:maven-duplicate-exception-regex-error="errors.mavenDuplicateExceptionRegex"
:loading="isLoading"
@update="updateSettings"
/>
</template>
</settings-block>
</div>
</template>

View File

@ -0,0 +1,113 @@
<script>
import { GlSprintf, GlToggle, GlFormGroup, GlFormInput } from '@gitlab/ui';
import {
MAVEN_TITLE,
MAVEN_SETTINGS_SUBTITLE,
MAVEN_DUPLICATES_ALLOWED_DISABLED,
MAVEN_DUPLICATES_ALLOWED_ENABLED,
MAVEN_SETTING_EXCEPTION_TITLE,
MAVEN_SETTINGS_EXCEPTION_LEGEND,
MAVEN_DUPLICATES_ALLOWED,
MAVEN_DUPLICATE_EXCEPTION_REGEX,
} from '~/packages_and_registries/settings/group/constants';
export default {
name: 'MavenSettings',
i18n: {
MAVEN_TITLE,
MAVEN_SETTINGS_SUBTITLE,
MAVEN_SETTING_EXCEPTION_TITLE,
MAVEN_SETTINGS_EXCEPTION_LEGEND,
},
modelNames: {
MAVEN_DUPLICATES_ALLOWED,
MAVEN_DUPLICATE_EXCEPTION_REGEX,
},
components: {
GlSprintf,
GlToggle,
GlFormGroup,
GlFormInput,
},
props: {
loading: {
type: Boolean,
required: false,
default: false,
},
mavenDuplicatesAllowed: {
type: Boolean,
default: false,
required: true,
},
mavenDuplicateExceptionRegex: {
type: String,
default: '',
required: true,
},
mavenDuplicateExceptionRegexError: {
type: String,
default: '',
required: false,
},
},
computed: {
enabledButtonLabel() {
return this.mavenDuplicatesAllowed
? MAVEN_DUPLICATES_ALLOWED_ENABLED
: MAVEN_DUPLICATES_ALLOWED_DISABLED;
},
isMavenDuplicateExceptionRegexValid() {
return !this.mavenDuplicateExceptionRegexError;
},
},
methods: {
update(type, value) {
this.$emit('update', { [type]: value });
},
},
};
</script>
<template>
<div>
<h5 class="gl-border-b-solid gl-border-b-1 gl-border-gray-200">
{{ $options.i18n.MAVEN_TITLE }}
</h5>
<p>{{ $options.i18n.MAVEN_SETTINGS_SUBTITLE }}</p>
<form>
<div class="gl-display-flex">
<gl-toggle
:value="mavenDuplicatesAllowed"
@change="update($options.modelNames.MAVEN_DUPLICATES_ALLOWED, $event)"
/>
<div class="gl-ml-5">
<div data-testid="toggle-label">
<gl-sprintf :message="enabledButtonLabel">
<template #bold="{ content }">
<strong>{{ content }}</strong>
</template>
</gl-sprintf>
</div>
<gl-form-group
v-if="!mavenDuplicatesAllowed"
class="gl-mt-4"
:label="$options.i18n.MAVEN_SETTING_EXCEPTION_TITLE"
label-size="sm"
:state="isMavenDuplicateExceptionRegexValid"
:invalid-feedback="mavenDuplicateExceptionRegexError"
:description="$options.i18n.MAVEN_SETTINGS_EXCEPTION_LEGEND"
label-for="maven-duplicated-settings-regex-input"
>
<gl-form-input
id="maven-duplicated-settings-regex-input"
:value="mavenDuplicateExceptionRegex"
@change="update($options.modelNames.MAVEN_DUPLICATE_EXCEPTION_REGEX, $event)"
/>
</gl-form-group>
</div>
</div>
</form>
</div>
</template>

View File

@ -1,4 +1,4 @@
import { s__ } from '~/locale';
import { s__, __ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
export const PACKAGE_SETTINGS_HEADER = s__('PackageRegistry|Package Registry');
@ -6,4 +6,26 @@ export const PACKAGE_SETTINGS_DESCRIPTION = s__(
'PackageRegistry|GitLab Packages allows organizations to utilize GitLab as a private repository for a variety of common package formats. %{linkStart}More Information%{linkEnd}',
);
export const MAVEN_TITLE = s__('PackageRegistry|Maven');
export const MAVEN_SETTINGS_SUBTITLE = s__('PackageRegistry|Settings for Maven packages');
export const MAVEN_DUPLICATES_ALLOWED_DISABLED = s__(
'PackageRegistry|%{boldStart}Do not allow duplicates%{boldEnd} - Packages with the same name and version are rejected.',
);
export const MAVEN_DUPLICATES_ALLOWED_ENABLED = s__(
'PackageRegistry|%{boldStart}Allow duplicates%{boldEnd} - Packages with the same name and version are accepted.',
);
export const MAVEN_SETTING_EXCEPTION_TITLE = __('Exceptions');
export const MAVEN_SETTINGS_EXCEPTION_LEGEND = s__(
'PackageRegistry|Packages can be published if their name or version matches this regex',
);
export const SUCCESS_UPDATING_SETTINGS = s__('PackageRegistry|Settings saved successfully');
export const ERROR_UPDATING_SETTINGS = s__(
'PackageRegistry|An error occurred while saving the settings',
);
// Parameters
export const PACKAGES_DOCS_PATH = helpPagePath('user/packages');
export const MAVEN_DUPLICATES_ALLOWED = 'mavenDuplicatesAllowed';
export const MAVEN_DUPLICATE_EXCEPTION_REGEX = 'mavenDuplicateExceptionRegex';

View File

@ -0,0 +1,22 @@
import { produce } from 'immer';
import getGroupPackagesSettingsQuery from '../queries/get_group_packages_settings.query.graphql';
export const updateGroupPackageSettings = (fullPath) => (client, { data: updatedData }) => {
const queryAndParams = {
query: getGroupPackagesSettingsQuery,
variables: { fullPath },
};
const sourceData = client.readQuery(queryAndParams);
const data = produce(sourceData, (draftState) => {
// eslint-disable-next-line no-param-reassign
draftState.group.packageSettings = {
...updatedData.updateNamespacePackageSettings.packageSettings,
};
});
client.writeQuery({
...queryAndParams,
data,
});
};

View File

@ -0,0 +1,11 @@
export const updateGroupPackagesSettingsOptimisticResponse = (changes) => ({
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'Mutation',
updateNamespacePackageSettings: {
__typename: 'UpdateNamespacePackageSettingsPayload',
errors: [],
packageSettings: {
...changes,
},
},
});

View File

@ -1,7 +1,7 @@
import ZenMode from '~/zen_mode';
import GLForm from '~/gl_form';
export default function ($formEl) {
export default function initProjectForm($formEl) {
new ZenMode(); // eslint-disable-line no-new
new GLForm($formEl); // eslint-disable-line no-new
}

View File

@ -16,7 +16,7 @@ import initInviteMemberModal from '~/invite_member/init_invite_member_modal';
import { IssuableType } from '~/issuable_show/constants';
export default function () {
export default function initShowIssue() {
const initialDataEl = document.getElementById('js-issuable-app');
const { issueType, ...issuableData } = parseIssuableData(initialDataEl);

View File

@ -10,7 +10,7 @@ import initInviteMemberTrigger from '~/invite_member/init_invite_member_trigger'
import initInviteMemberModal from '~/invite_member/init_invite_member_modal';
import StatusBox from '~/merge_request/components/status_box.vue';
export default function () {
export default function initMergeRequestShow() {
new ZenMode(); // eslint-disable-line no-new
initIssuableSidebar();
initPipelines();

View File

@ -9,6 +9,7 @@ import {
GlFormGroup,
GlFormInput,
GlFormSelect,
GlFormTextarea,
GlLink,
GlDropdown,
GlDropdownItem,
@ -38,6 +39,9 @@ export default {
errorTitle: __('Pipeline cannot be run.'),
warningTitle: __('The form contains the following warning:'),
maxWarningsSummary: __('%{total} warnings found: showing first %{warningsDisplayed}'),
// this height value is used inline on the textarea to match the input field height
// it's used to prevent the overwrite if 'gl-h-7' or 'gl-h-7!' were used
textAreaStyle: { height: '32px' },
components: {
GlAlert,
GlIcon,
@ -46,6 +50,7 @@ export default {
GlFormGroup,
GlFormInput,
GlFormSelect,
GlFormTextarea,
GlLink,
GlDropdown,
GlDropdownItem,
@ -426,10 +431,12 @@ export default {
data-testid="pipeline-form-ci-variable-key"
@change="addEmptyVariable(refFullName)"
/>
<gl-form-input
<gl-form-textarea
v-model="variable.value"
:placeholder="s__('CiVariables|Input variable value')"
class="gl-mb-3"
:style="$options.textAreaStyle"
:no-resize="false"
data-testid="pipeline-form-ci-variable-value"
/>

View File

@ -1,24 +1,13 @@
<script>
import { GlButton } from '@gitlab/ui';
import { isExperimentEnabled } from '~/lib/utils/experimentation';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
export default {
i18n: {
control: {
infoMessage: s__(`Pipelines|Continuous Integration can help
catch bugs by running your tests automatically,
while Continuous Deployment can help you deliver
code to your product environment.`),
buttonMessage: s__('Pipelines|Get started with Pipelines'),
},
experiment: {
infoMessage: s__(`Pipelines|GitLab CI/CD can automatically build,
infoMessage: s__(`Pipelines|GitLab CI/CD can automatically build,
test, and deploy your code. Let GitLab take care of time
consuming tasks, so you can spend more time creating.`),
buttonMessage: s__('Pipelines|Get started with CI/CD'),
},
buttonMessage: s__('Pipelines|Get started with CI/CD'),
},
name: 'PipelinesEmptyState',
components: {
@ -38,23 +27,6 @@ export default {
required: true,
},
},
mounted() {
this.track('viewed');
},
methods: {
track(action) {
if (!gon.tracking_data) {
return;
}
const { category, value, label, property } = gon.tracking_data;
Tracking.event(category, action, { value, label, property });
},
isExperimentEnabled() {
return isExperimentEnabled('pipelinesEmptyState');
},
},
};
</script>
<template>
@ -70,11 +42,7 @@ export default {
{{ s__('Pipelines|Build with confidence') }}
</h4>
<p data-testid="info-text">
{{
isExperimentEnabled()
? $options.i18n.experiment.infoMessage
: $options.i18n.control.infoMessage
}}
{{ $options.i18n.infoMessage }}
</p>
<div class="gl-text-center">
@ -83,13 +51,8 @@ export default {
variant="info"
category="primary"
data-testid="get-started-pipelines"
@click="track('documentation_clicked')"
>
{{
isExperimentEnabled()
? $options.i18n.experiment.buttonMessage
: $options.i18n.control.buttonMessage
}}
{{ $options.i18n.buttonMessage }}
</gl-button>
</div>
</template>

View File

@ -77,7 +77,7 @@ const createTestDetails = () => {
});
};
export default async function () {
export default async function initPipelineDetailsBundle() {
createTestDetails();
createDagApp();

View File

@ -1,7 +1,7 @@
import Vue from 'vue';
import NewProjectCreationApp from './components/app.vue';
export default function (el, props) {
export default function initNewProjectCreation(el, props) {
return new Vue({
el,
components: {

View File

@ -60,8 +60,8 @@ export default {
const nextItemEl = itemEl.nextElementSibling;
return {
beforeId: prevItemEl && parseInt(prevItemEl.dataset.orderingId, 0),
afterId: nextItemEl && parseInt(nextItemEl.dataset.orderingId, 0),
beforeId: prevItemEl && parseInt(prevItemEl.dataset.orderingId, 10),
afterId: nextItemEl && parseInt(nextItemEl.dataset.orderingId, 10),
};
},
reordered(event) {

View File

@ -86,7 +86,7 @@ const createValidator = (context, feedbackMap) => ({ el, reportInvalidInput = fa
* @param {Object<string, { message: string, isValid: ?function}>} customFeedbackMap
* @returns {{ inserted: function, update: function }} validateDirective
*/
export default function (customFeedbackMap = {}) {
export default function initValidation(customFeedbackMap = {}) {
const feedbackMap = merge(defaultFeedbackMap, customFeedbackMap);
const elDataMap = new WeakMap();

View File

@ -156,14 +156,6 @@
color: inherit;
}
// TODO remove this class once we can generate a correct hover utility from `gitlab/ui`,
// see here: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39286#note_396767000
.btn-link-hover:hover {
* {
@include gl-text-blue-800;
}
}
.issuable-header-text {
margin-top: 7px;
}

View File

@ -12,7 +12,6 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
before_action :build_merge_request, except: [:create]
before_action do
push_frontend_feature_flag(:merge_request_reviewers, @project, default_enabled: true)
push_frontend_feature_flag(:mr_collapsed_approval_rules, @project)
push_frontend_feature_flag(:reviewer_approval_rules, @project, default_enabled: :yaml)
end

View File

@ -52,7 +52,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
before_action do
push_frontend_feature_flag(:merge_request_reviewers, @project, default_enabled: true)
push_frontend_feature_flag(:mr_collapsed_approval_rules, @project)
push_frontend_feature_flag(:reviewer_approval_rules, @project, default_enabled: :yaml)
end

View File

@ -20,7 +20,6 @@ class Projects::PipelinesController < Projects::ApplicationController
push_frontend_feature_flag(:jira_for_vulnerabilities, project, type: :development, default_enabled: :yaml)
end
before_action :ensure_pipeline, only: [:show]
before_action :push_experiment_to_gon, only: :index, if: :html_request?
# Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/225596
before_action :redirect_for_legacy_scope_filter, only: [:index], if: -> { request.format.html? }
@ -45,11 +44,7 @@ class Projects::PipelinesController < Projects::ApplicationController
@pipelines_count = limited_pipelines_count(project)
respond_to do |format|
format.html do
record_empty_pipeline_experiment
render :index
end
format.html
format.json do
Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)
@ -300,20 +295,6 @@ class Projects::PipelinesController < Projects::ApplicationController
def index_params
params.permit(:scope, :username, :ref, :status)
end
def record_empty_pipeline_experiment
return unless @pipelines_count.to_i == 0
return if helpers.has_gitlab_ci?(@project)
record_experiment_user(:pipelines_empty_state)
end
def push_experiment_to_gon
return unless current_user
push_frontend_experiment(:pipelines_empty_state, subject: current_user)
frontend_experimentation_tracking_data(:pipelines_empty_state, 'view', project.namespace_id, subject: current_user)
end
end
Projects::PipelinesController.prepend_if_ee('EE::Projects::PipelinesController')

View File

@ -22,7 +22,7 @@ module Resolvers
def only_count_is_selected_with_merged_at_filter?(args)
return unless lookahead
argument_names = args.except(:lookahead, :sort, :merged_before, :merged_after).keys
argument_names = args.compact.except(:lookahead, :sort, :merged_before, :merged_after).keys
# no extra filtering arguments are provided
return unless argument_names.empty?
@ -34,7 +34,7 @@ module Resolvers
# totalTimeToMerge
# }
allowed_selected_fields = [:count, :total_time_to_merge]
selected_fields = lookahead.selections.map(&:field).map(&:original_name)
selected_fields = lookahead.selections.map(&:field).map(&:original_name) - [:__typename] # ignore __typename meta field
# only the allowed_selected_fields are present
(selected_fields - allowed_selected_fields).empty?

View File

@ -243,7 +243,7 @@ module Types
end
def reviewers
object.reviewers if object.allows_reviewers?
object.reviewers
end
end
end

View File

@ -174,15 +174,9 @@ module MergeRequestsHelper
end
end
def merge_request_reviewers_enabled?
Feature.enabled?(:merge_request_reviewers, default_enabled: :yaml)
end
private
def review_requested_merge_requests_count
return 0 unless merge_request_reviewers_enabled?
current_user.review_requested_open_merge_requests_count
end

View File

@ -996,7 +996,7 @@ module Ci
end
def has_coverage_reports?
pipeline_artifacts&.has_report?(:code_coverage)
pipeline_artifacts&.report_exists?(:code_coverage)
end
def can_generate_coverage_reports?
@ -1004,7 +1004,7 @@ module Ci
end
def has_codequality_mr_diff_report?
pipeline_artifacts&.has_report?(:code_quality_mr_diff)
pipeline_artifacts&.report_exists?(:code_quality_mr_diff)
end
def can_generate_codequality_reports?

View File

@ -18,6 +18,11 @@ module Ci
code_quality_mr_diff: 'code_quality_mr_diff.json'
}.freeze
REPORT_TYPES = {
code_coverage: :raw,
code_quality_mr_diff: :raw
}.freeze
belongs_to :project, class_name: "Project", inverse_of: :pipeline_artifacts
belongs_to :pipeline, class_name: "Ci::Pipeline", inverse_of: :pipeline_artifacts
@ -36,7 +41,9 @@ module Ci
}
class << self
def has_report?(file_type)
def report_exists?(file_type)
return false unless REPORT_TYPES.key?(file_type)
where(file_type: file_type).exists?
end

View File

@ -1784,7 +1784,7 @@ class MergeRequest < ApplicationRecord
end
def allows_reviewers?
Feature.enabled?(:merge_request_reviewers, project, default_enabled: true)
true
end
def allows_multiple_reviewers?

View File

@ -30,7 +30,8 @@ class JiraService < IssueTrackerService
# TODO: we can probably just delegate as part of
# https://gitlab.com/gitlab-org/gitlab/issues/29404
data_field :username, :password, :url, :api_url, :jira_issue_transition_id, :project_key, :issues_enabled, :vulnerabilities_enabled, :vulnerabilities_issuetype
data_field :username, :password, :url, :api_url, :jira_issue_transition_id, :project_key, :issues_enabled,
:vulnerabilities_enabled, :vulnerabilities_issuetype, :proxy_address, :proxy_port, :proxy_username, :proxy_password
before_update :reset_password
after_commit :update_deployment_type, on: [:create, :update], if: :update_deployment_type?

View File

@ -7,6 +7,15 @@ class JiraTrackerData < ApplicationRecord
attr_encrypted :api_url, encryption_options
attr_encrypted :username, encryption_options
attr_encrypted :password, encryption_options
attr_encrypted :proxy_address, encryption_options
attr_encrypted :proxy_port, encryption_options
attr_encrypted :proxy_username, encryption_options
attr_encrypted :proxy_password, encryption_options
validates :proxy_address, length: { maximum: 2048 }
validates :proxy_port, length: { maximum: 5 }
validates :proxy_username, length: { maximum: 255 }
validates :proxy_password, length: { maximum: 255 }
enum deployment_type: { unknown: 0, server: 1, cloud: 2 }, _prefix: :deployment
end

View File

@ -10,7 +10,7 @@ class MergeRequestBasicEntity < Grape::Entity
expose :milestone, using: API::Entities::Milestone
expose :labels, using: LabelEntity
expose :assignees, using: API::Entities::UserBasic
expose :reviewers, if: -> (m) { m.allows_reviewers? }, using: API::Entities::UserBasic
expose :reviewers, using: API::Entities::UserBasic
expose :task_status, :task_status_short
expose :lock_version, :lock_version
end

View File

@ -5,7 +5,7 @@ class MergeRequestSidebarExtrasEntity < IssuableSidebarExtrasEntity
MergeRequestUserEntity.represent(merge_request.assignees, options.merge(merge_request: merge_request))
end
expose :reviewers, if: -> (m) { m.allows_reviewers? } do |merge_request, options|
expose :reviewers do |merge_request, options|
MergeRequestUserEntity.represent(merge_request.reviewers, options.merge(merge_request: merge_request))
end
end

View File

@ -123,7 +123,6 @@ module Ci
def record_conversion_event
Experiments::RecordConversionEventWorker.perform_async(:ci_syntax_templates, current_user.id)
Experiments::RecordConversionEventWorker.perform_async(:pipelines_empty_state, current_user.id)
end
def create_namespace_onboarding_action

View File

@ -11,7 +11,7 @@ module Ci
pipeline.pipeline_artifacts.create!(
project_id: pipeline.project_id,
file_type: :code_coverage,
file_format: :raw,
file_format: Ci::PipelineArtifact::REPORT_TYPES.fetch(:code_coverage),
size: file["tempfile"].size,
file: file,
expire_at: Ci::PipelineArtifact::EXPIRATION_DATE.from_now

View File

@ -11,7 +11,7 @@ module Ci
pipeline.pipeline_artifacts.create!(
project_id: pipeline.project_id,
file_type: :code_quality_mr_diff,
file_format: :raw,
file_format: Ci::PipelineArtifact::REPORT_TYPES.fetch(:code_quality_mr_diff),
size: file["tempfile"].size,
file: file,
expire_at: Ci::PipelineArtifact::EXPIRATION_DATE.from_now

View File

@ -18,6 +18,7 @@ module DesignManagement
return error("Only #{MAX_FILES} files are allowed simultaneously") if files.size > MAX_FILES
return error("Duplicate filenames are not allowed!") if files.map(&:original_filename).uniq.length != files.length
return error("Design copy is in progress") if design_collection.copy_in_progress?
return error("Filenames contained invalid characters and could not be saved") if files.any?(&:filename_sanitized?)
uploaded_designs, version = upload_designs!
skipped_designs = designs - uploaded_designs

View File

@ -108,7 +108,7 @@ module MergeRequests
def filter_reviewer(merge_request)
return if params[:reviewer_ids].blank?
unless can_admin_issuable?(merge_request) && merge_request.allows_reviewers?
unless can_admin_issuable?(merge_request)
params.delete(:reviewer_ids)
return

View File

@ -29,6 +29,7 @@
= f.number_field :session_expire_delay, class: 'form-control gl-form-input', title: _('Maximum duration of a session.'), data: { toggle: 'tooltip', container: 'body' }
%span.form-text.text-muted#session_expire_delay_help_block= _('GitLab restart is required to apply changes.')
= render_if_exists 'admin/application_settings/git_two_factor_session_expiry', form: f
= render_if_exists 'admin/application_settings/personal_access_token_expiration_policy', form: f
= render_if_exists 'admin/application_settings/enforce_pat_expiration', form: f
= render_if_exists 'admin/application_settings/enforce_ssh_key_expiration', form: f

View File

@ -1,7 +1,7 @@
- breadcrumb_title _('Repository Settings')
- page_title _('Repository')
- deploy_token_description = s_('DeployTokens|Group Deploy Tokens allow access to the packages, repositories, and registry images within the group.')
- deploy_token_description = s_('DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group.')
= render "shared/deploy_tokens/index", group_or_project: @group, description: deploy_token_description
= render "initial_branch_name", group: @group

View File

@ -47,11 +47,10 @@
%span.badge.badge-pill.issues-count.green-badge{ class: ('hidden' if issues_count == 0) }
= number_with_delimiter(issues_count)
- if header_link?(:merge_requests)
- reviewers_enabled = merge_request_reviewers_enabled?
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter #{reviewers_enabled ? 'dropdown' : ''}" }) do
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter dropdown" }) do
= link_to assigned_mrs_dashboard_path, class: 'dashboard-shortcuts-merge_requests', title: _('Merge requests'), aria: { label: _('Merge requests') },
data: { qa_selector: 'merge_requests_shortcut_button',
toggle: reviewers_enabled ? "dropdown" : "tooltip",
toggle: "dropdown",
placement: 'bottom',
track_label: 'main_navigation',
track_event: 'click_merge_link',
@ -60,23 +59,21 @@
= sprite_icon('git-merge')
%span.badge.badge-pill.merge-requests-count.js-merge-requests-count{ class: ('hidden' if user_merge_requests_counts[:total] == 0) }
= number_with_delimiter(user_merge_requests_counts[:total])
- if reviewers_enabled
= sprite_icon('chevron-down', css_class: 'caret-down gl-mx-0!')
- if reviewers_enabled
.dropdown-menu.dropdown-menu-right
%ul
%li.dropdown-header
= _('Merge requests')
%li
= link_to assigned_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center' do
= _('Assigned to you')
%span.badge.gl-badge.badge-pill.badge-muted.merge-request-badge.gl-ml-auto.js-assigned-mr-count{ class: "" }
= user_merge_requests_counts[:assigned]
%li
= link_to reviewer_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center' do
= _('Review requests for you')
%span.badge.gl-badge.badge-pill.badge-muted.merge-request-badge.gl-ml-auto.js-reviewer-mr-count{ class: "" }
= user_merge_requests_counts[:review_requested]
= sprite_icon('chevron-down', css_class: 'caret-down gl-mx-0!')
.dropdown-menu.dropdown-menu-right
%ul
%li.dropdown-header
= _('Merge requests')
%li
= link_to assigned_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center' do
= _('Assigned to you')
%span.badge.gl-badge.badge-pill.badge-muted.merge-request-badge.gl-ml-auto.js-assigned-mr-count{ class: "" }
= user_merge_requests_counts[:assigned]
%li
= link_to reviewer_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center' do
= _('Review requests for you')
%span.badge.gl-badge.badge-pill.badge-muted.merge-request-badge.gl-ml-auto.js-reviewer-mr-count{ class: "" }
= user_merge_requests_counts[:review_requested]
- if header_link?(:todos)
= nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
= link_to dashboard_todos_path, title: _('To-Do List'), aria: { label: _('To-Do List') }, class: 'shortcuts-todos',

View File

@ -45,7 +45,7 @@
= s_('AccessTokens|It cannot be used to access any other data.')
.col-lg-8.feed-token-reset
= label_tag :feed_token, s_('AccessTokens|Feed token'), class: 'label-bold'
= text_field_tag :feed_token, current_user.feed_token, class: 'form-control js-select-on-focus', readonly: true
= text_field_tag :feed_token, current_user.feed_token, class: 'form-control gl-form-input js-select-on-focus', readonly: true
%p.form-text.text-muted
- reset_link = link_to s_('AccessTokens|reset it'), [:reset, :feed_token, :profile], method: :put, data: { confirm: s_('AccessTokens|Are you sure? Any RSS or calendar URLs currently in use will stop working.') }
- reset_message = s_('AccessTokens|Keep this token secret. Anyone who gets ahold of it can read activity and issue RSS feeds or your calendar feed as if they were you. You should %{link_reset_it} if that ever happens.') % { link_reset_it: reset_link }
@ -64,7 +64,7 @@
= s_('AccessTokens|It cannot be used to access any other data.')
.col-lg-8.incoming-email-token-reset
= label_tag :incoming_email_token, s_('AccessTokens|Incoming email token'), class: 'label-bold'
= text_field_tag :incoming_email_token, current_user.incoming_email_token, class: 'form-control js-select-on-focus', readonly: true
= text_field_tag :incoming_email_token, current_user.incoming_email_token, class: 'form-control gl-form-input js-select-on-focus', readonly: true
%p.form-text.text-muted
- reset_link = link_to s_('AccessTokens|reset it'), [:reset, :incoming_email_token, :profile], method: :put, data: { confirm: s_('AccessTokens|Are you sure? Any issue email addresses currently in use will stop working.') }
- reset_message = s_('AccessTokens|Keep this token secret. Anyone who gets ahold of it can create issues as if they were you. You should %{link_reset_it} if that ever happens.') % { link_reset_it: reset_link }
@ -83,7 +83,7 @@
= s_('AccessTokens|It cannot be used to access any other data.')
.col-lg-8
= label_tag :static_object_token, s_('AccessTokens|Static object token'), class: "label-bold"
= text_field_tag :static_object_token, current_user.static_object_token, class: 'form-control', readonly: true, onclick: 'this.select()'
= text_field_tag :static_object_token, current_user.static_object_token, class: 'form-control gl-form-input', readonly: true, onclick: 'this.select()'
%p.form-text.text-muted
- reset_link = url_for [:reset, :static_object_token, :profile]
- reset_link_start = '<a data-confirm="%{confirm}" rel="nofollow" data-method="put" href="%{url}">'.html_safe % { confirm: s_('AccessTokens|Are you sure?'), url: reset_link }

View File

@ -2,7 +2,7 @@
%section.settings.no-animate#default-branch-settings{ class: ('expanded' if expanded) }
.settings-header
%h4= _('Default Branch')
%h4= _('Default branch')
%button.btn.js-settings-toggle
= expanded ? _('Collapse') : _('Expand')
%p
@ -16,7 +16,7 @@
= _('A default branch cannot be chosen for an empty project.')
- else
.form-group
= f.label :default_branch, "Default Branch", class: 'label-bold'
= f.label :default_branch, "Default branch", class: 'label-bold'
= f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'})
.form-group

View File

@ -55,7 +55,7 @@
- if merge_request.assignees.any?
%li.gl-display-flex.gl-align-items-center
= render 'shared/issuable/assignees', project: merge_request.project, issuable: merge_request
- if Feature.enabled?(:merge_request_reviewers, @project, default_enabled: true) && merge_request.reviewers.any?
- if merge_request.reviewers.any?
%li.gl-display-flex.issuable-reviewers
= render 'shared/issuable/reviewers', project: merge_request.project, issuable: merge_request
= render 'projects/merge_requests/approvals_count', merge_request: merge_request

View File

@ -3,7 +3,7 @@
%section.settings.no-animate#js-protected-branches-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_branches_settings_content' } }
.settings-header
%h4
Protected Branches
Protected branches
%button.btn.js-settings-toggle.qa-expand-protected-branches{ type: 'button' }
= expanded ? 'Collapse' : 'Expand'
%p

View File

@ -3,7 +3,7 @@
%section.settings.no-animate#js-protected-tags-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_tag_settings_content' } }
.settings-header
%h4
Protected Tags
Protected tags
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? 'Collapse' : 'Expand'
%p

View File

@ -1,7 +1,7 @@
- breadcrumb_title _("Repository Settings")
- page_title _("Repository")
- @content_class = "limit-container-width" unless fluid_layout
- deploy_token_description = s_('DeployTokens|Deploy Tokens allow access to packages, your repository, and registry images.')
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to packages, your repository, and registry images.')
= render "projects/default_branch/show"
= render_if_exists "projects/push_rules/index"

View File

@ -1,12 +1,12 @@
- expanded = expanded_by_default?
%section.qa-deploy-keys-settings.settings.no-animate#js-deploy-keys-settings{ class: ('expanded' if expanded), data: { qa_selector: 'deploy_keys_settings_content' } }
.settings-header
%h4= _('Deploy Keys')
%h4= _('Deploy keys')
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? 'Collapse' : 'Expand'
%p
- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/deploy_keys/index') }
= _("Add deploy keys to grant read/write access to this repository. %{link_start}What are Deploy Keys?%{link_end}").html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
= _("Add deploy keys to grant read/write access to this repository. %{link_start}What are deploy keys?%{link_end}").html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
.settings-content
%h5.gl-mt-0
= render @deploy_keys.form_partial_path

View File

@ -2,7 +2,7 @@
%section.qa-deploy-tokens-settings.settings.no-animate#js-deploy-tokens{ class: ('expanded' if expanded), data: { qa_selector: 'deploy_tokens_settings_content' } }
.settings-header
%h4= s_('DeployTokens|Deploy Tokens')
%h4= s_('DeployTokens|Deploy tokens')
%button.gl-button.btn.js-settings-toggle.qa-expand-deploy-keys{ type: 'button' }
= expanded ? 'Collapse' : 'Expand'
%p
@ -11,7 +11,7 @@
- if @new_deploy_token.persisted?
= render 'shared/deploy_tokens/new_deploy_token', deploy_token: @new_deploy_token
%h5.gl-mt-0
= s_('DeployTokens|Add a Deploy Token')
= s_('DeployTokens|Add a deploy token')
= render 'shared/deploy_tokens/form', group_or_project: group_or_project, token: @new_deploy_token, presenter: @deploy_tokens
%hr
= render 'shared/deploy_tokens/table', group_or_project: group_or_project, active_tokens: @deploy_tokens

View File

@ -26,7 +26,7 @@
.block.assignee.qa-assignee-block
= render "shared/issuable/sidebar_assignees", issuable_sidebar: issuable_sidebar, assignees: assignees, signed_in: signed_in
- if Feature.enabled?(:merge_request_reviewers, @project, default_enabled: true) && reviewers
- if reviewers
.block.reviewer.qa-reviewer-block
= render "shared/issuable/sidebar_reviewers", issuable_sidebar: issuable_sidebar, reviewers: reviewers, signed_in: signed_in

View File

@ -0,0 +1,5 @@
---
title: Add Jira proxy settings columns
merge_request: 52119
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Apply new GitLab UI for input field in user personal access token settings
merge_request: 52426
author: Yogi (@yo)
type: other

View File

@ -0,0 +1,5 @@
---
title: 'Designs: return error if uploading filenames with special chars'
merge_request: 44136
author: Sushil Khanchi @khanchi97
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Change pipeline empty state language
merge_request: 53281
author:
type: changed

View File

@ -0,0 +1,6 @@
---
title: Support multi-line string variable values when running a manual pipeline in
the UI.
merge_request: 53292
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Remove merge_request_reviewers feature flag
merge_request: 52468
author:
type: removed

View File

@ -0,0 +1,5 @@
---
title: Updated UI text to be sentence case
merge_request: 53323
author:
type: other

View File

@ -1,8 +0,0 @@
---
name: merge_request_reviewers
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40488
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/245190
milestone: '13.4'
type: development
group: group::code review
default_enabled: true

View File

@ -1,8 +0,0 @@
---
name: pipelines_empty_state_experiment_percentage
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47952
rollout_issue_url: https://gitlab.com/gitlab-org/growth/team-tasks/-/issues/289
milestone: '13.8'
type: experiment
group: group::activation
default_enabled: false

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddProxySettingsToJiraTrackerData < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :jira_tracker_data, :encrypted_proxy_address, :text
add_column :jira_tracker_data, :encrypted_proxy_address_iv, :text
add_column :jira_tracker_data, :encrypted_proxy_port, :text
add_column :jira_tracker_data, :encrypted_proxy_port_iv, :text
add_column :jira_tracker_data, :encrypted_proxy_username, :text
add_column :jira_tracker_data, :encrypted_proxy_username_iv, :text
add_column :jira_tracker_data, :encrypted_proxy_password, :text
add_column :jira_tracker_data, :encrypted_proxy_password_iv, :text
end
end

View File

@ -0,0 +1 @@
c8b5485f158fdec0ab6813e4014713786dfa231b901e77ea610a873d03f8f0f0

View File

@ -13602,6 +13602,14 @@ CREATE TABLE jira_tracker_data (
deployment_type smallint DEFAULT 0 NOT NULL,
vulnerabilities_issuetype text,
vulnerabilities_enabled boolean DEFAULT false NOT NULL,
encrypted_proxy_address text,
encrypted_proxy_address_iv text,
encrypted_proxy_port text,
encrypted_proxy_port_iv text,
encrypted_proxy_username text,
encrypted_proxy_username_iv text,
encrypted_proxy_password text,
encrypted_proxy_password_iv text,
CONSTRAINT check_0bf84b76e9 CHECK ((char_length(vulnerabilities_issuetype) <= 255)),
CONSTRAINT check_214cf6a48b CHECK ((char_length(project_key) <= 255))
);

View File

@ -454,10 +454,10 @@ Parameters:
| `author_id` | integer | no | Returns merge requests created by the given user `id`. Mutually exclusive with `author_username`. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13060) in GitLab 9.5)_. |
| `author_username` | string | no | Returns merge requests created by the given `username`. Mutually exclusive with `author_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13060) in GitLab 12.10)_. |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13060) in GitLab 9.5)_. |
| `approver_ids` **(PREMIUM)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approver_ids` **(PREMIUM))** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved_by_ids` **(PREMIUM)** | integer array | no | Returns merge requests which have been approved by all the users with the given `id`s (Max: 5). `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
| `reviewer_id` | integer | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#enable-or-disable-merge-request-reviewers) with the given user `id`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_username`. |
| `reviewer_username` | string | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#enable-or-disable-merge-request-reviewers) with the given `username`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_id`. |
| `reviewer_id` | integer | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#reviewer) with the given user `id`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_username`. |
| `reviewer_username` | string | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#reviewer) with the given `username`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_id`. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14016) in GitLab 10.0)_. |
| `source_branch` | string | no | Return merge requests with the given source branch. |
| `target_branch` | string | no | Return merge requests with the given target branch. |

View File

@ -282,6 +282,7 @@ listed in the descriptions of the relevant settings.
| `first_day_of_week` | integer | no | Start day of the week for calendar views and date pickers. Valid values are `0` (default) for Sunday, `1` for Monday, and `6` for Saturday. |
| `geo_node_allowed_ips` | string | yes | **(PREMIUM)** Comma-separated list of IPs and CIDRs of allowed secondary nodes. For example, `1.1.1.1, 2.2.2.0/24`. |
| `geo_status_timeout` | integer | no | **(PREMIUM)** The amount of seconds after which a request to get a secondary node status times out. |
| `git_two_factor_session_expiry` | integer | no | **(PREMIUM)** Maximum duration (in minutes) of a session for Git operations when 2FA is enabled. |
| `gitaly_timeout_default` | integer | no | Default Gitaly timeout, in seconds. This timeout is not enforced for Git fetch/push operations or Sidekiq jobs. Set to `0` to disable timeouts. |
| `gitaly_timeout_fast` | integer | no | Gitaly fast operation timeout, in seconds. Some Gitaly operations are expected to be fast. If they exceed this threshold, there may be a problem with a storage shard and 'failing fast' can help maintain the stability of the GitLab instance. Set to `0` to disable timeouts. |
| `gitaly_timeout_medium` | integer | no | Medium Gitaly timeout, in seconds. This should be a value between the Fast and the Default timeout. Set to `0` to disable timeouts. |

View File

@ -0,0 +1,219 @@
---
stage: none
group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Design Anti-patterns
Anti-patterns may seem like good approaches at first, but it has been shown that they bring more ills than benefits. These should
generally be avoided.
Throughout the GitLab codebase, there may be historic uses of these anti-patterns. Please [use descretion](https://about.gitlab.com/handbook/engineering/#balance-refactoring-and-velocity)
when figuring out whether or not to refactor, when touching code that uses one of these legacy patterns.
**Please note:** For new features, anti-patterns are not necessarily prohibited, but it is **strongly suggested** to find another approach.
## Shared Global Object (Anti-pattern)
A shared global object is an instance of something that can be accessed from anywhere and therefore has no clear owner.
Here's an example of this pattern applied to a Vuex Store:
```javascript
const createStore = () => new Vuex.Store({
actions,
state,
mutations
});
// Notice that we are forcing all references to this module to use the same single instance of the store.
// We are also creating the store at import-time and there is nothing which can automatically dispose of it.
//
// As an alternative, we should simply export the `createStore` and let the client manage the
// lifecycle and instance of the store.
export default createStore();
```
### What problems do Shared Global Objects cause?
Shared Global Objects are convenient because they can be accessed from anywhere. However,
the convenience does not always outweigh their heavy cost:
- **No ownership.** There is no clear owner to these objects and therefore they assume a non-deterministic
and permanent lifecycle. This can be especially problematic for tests.
- **No access control.** When Shared Global Objects manage some state, this can create some very buggy and difficult
coupling situations because there is no access control to this object.
- **Possible circular references.** Shared Global Objects can also create some circular referencing situations since submodules
of the Shared Global Object can reference modules that reference itself (see
[this MR for an example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33366)).
Here are some historic examples where this pattern was identified to be problematic:
- [Reference to global Vuex store in IDE](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36401)
- [Docs update to discourage singleton Vuex store](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36952)
### When could the Shared Global Object pattern be actually appropriate?
Shared Global Object's solve the problem of making something globally accessible. This pattern
could be appropriate:
- When a responsibility is truly global and should be referenced across the application
(e.g., an application-wide Event Bus).
Even in these scenarios, please consider avoiding the Shared Global Object pattern because the
side-effects can be notoriously difficult to reason with.
### References
To read more on this topic, check out the following references:
- [GlobalVariablesAreBad from C2 wiki](https://wiki.c2.com/?GlobalVariablesAreBad)
## Singleton (Anti-pattern)
The classic [Singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern) is an approach to ensure that only one
instance of a thing exists.
Here's an example of this pattern:
```javascript
class MyThing {
constructor() {
// ...
}
// ...
}
MyThing.instance = null;
export const getThingInstance = () => {
if (MyThing.instance) {
return MyThing.instance;
}
const instance = new MyThing();
MyThing.instance = instance;
return instance;
};
```
### What problems do Singletons cause?
It is a big assumption that only one instance of a thing should exist. More often than not,
a Singleton is misused and causes very tight coupling amongst itself and the modules that reference it.
Here are some historic examples where this pattern was identified to be problematic:
- [Test issues caused by singleton class in IDE](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30398#note_331174190)
- [Implicit Singleton created by module's shared variables](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/97#note_417515776)
- [Complexity caused by Singletons](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29461#note_324585814)
Here are some ills that Singletons often produce:
1. **Non-deterministic tests.** Singletons encourage non-deterministic tests because the single instance is shared across
individual tests, often causing the state of one test to bleed into another.
1. **High coupling.** Under the hood, clients of a singleton class all share a single specific
instance of an object, which means this pattern inherits all the [problems of Shared Global Object](#what-problems-do-shared-global-objects-cause)
such as no clear ownership and no access control. These leads to high coupling situations that can
be buggy and difficult to untangle.
1. **Infectious.** Singletons are infectious, especially when they manage state. Consider the component
[RepoEditor](https://gitlab.com/gitlab-org/gitlab/blob/27ad6cb7b76430fbcbaf850df68c338d6719ed2b/app%2Fassets%2Fjavascripts%2Fide%2Fcomponents%2Frepo_editor.vue#L0-1)
used in the Web IDE. This component interfaces with a Singleton [Editor](https://gitlab.com/gitlab-org/gitlab/blob/862ad57c44ec758ef3942ac2e7a2bd40a37a9c59/app%2Fassets%2Fjavascripts%2Fide%2Flib%2Feditor.js#L21)
which manages some state for working with Monaco. Because of the Singleton nature of the Editor class,
the component `RepoEditor` is now forced to be a Singleton as well. Multiple instances of this component
would cause production issues because no one truly owns the instance of `Editor`.
### Why is the Singleton pattern popular in other languages like Java?
This is because of the limitations of languages like Java where everything has to be wrapped
in a class. In JavaScript we have things like object and function literals where we can solve
many problems with a module that simply exports utility functions.
### When could the Singleton pattern be actually appropriate?**
Singletons solve the problem of enforcing there to be only 1 instance of a thing. It's possible
that a Singleton could be appropriate in the following rare cases:
- We need to manage some resource that **MUST** have just 1 instance (i.e. some hardware restriction).
- There is a real [cross-cutting concern](https://en.wikipedia.org/wiki/Cross-cutting_concern) (e.g., logging) and a Singleton provides the simplest API.
Even in these scenarios, please consider avoiding the Singleton pattern.
### What alternatives are there to the Singleton pattern?
#### Utility Functions
When no state needs to be managed, we can simply export utility functions from a module without
messing with any class instantiation.
```javascript
// bad - Singleton
export class ThingUtils {
static create() {
if(this.instance) {
return this.instance;
}
this.instance = new ThingUtils();
return this.instance;
}
bar() { /* ... */ }
fuzzify(id) { /* ... */ }
}
// good - Utility functions
export const bar = () => { /* ... */ };
export const fuzzify = (id) => { /* ... */ };
```
#### Dependency Injection
[Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) is an approach which breaks
coupling by declaring a module's dependencies to be injected from outside the module (e.g., through constructor parameters, a bon-a-fide Dependency Injection framework, and even Vue's `provide/inject`).
```javascript
// bad - Vue component coupled to Singleton
export default {
created() {
this.mediator = MyFooMediator.getInstance();
},
};
// good - Vue component declares dependency
export default {
inject: ['mediator']
};
```
```javascript
// bad - We're not sure where the singleton is in it's lifecycle so we init it here.
export class Foo {
constructor() {
Bar.getInstance().init();
}
stuff() {
return Bar.getInstance().doStuff();
}
}
// good - Lets receive this dependency as a constructor argument.
// It's also not our responsibility to manage the lifecycle.
export class Foo {
constructor(bar) {
this.bar = bar;
}
stuff() {
return this.bar.doStuff();
}
}
```
In this example, the lifecycle and implementation details of `mediator` are all managed
**outside** the component (most likely the page entrypoint).

View File

@ -6,79 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Design Patterns
## Singletons
The following design patterns are suggested approaches for solving common problems. Use discretion when evaluating
if a certain pattern makes sense in your situation. Just because it is a pattern, doesn't mean it is a good one for your problem.
When exactly one object is needed for a given task, prefer to define it as a
`class` rather than as an object literal. Prefer also to explicitly restrict
instantiation, unless flexibility is important (such as for testing).
**Please note:** When adding a design pattern to this document, be sure to clearly state the **problem it solves**.
```javascript
// bad
## TBD
const MyThing = {
prop1: 'hello',
method1: () => {}
};
export default MyThing;
// good
class MyThing {
constructor() {
this.prop1 = 'hello';
}
method1() {}
}
export default new MyThing();
// best
export default class MyThing {
constructor() {
if (!MyThing.prototype.singleton) {
this.init();
MyThing.prototype.singleton = this;
}
return MyThing.prototype.singleton;
}
init() {
this.prop1 = 'hello';
}
method1() {}
}
```
## Manipulating the DOM in a JS Class
When writing a class that needs to manipulate the DOM guarantee a container option is provided.
This can be used when we need that class to be instantiated more than once in the same page.
Bad:
```javascript
class Foo {
constructor() {
document.querySelector('.bar');
}
}
new Foo();
```
Good:
```javascript
class Foo {
constructor(opts) {
document.querySelector(`${opts.container} .bar`);
}
}
new Foo({ container: '.my-element' });
```
You can find an example of the above in this [class](https://gitlab.com/gitlab-org/gitlab/blob/master/app/assets/javascripts/mini_pipeline_graph_dropdown.js);
Stay tuned!

View File

@ -56,7 +56,11 @@ Reusable components with technical and usage guidelines can be found in our
## Design Patterns
Common JavaScript [design patterns](design_patterns.md) in the GitLab codebase.
JavaScript [design patterns](design_patterns.md) in the GitLab codebase.
## Design Anti-patterns
JavaScript [design anti-patterns](design_anti_patterns.md) we try to avoid.
## Vue.js Best Practices

View File

@ -131,6 +131,23 @@ add the line below to `/etc/gitlab/gitlab.rb` before increasing the max attachme
nginx['client_max_body_size'] = "200m"
```
## Customize session duration for Git Operations when 2FA is enabled **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/296669) in GitLab 13.9.
> - It's deployed behind a feature flag, disabled by default.
> - It's disabled on GitLab.com.
> - It's not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](../../../security/two_factor_authentication.md#enable-or-disable-two-factor-authentication-2fa-for-git-operations)
GitLab administrators can choose to customize the session duration (in minutes) for Git operations when 2FA is enabled. The default is 15 and this can be set to a value between 1 and 10080.
To set a limit on how long these sessions are valid:
1. Navigate to **Admin Area > Settings > General**.
1. Expand the **Account and limit** section.
1. Fill in the **Session duration for Git operations when 2FA is enabled (minutes)** field.
1. Click **Save changes**.
## Limiting lifetime of personal access tokens **(ULTIMATE SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3649) in GitLab Ultimate 12.6.

View File

@ -115,16 +115,9 @@ It is also possible to manage multiple assignees:
### Reviewer
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216054) in GitLab 13.5.
> - It was [deployed behind a feature flag](../../../user/feature_flags.md), disabled by default.
> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49787) on GitLab 13.7.
> - It's enabled on GitLab.com.
> - It's recommended for production use.
> - It can be enabled or disabled for a single project.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-merge-request-reviewers). **(FREE SELF)**
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/245190) in GitLab 13.9.
WARNING:
This feature might not be available to you. Check the **version history** note above for details.
Requesting a code review is an important part of contributing code. However, deciding who should review
your code and asking for a review are no easy tasks. Using the "assignee" field for both authors and
reviewers makes it hard for others to determine who's doing what on a merge request.
@ -137,31 +130,6 @@ This makes it easy to determine the relevant roles for the users involved in the
To request it, open the **Reviewers** drop-down box to search for the user you wish to get a review from.
#### Enable or disable Merge Request Reviewers **(FREE SELF)**
Merge Request Reviewers is under development but ready for production use.
It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can opt to disable it.
To enable it:
```ruby
# For the instance
Feature.enable(:merge_request_reviewers)
# For a single project
Feature.enable(:merge_request_reviewers, Project.find(<project id>))
```
To disable it:
```ruby
# For the instance
Feature.disable(:merge_request_reviewers)
# For a single project
Feature.disable(:merge_request_reviewers, Project.find(<project id>))
```
#### Approval Rule information for Reviewers **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233736) in GitLab 13.8.

View File

@ -27,7 +27,7 @@ module API
expose(:downvotes) { |merge_request, options| issuable_metadata.downvotes }
expose :author, :assignees, :assignee, using: Entities::UserBasic
expose :reviewers, if: -> (merge_request, _) { merge_request.allows_reviewers? }, using: Entities::UserBasic
expose :reviewers, using: Entities::UserBasic
expose :source_project_id, :target_project_id
expose :labels do |merge_request, options|
if options[:with_labels_details]

View File

@ -5,7 +5,6 @@ module Gitlab
module Otp
class SessionEnforcer
OTP_SESSIONS_NAMESPACE = 'session:otp'
DEFAULT_EXPIRATION = 15.minutes.to_i
def initialize(key)
@key = key
@ -13,7 +12,7 @@ module Gitlab
def update_session
Gitlab::Redis::SharedState.with do |redis|
redis.setex(key_name, DEFAULT_EXPIRATION, true)
redis.setex(key_name, session_expiry_in_seconds, true)
end
end
@ -30,6 +29,10 @@ module Gitlab
def key_name
@key_name ||= "#{OTP_SESSIONS_NAMESPACE}:#{key.id}"
end
def session_expiry_in_seconds
Gitlab::CurrentSettings.git_two_factor_session_expiry.minutes.to_i
end
end
end
end

View File

@ -92,10 +92,6 @@ module Gitlab
tracking_category: 'Growth::Activation::Experiment::CiSyntaxTemplates',
rollout_strategy: :user
},
pipelines_empty_state: {
tracking_category: 'Growth::Activation::Experiment::PipelinesEmptyState',
rollout_strategy: :user
},
invite_members_new_dropdown: {
tracking_category: 'Growth::Expansion::Experiment::InviteMembersNewDropdown'
},

View File

@ -181,8 +181,7 @@ module Gitlab
end
types MergeRequest
condition do
Feature.enabled?(:merge_request_reviewers, project, default_enabled: :yaml) &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
end
parse_params do |reviewer_param|
extract_users(reviewer_param)
@ -221,7 +220,6 @@ module Gitlab
types MergeRequest
condition do
quick_action_target.persisted? &&
Feature.enabled?(:merge_request_reviewers, project, default_enabled: :yaml) &&
quick_action_target.reviewers.any? &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
desc 'Security check via brakeman'
task :brakeman do
# We get 0 warnings at level 'w3' but we would like to reach 'w2'. Merge

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :cache do
namespace :clear do
REDIS_CLEAR_BATCH_SIZE = 1000 # There seems to be no speedup when pushing beyond 1,000

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :ci do
namespace :cleanup do
desc "GitLab | CI | Clean running builds"

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :cleanup do
desc "GitLab | Cleanup | Delete moved repositories"

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
module ConfigLint
def self.run(files)
failures = files.reject do |file|

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
desc 'Show a list of obsolete `ignored_columns`'
task 'db:obsolete_ignored_columns' => :environment do
list = Gitlab::Database::ObsoleteIgnoredColumns.new.execute

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
task dev: ["dev:setup"]
namespace :dev do

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
desc 'Checks if migrations in a branch require downtime'
task downtime_check: :environment do
repo = if defined?(Gitlab::License)

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
unless Rails.env.production?
desc "GitLab | Run ESLint"
task eslint: ['yarn:check'] do

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :file_hooks do
desc 'Validate existing file hooks'
task validate: :environment do

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
unless Rails.env.production?
namespace :frontend do
desc 'GitLab | Frontend | Generate fixtures for JavaScript tests'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gemojione do
desc 'Generates Emoji SHA256 digests'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :artifacts do
desc 'GitLab | Artifacts | Check integrity of uploaded job artifacts'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'logger'
require 'resolv-replace'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'active_record/fixtures'
namespace :gitlab do

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :import do
desc "GitLab | Import | Add all users to all projects (admin users are added as maintainers)"

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
desc 'GitLab | Check the configuration of GitLab and its environment'
task check: :gitlab_environment do

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :container_registry do
desc "GitLab | Container Registry | Configure"

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :db do
desc 'GitLab | DB | Manually insert schema migration version'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :doctor do
desc "GitLab | Check if the database encrypted values can be decrypted using current secrets"

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :exclusive_lease do
desc 'GitLab | Exclusive Lease | Clear existing exclusive leases for specified scope (default: *)'

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :external_diffs do
desc "Override external diffs in file storage to be in object storage instead. This does not change the actual location of the data"

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :gitlab do
namespace :features do
desc 'GitLab | Features | Enable direct Git access via Rugged for NFS'

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