Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c59393a068
commit
0351d9ed83
|
@ -23,21 +23,6 @@ Layout/SpaceInsideParens:
|
|||
- 'ee/app/services/sitemap/create_service.rb'
|
||||
- 'ee/lib/ee/gitlab/auth/ldap/access.rb'
|
||||
- 'ee/lib/gitlab/auth/smartcard/session.rb'
|
||||
- 'ee/spec/features/account_recovery_regular_check_spec.rb'
|
||||
- 'ee/spec/features/billings/billing_plans_spec.rb'
|
||||
- 'ee/spec/features/boards/board_filters_spec.rb'
|
||||
- 'ee/spec/features/boards/group_boards/board_deletion_spec.rb'
|
||||
- 'ee/spec/features/boards/user_visits_board_spec.rb'
|
||||
- 'ee/spec/features/groups/analytics/ci_cd_analytics_spec.rb'
|
||||
- 'ee/spec/features/groups/issues_spec.rb'
|
||||
- 'ee/spec/features/groups/iteration_spec.rb'
|
||||
- 'ee/spec/features/groups/iterations/user_creates_iteration_in_cadence_spec.rb'
|
||||
- 'ee/spec/features/groups/iterations/user_edits_iteration_cadence_spec.rb'
|
||||
- 'ee/spec/features/groups/iterations/user_edits_iteration_spec.rb'
|
||||
- 'ee/spec/features/merge_request/user_edits_multiple_reviewers_mr_spec.rb'
|
||||
- 'ee/spec/features/merge_requests/user_resets_approvers_spec.rb'
|
||||
- 'ee/spec/features/merge_requests/user_views_all_merge_requests_spec.rb'
|
||||
- 'ee/spec/features/merge_trains/two_merge_requests_on_train_spec.rb'
|
||||
- 'ee/spec/finders/ee/alert_management/http_integrations_finder_spec.rb'
|
||||
- 'ee/spec/finders/epics_finder_spec.rb'
|
||||
- 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb'
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -229,7 +229,7 @@ gem 'gitlab-sidekiq-fetcher', '0.8.0', require: 'sidekiq-reliable-fetch'
|
|||
gem 'fugit', '~> 1.2.1'
|
||||
|
||||
# HTTP requests
|
||||
gem 'httparty', '~> 0.16.4'
|
||||
gem 'httparty', '~> 0.20.0'
|
||||
|
||||
# Colored output to console
|
||||
gem 'rainbow', '~> 3.0'
|
||||
|
|
|
@ -272,7 +272,7 @@
|
|||
{"name":"http-cookie","version":"1.0.5","platform":"ruby","checksum":"73756d46c7dbdc7023deecdb8a171348ea95a1b99810b31cfe8b4fb4e9a6318f"},
|
||||
{"name":"http-form_data","version":"2.3.0","platform":"ruby","checksum":"cc4eeb1361d9876821e31d7b1cf0b68f1cf874b201d27903480479d86448a5f3"},
|
||||
{"name":"http-parser","version":"1.2.3","platform":"ruby","checksum":"414dec1f443d68e1068509f184ee4b93e3442f626645071182ce49bc27db18a3"},
|
||||
{"name":"httparty","version":"0.16.4","platform":"ruby","checksum":"62c89d00f5e8933b2d397a49b57deb18ca18e16cb7d862ee4f53b73228dc3d81"},
|
||||
{"name":"httparty","version":"0.20.0","platform":"ruby","checksum":"490d2a028a5accc611f1685d479d80ef80b129140d24a93c53c119f578614867"},
|
||||
{"name":"httpclient","version":"2.8.3","platform":"ruby","checksum":"2951e4991214464c3e92107e46438527d23048e634f3aee91c719e0bdfaebda6"},
|
||||
{"name":"i18n","version":"1.12.0","platform":"ruby","checksum":"91e3cc1b97616d308707eedee413d82ee021d751c918661fb82152793e64aced"},
|
||||
{"name":"i18n_data","version":"0.8.0","platform":"ruby","checksum":"92d942cc193dc4a54a95b68f44e52c79e024fa72e09f26a982bc61153b6f0c6c"},
|
||||
|
|
|
@ -734,7 +734,7 @@ GEM
|
|||
http-form_data (2.3.0)
|
||||
http-parser (1.2.3)
|
||||
ffi-compiler (>= 1.0, < 2.0)
|
||||
httparty (0.16.4)
|
||||
httparty (0.20.0)
|
||||
mime-types (~> 3.0)
|
||||
multi_xml (>= 0.5.2)
|
||||
httpclient (2.8.3)
|
||||
|
@ -1666,7 +1666,7 @@ DEPENDENCIES
|
|||
health_check (~> 3.0)
|
||||
html-pipeline (~> 2.13.2)
|
||||
html2text
|
||||
httparty (~> 0.16.4)
|
||||
httparty (~> 0.20.0)
|
||||
icalendar
|
||||
invisible_captcha (~> 1.1.0)
|
||||
ipaddr (= 1.2.2)
|
||||
|
|
|
@ -112,21 +112,21 @@ export default {
|
|||
>
|
||||
<div class="table-section section-20 section-wrap">
|
||||
<div role="rowheader" class="table-mobile-header">{{ __('Suite') }}</div>
|
||||
<div class="table-mobile-content gl-md-pr-2 gl-overflow-wrap-break">
|
||||
<div class="table-mobile-content gl-pr-0 gl-sm-pr-2 gl-overflow-wrap-break">
|
||||
<gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.classname" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-section section-40 section-wrap">
|
||||
<div role="rowheader" class="table-mobile-header">{{ __('Name') }}</div>
|
||||
<div class="table-mobile-content gl-md-pr-2 gl-overflow-wrap-break">
|
||||
<div class="table-mobile-content gl-pr-0 gl-sm-pr-2 gl-overflow-wrap-break">
|
||||
<gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.name" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-section section-10 section-wrap">
|
||||
<div role="rowheader" class="table-mobile-header">{{ __('Filename') }}</div>
|
||||
<div class="table-mobile-content gl-md-pr-2 gl-overflow-wrap-break">
|
||||
<div class="table-mobile-content gl-pr-0 gl-sm-pr-2 gl-overflow-wrap-break">
|
||||
<gl-link v-if="testCase.file" :href="testCase.filePath" target="_blank">
|
||||
<gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.file" />
|
||||
</gl-link>
|
||||
|
@ -156,7 +156,7 @@ export default {
|
|||
<div role="rowheader" class="table-mobile-header">
|
||||
{{ __('Duration') }}
|
||||
</div>
|
||||
<div class="table-mobile-content gl-sm-pr-2">
|
||||
<div class="table-mobile-content gl-pr-0 gl-sm-pr-2">
|
||||
{{ testCase.formattedTime }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -170,7 +170,7 @@ export default {
|
|||
this.$emit('closeForm');
|
||||
},
|
||||
openDatePicker() {
|
||||
this.$refs.datePicker.calendar.show();
|
||||
this.$refs.datePicker.show();
|
||||
},
|
||||
setFixedDate(isFixed) {
|
||||
const date = this.issuable[dateFields[this.dateType].dateFixed];
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
export const AJAX_USERS_SELECT_OPTIONS_MAP = {
|
||||
projectId: 'projectId',
|
||||
groupId: 'groupId',
|
||||
showCurrentUser: 'currentUser',
|
||||
authorId: 'authorId',
|
||||
skipUsers: 'skipUsers',
|
||||
};
|
||||
|
||||
export const AJAX_USERS_SELECT_PARAMS_MAP = {
|
||||
project_id: 'projectId',
|
||||
group_id: 'groupId',
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
/* eslint-disable func-names, prefer-rest-params, consistent-return, no-shadow, no-self-compare, no-unused-expressions, yoda, prefer-spread, camelcase, no-param-reassign */
|
||||
/* eslint-disable func-names, consistent-return, no-shadow, no-self-compare, no-unused-expressions, camelcase, no-param-reassign */
|
||||
/* global Issuable */
|
||||
/* global emitSidebarEvent */
|
||||
|
||||
import $ from 'jquery';
|
||||
import { escape, template, uniqBy } from 'lodash';
|
||||
import {
|
||||
AJAX_USERS_SELECT_OPTIONS_MAP,
|
||||
AJAX_USERS_SELECT_PARAMS_MAP,
|
||||
} from 'ee_else_ce/users_select/constants';
|
||||
import { AJAX_USERS_SELECT_PARAMS_MAP } from 'ee_else_ce/users_select/constants';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
import { isUserBusy } from '~/set_status_modal/utils';
|
||||
import { fixTitle, dispose } from '~/tooltips';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { parseBoolean, spriteIcon } from '~/lib/utils/common_utils';
|
||||
import { loadCSSFile } from '~/lib/utils/css_utils';
|
||||
import { s__, __, sprintf } from '~/locale';
|
||||
import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from './utils';
|
||||
import { getAjaxUsersSelectParams } from './utils';
|
||||
|
||||
// TODO: remove eventHub hack after code splitting refactor
|
||||
window.emitSidebarEvent = window.emitSidebarEvent || $.noop;
|
||||
|
@ -24,9 +20,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
const elsClassName = els?.toString().match('.(.+$)')[1];
|
||||
const $els = $(els || '.js-user-search');
|
||||
this.users = this.users.bind(this);
|
||||
this.user = this.user.bind(this);
|
||||
this.usersPath = '/-/autocomplete/users.json';
|
||||
this.userPath = '/-/autocomplete/users/:id.json';
|
||||
if (currentUser != null) {
|
||||
if (typeof currentUser === 'object') {
|
||||
this.currentUser = currentUser;
|
||||
|
@ -36,7 +30,6 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
}
|
||||
|
||||
const { handleClick } = options;
|
||||
const userSelect = this;
|
||||
|
||||
$els.each((i, dropdown) => {
|
||||
const userSelect = this;
|
||||
|
@ -619,156 +612,8 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
if ($('.ajax-users-select').length) {
|
||||
import(/* webpackChunkName: 'select2' */ 'select2/select2')
|
||||
.then(() => {
|
||||
// eslint-disable-next-line promise/no-nesting
|
||||
loadCSSFile(gon.select2_css_path)
|
||||
.then(() => {
|
||||
$('.ajax-users-select').each((i, select) => {
|
||||
const options = getAjaxUsersSelectOptions($(select), AJAX_USERS_SELECT_OPTIONS_MAP);
|
||||
options.skipLdap = $(select).hasClass('skip_ldap');
|
||||
const showNullUser = $(select).data('nullUser');
|
||||
const showAnyUser = $(select).data('anyUser');
|
||||
const showEmailUser = $(select).data('emailUser');
|
||||
const firstUser = $(select).data('firstUser');
|
||||
return $(select).select2({
|
||||
placeholder: __('Search for a user'),
|
||||
multiple: $(select).hasClass('multiselect'),
|
||||
minimumInputLength: 0,
|
||||
query(query) {
|
||||
return userSelect.users(query.term, options, (users) => {
|
||||
let name;
|
||||
const data = {
|
||||
results: users,
|
||||
};
|
||||
if (query.term.length === 0) {
|
||||
if (firstUser) {
|
||||
// Move current user to the front of the list
|
||||
const ref = data.results;
|
||||
|
||||
for (let index = 0, len = ref.length; index < len; index += 1) {
|
||||
const obj = ref[index];
|
||||
if (obj.username === firstUser) {
|
||||
data.results.splice(index, 1);
|
||||
data.results.unshift(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (showNullUser) {
|
||||
const nullUser = {
|
||||
name: s__('UsersSelect|Unassigned'),
|
||||
id: 0,
|
||||
};
|
||||
data.results.unshift(nullUser);
|
||||
}
|
||||
if (showAnyUser) {
|
||||
name = showAnyUser;
|
||||
if (name === true) {
|
||||
name = s__('UsersSelect|Any User');
|
||||
}
|
||||
const anyUser = {
|
||||
name,
|
||||
id: null,
|
||||
};
|
||||
data.results.unshift(anyUser);
|
||||
}
|
||||
}
|
||||
if (
|
||||
showEmailUser &&
|
||||
data.results.length === 0 &&
|
||||
query.term.match(/^[^@]+@[^@]+$/)
|
||||
) {
|
||||
const trimmed = query.term.trim();
|
||||
const emailUser = {
|
||||
name: sprintf(__('Invite "%{trimmed}" by email'), { trimmed }),
|
||||
username: trimmed,
|
||||
id: trimmed,
|
||||
invite: true,
|
||||
};
|
||||
data.results.unshift(emailUser);
|
||||
}
|
||||
return query.callback(data);
|
||||
});
|
||||
},
|
||||
initSelection() {
|
||||
const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
|
||||
return userSelect.initSelection.apply(userSelect, args);
|
||||
},
|
||||
formatResult() {
|
||||
const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
|
||||
return userSelect.formatResult.apply(userSelect, args);
|
||||
},
|
||||
formatSelection() {
|
||||
const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
|
||||
return userSelect.formatSelection.apply(userSelect, args);
|
||||
},
|
||||
dropdownCssClass: 'ajax-users-dropdown',
|
||||
// we do not want to escape markup since we are displaying html in results
|
||||
escapeMarkup(m) {
|
||||
return m;
|
||||
},
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
UsersSelect.prototype.initSelection = function (element, callback) {
|
||||
const id = $(element).val();
|
||||
if (id === '0') {
|
||||
const nullUser = {
|
||||
name: s__('UsersSelect|Unassigned'),
|
||||
};
|
||||
return callback(nullUser);
|
||||
} else if (id !== '') {
|
||||
return this.user(id, callback);
|
||||
}
|
||||
};
|
||||
|
||||
UsersSelect.prototype.formatResult = function (user) {
|
||||
let avatar = gon.default_avatar_url;
|
||||
if (user.avatar_url) {
|
||||
avatar = user.avatar_url;
|
||||
}
|
||||
return `
|
||||
<div class='user-result'>
|
||||
<div class='user-image'>
|
||||
<img class='avatar avatar-inline s32' src='${avatar}'>
|
||||
</div>
|
||||
<div class='user-info'>
|
||||
<div class='user-name dropdown-menu-user-full-name'>
|
||||
${escape(user.name)}
|
||||
</div>
|
||||
<div class='user-username dropdown-menu-user-username text-secondary'>
|
||||
${!user.invite ? `@${escape(user.username)}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
UsersSelect.prototype.formatSelection = function (user) {
|
||||
return escape(user.name);
|
||||
};
|
||||
|
||||
UsersSelect.prototype.user = function (user_id, callback) {
|
||||
if (!/^\d+$/.test(user_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let url = this.buildUrl(this.userPath);
|
||||
url = url.replace(':id', user_id);
|
||||
return axios.get(url).then(({ data }) => {
|
||||
callback(data);
|
||||
});
|
||||
};
|
||||
|
||||
// Return users list. Filtered by query
|
||||
// Only active users retrieved
|
||||
UsersSelect.prototype.users = function (query, options, callback) {
|
||||
|
|
|
@ -1,17 +1,3 @@
|
|||
/**
|
||||
* Get options from data attributes on passed `$select`.
|
||||
* @param {jQuery} $select
|
||||
* @param {Object} optionsMap e.g. { optionKeyName: 'dataAttributeName' }
|
||||
*/
|
||||
export const getAjaxUsersSelectOptions = ($select, optionsMap) => {
|
||||
return Object.keys(optionsMap).reduce((accumulator, optionKey) => {
|
||||
const dataKey = optionsMap[optionKey];
|
||||
accumulator[optionKey] = $select.data(dataKey);
|
||||
|
||||
return accumulator;
|
||||
}, {});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get query parameters used for users request from passed `options` parameter
|
||||
* @param {Object} options e.g. { currentUserId: 1, fooBar: 'baz' }
|
||||
|
|
|
@ -538,13 +538,15 @@ export default {
|
|||
<div class="media-body">
|
||||
<div class="mr-widget-body-controls gl-display-flex gl-align-items-center gl-flex-wrap">
|
||||
<template v-if="shouldShowMergeControls">
|
||||
<div class="gl-display-flex gl-align-items-center gl-flex-wrap gl-w-full gl-mb-5">
|
||||
<div
|
||||
class="gl-display-flex gl-sm-flex-direction-column gl-md-align-items-center gl-flex-wrap gl-w-full gl-md-pb-5"
|
||||
>
|
||||
<gl-form-checkbox
|
||||
v-if="canRemoveSourceBranch"
|
||||
id="remove-source-branch-input"
|
||||
v-model="removeSourceBranch"
|
||||
:disabled="isRemoveSourceBranchButtonDisabled"
|
||||
class="js-remove-source-branch-checkbox gl-display-flex gl-align-items-center gl-mr-5"
|
||||
class="js-remove-source-branch-checkbox gl-display-flex gl-align-items-center gl-mr-5 gl-mb-3 gl-md-mb-0"
|
||||
>
|
||||
{{ __('Delete source branch') }}
|
||||
</gl-form-checkbox>
|
||||
|
@ -555,37 +557,18 @@ export default {
|
|||
v-model="squashBeforeMerge"
|
||||
:help-path="mr.squashBeforeMergeHelpPath"
|
||||
:is-disabled="isSquashReadOnly"
|
||||
class="gl-mr-5"
|
||||
class="gl-mr-5 gl-mb-3 gl-md-mb-0"
|
||||
/>
|
||||
|
||||
<gl-form-checkbox
|
||||
v-if="shouldShowSquashEdit || shouldShowMergeEdit"
|
||||
v-model="editCommitMessage"
|
||||
data-testid="widget_edit_commit_message"
|
||||
class="gl-display-flex gl-align-items-center"
|
||||
class="gl-display-flex gl-align-items-center gl-mb-3 gl-md-mb-0"
|
||||
>
|
||||
{{ __('Edit commit message') }}
|
||||
</gl-form-checkbox>
|
||||
</div>
|
||||
<div class="gl-w-full gl-text-gray-500 gl-mb-5">
|
||||
<added-commit-message
|
||||
:is-squash-enabled="squashBeforeMerge"
|
||||
:is-fast-forward-enabled="!shouldShowMergeEdit"
|
||||
:commits-count="commitsCount"
|
||||
:target-branch="stateData.targetBranch"
|
||||
/>
|
||||
<template v-if="mr.relatedLinks">
|
||||
·
|
||||
<related-links
|
||||
:state="mr.state"
|
||||
:related-links="mr.relatedLinks"
|
||||
:show-assign-to-me="false"
|
||||
:diverged-commits-count="mr.divergedCommitsCount"
|
||||
:target-branch-path="mr.targetBranchPath"
|
||||
class="mr-ready-merge-related-links gl-display-inline"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="editCommitMessage" class="gl-w-full" data-testid="edit_commit_message">
|
||||
<ul class="border-top commits-list flex-list gl-list-style-none gl-p-0 gl-pt-4">
|
||||
<commit-edit
|
||||
|
@ -625,6 +608,25 @@ export default {
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="gl-w-full gl-text-gray-500 gl-mb-3 gl-md-mb-0 gl-md-pb-5">
|
||||
<added-commit-message
|
||||
:is-squash-enabled="squashBeforeMerge"
|
||||
:is-fast-forward-enabled="!shouldShowMergeEdit"
|
||||
:commits-count="commitsCount"
|
||||
:target-branch="stateData.targetBranch"
|
||||
/>
|
||||
<template v-if="mr.relatedLinks">
|
||||
·
|
||||
<related-links
|
||||
:state="mr.state"
|
||||
:related-links="mr.relatedLinks"
|
||||
:show-assign-to-me="false"
|
||||
:diverged-commits-count="mr.divergedCommitsCount"
|
||||
:target-branch-path="mr.targetBranchPath"
|
||||
class="mr-ready-merge-related-links gl-display-inline"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<gl-button-group class="gl-align-self-start">
|
||||
<gl-button
|
||||
size="medium"
|
||||
|
|
|
@ -134,12 +134,12 @@ export default {
|
|||
async clickShowDueDate() {
|
||||
this.showDueDateInput = true;
|
||||
await this.$nextTick();
|
||||
this.$refs.dueDatePicker.calendar.show();
|
||||
this.$refs.dueDatePicker.show();
|
||||
},
|
||||
async clickShowStartDate() {
|
||||
this.showStartDateInput = true;
|
||||
await this.$nextTick();
|
||||
this.$refs.startDatePicker.calendar.show();
|
||||
this.$refs.startDatePicker.show();
|
||||
},
|
||||
handleStartDateInput() {
|
||||
if (this.dirtyDueDate && this.dirtyStartDate > this.dirtyDueDate) {
|
||||
|
|
|
@ -1,15 +1,3 @@
|
|||
.ajax-users-select {
|
||||
width: 400px;
|
||||
|
||||
&.input-large {
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
&.input-clamp {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.group-result {
|
||||
.group-image {
|
||||
float: left;
|
||||
|
@ -49,7 +37,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ajax-users-dropdown {
|
||||
min-width: 250px !important;
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
format.json do
|
||||
Gitlab::UsageDataCounters::ServiceUsageDataCounter.count(:download_payload_click)
|
||||
|
||||
render json: service_ping_data.to_json
|
||||
render json: Gitlab::Json.dump(service_ping_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -137,7 +137,7 @@ module AuthenticatesWithTwoFactor
|
|||
|
||||
session[:credentialRequestOptions] = get_options
|
||||
session[:challenge] = get_options.challenge
|
||||
gon.push(webauthn: { options: get_options.to_json })
|
||||
gon.push(webauthn: { options: Gitlab::Json.dump(get_options) })
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
|
@ -86,7 +86,7 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: @merge_requests.to_json
|
||||
render json: Gitlab::Json.dump(@merge_requests)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ module Projects
|
|||
gcpRegions: gcp_regions,
|
||||
revokeOauthUrl: revoke_oauth_url
|
||||
}
|
||||
@js_data = js_data.to_json
|
||||
@js_data = Gitlab::Json.dump(js_data)
|
||||
track_event(:render_page)
|
||||
end
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ module Projects
|
|||
cloudsqlInstances: ::GoogleCloud::GetCloudsqlInstancesService.new(project).execute,
|
||||
emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg')
|
||||
}
|
||||
@js_data = js_data.to_json
|
||||
|
||||
@js_data = Gitlab::Json.dump(js_data)
|
||||
|
||||
track_event(:render_page)
|
||||
end
|
||||
|
@ -27,7 +28,7 @@ module Projects
|
|||
|
||||
@title = title(product)
|
||||
|
||||
@js_data = {
|
||||
js_data = {
|
||||
gcpProjects: gcp_projects,
|
||||
refs: refs,
|
||||
cancelPath: project_google_cloud_databases_path(project),
|
||||
|
@ -35,7 +36,9 @@ module Projects
|
|||
formDescription: description(product),
|
||||
databaseVersions: Projects::GoogleCloud::CloudsqlHelper::VERSIONS[product],
|
||||
tiers: Projects::GoogleCloud::CloudsqlHelper::TIERS
|
||||
}.to_json
|
||||
}
|
||||
|
||||
@js_data = Gitlab::Json.dump(js_data)
|
||||
|
||||
track_event(:render_form)
|
||||
render template: 'projects/google_cloud/databases/cloudsql_form', formats: :html
|
||||
|
|
|
@ -11,7 +11,7 @@ class Projects::GoogleCloud::DeploymentsController < Projects::GoogleCloud::Base
|
|||
enableCloudRunUrl: project_google_cloud_deployments_cloud_run_path(project),
|
||||
enableCloudStorageUrl: project_google_cloud_deployments_cloud_storage_path(project)
|
||||
}
|
||||
@js_data = js_data.to_json
|
||||
@js_data = Gitlab::Json.dump(js_data)
|
||||
track_event(:render_page)
|
||||
end
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class Projects::GoogleCloud::GcpRegionsController < Projects::GoogleCloud::BaseC
|
|||
refs: refs,
|
||||
cancelPath: project_google_cloud_configuration_path(project)
|
||||
}
|
||||
@js_data = js_data.to_json
|
||||
@js_data = Gitlab::Json.dump(js_data)
|
||||
track_event(:render_form)
|
||||
end
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud::
|
|||
refs: refs,
|
||||
cancelPath: project_google_cloud_configuration_path(project)
|
||||
}
|
||||
@js_data = js_data.to_json
|
||||
@js_data = Gitlab::Json.dump(js_data)
|
||||
|
||||
track_event(:render_form)
|
||||
end
|
||||
|
|
|
@ -104,7 +104,7 @@ class Projects::GraphsController < Projects::ApplicationController
|
|||
}
|
||||
end
|
||||
|
||||
render json: @log.to_json
|
||||
render json: Gitlab::Json.dump(@log)
|
||||
end
|
||||
|
||||
def tracking_namespace_source
|
||||
|
|
|
@ -124,7 +124,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
@commits_count = @merge_request.commits_count + @merge_request.context_commits_count
|
||||
@diffs_count = get_diffs_count
|
||||
@issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
|
||||
@current_user_data = UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestCurrentUserEntity).to_json
|
||||
@current_user_data = Gitlab::Json.dump(UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestCurrentUserEntity))
|
||||
@show_whitespace_default = current_user.nil? || current_user.show_whitespace_in_diffs
|
||||
@file_by_file_default = current_user&.view_diffs_file_by_file
|
||||
@coverage_path = coverage_reports_project_merge_request_path(@project, @merge_request, format: :json) if @merge_request.has_coverage_reports?
|
||||
|
@ -536,7 +536,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
|
||||
render json: '', status: :no_content
|
||||
when :parsed
|
||||
render json: report_comparison[:data].to_json, status: :ok
|
||||
render json: Gitlab::Json.dump(report_comparison[:data]), status: :ok
|
||||
when :error
|
||||
render json: { status_reason: report_comparison[:status_reason] }, status: :bad_request
|
||||
else
|
||||
|
|
|
@ -58,7 +58,7 @@ class Projects::NotesController < Projects::ApplicationController
|
|||
|
||||
def outdated_line_change
|
||||
diff_lines = Rails.cache.fetch(['note', note.id, 'oudated_line_change'], expires_in: 7.days) do
|
||||
::MergeRequests::OutdatedDiscussionDiffLinesService.new(project: note.noteable.source_project, note: note).execute.to_json
|
||||
Gitlab::Json.dump(::MergeRequests::OutdatedDiscussionDiffLinesService.new(project: note.noteable.source_project, note: note).execute)
|
||||
end
|
||||
|
||||
render json: diff_lines
|
||||
|
|
|
@ -23,9 +23,11 @@ module Projects
|
|||
|
||||
def show
|
||||
if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project)
|
||||
@triggers_json = ::Ci::TriggerSerializer.new.represent(
|
||||
triggers = ::Ci::TriggerSerializer.new.represent(
|
||||
@project.triggers, current_user: current_user, project: @project
|
||||
).to_json
|
||||
)
|
||||
|
||||
@triggers_json = Gitlab::Json.dump(triggers)
|
||||
end
|
||||
|
||||
render
|
||||
|
|
|
@ -12,7 +12,7 @@ class Projects::TemplatesController < Projects::ApplicationController
|
|||
templates = @template_type.template_subsets(project)
|
||||
|
||||
respond_to do |format|
|
||||
format.json { render json: templates.to_json }
|
||||
format.json { render json: Gitlab::Json.dump(templates) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -20,7 +20,7 @@ class Projects::TemplatesController < Projects::ApplicationController
|
|||
template = @template_type.find(params[:key], project)
|
||||
|
||||
respond_to do |format|
|
||||
format.json { render json: template.to_json }
|
||||
format.json { render json: Gitlab::Json.dump(template) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -343,7 +343,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
options['Commits'] = [ref]
|
||||
end
|
||||
|
||||
render json: options.to_json
|
||||
render json: Gitlab::Json.dump(options)
|
||||
rescue Gitlab::Git::CommandError
|
||||
render json: { error: _('Unable to load refs') }, status: :service_unavailable
|
||||
end
|
||||
|
|
|
@ -108,7 +108,7 @@ class SearchController < ApplicationController
|
|||
@ref = params[:project_ref] if params[:project_ref].present?
|
||||
@filter = params[:filter]
|
||||
|
||||
render json: search_autocomplete_opts(term, filter: @filter).to_json
|
||||
render json: Gitlab::Json.dump(search_autocomplete_opts(term, filter: @filter))
|
||||
end
|
||||
|
||||
def opensearch
|
||||
|
|
|
@ -5,10 +5,6 @@ module Groups::GroupMembersHelper
|
|||
|
||||
AVATAR_SIZE = 40
|
||||
|
||||
def group_member_select_options
|
||||
{ multiple: true, class: 'input-clamp qa-member-select-field ', scope: :all, email_user: true }
|
||||
end
|
||||
|
||||
def group_members_app_data(group, members:, invited:, access_requests:, banned:, include_relations:, search:)
|
||||
{
|
||||
user: group_members_list_data(group, members, { param_name: :page, params: { invited_members_page: nil, search_invited: nil } }),
|
||||
|
|
|
@ -1,30 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SelectsHelper
|
||||
def users_select_tag(id, opts = {})
|
||||
css_class = ["ajax-users-select"]
|
||||
css_class << "multiselect" if opts[:multiple]
|
||||
css_class << "skip_ldap" if opts[:skip_ldap]
|
||||
css_class << (opts[:class] || '')
|
||||
value = opts[:selected] || ''
|
||||
html = {
|
||||
class: css_class.join(' '),
|
||||
data: users_select_data_attributes(opts)
|
||||
}
|
||||
|
||||
unless opts[:scope] == :all
|
||||
project = opts[:project] || @project
|
||||
|
||||
if project
|
||||
html['data-project-id'] = project.id
|
||||
elsif @group
|
||||
html['data-group-id'] = @group.id
|
||||
end
|
||||
end
|
||||
|
||||
hidden_field_tag(id, value, html)
|
||||
end
|
||||
|
||||
def groups_select_tag(id, opts = {})
|
||||
classes = Array.wrap(opts[:class])
|
||||
classes << 'ajax-groups-select'
|
||||
|
@ -68,22 +44,6 @@ module SelectsHelper
|
|||
|
||||
hidden_field_tag(id, value, opts)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def users_select_data_attributes(opts)
|
||||
{
|
||||
placeholder: opts[:placeholder] || 'Search for a user',
|
||||
null_user: opts[:null_user] || false,
|
||||
any_user: opts[:any_user] || false,
|
||||
email_user: opts[:email_user] || false,
|
||||
first_user: opts[:first_user] && current_user ? current_user.username : false,
|
||||
current_user: opts[:current_user] || false,
|
||||
author_id: opts[:author_id] || '',
|
||||
skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil,
|
||||
qa_selector: opts[:qa_selector] || ''
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
SelectsHelper.prepend_mod_with('SelectsHelper')
|
||||
|
|
|
@ -183,7 +183,7 @@ module Ci
|
|||
false
|
||||
end
|
||||
|
||||
def prevent_rollback_deployment?
|
||||
def outdated_deployment?
|
||||
false
|
||||
end
|
||||
|
||||
|
|
|
@ -445,9 +445,10 @@ module Ci
|
|||
manual? && starts_environment? && deployment&.blocked?
|
||||
end
|
||||
|
||||
def prevent_rollback_deployment?
|
||||
strong_memoize(:prevent_rollback_deployment) do
|
||||
def outdated_deployment?
|
||||
strong_memoize(:outdated_deployment) do
|
||||
starts_environment? &&
|
||||
incomplete? &&
|
||||
project.ci_forward_deployment_enabled? &&
|
||||
deployment&.older_than_last_successful_deployment?
|
||||
end
|
||||
|
|
|
@ -110,6 +110,10 @@ module Ci
|
|||
COMPLETED_STATUSES.include?(status)
|
||||
end
|
||||
|
||||
def incomplete?
|
||||
COMPLETED_STATUSES.exclude?(status)
|
||||
end
|
||||
|
||||
def blocked?
|
||||
BLOCKED_STATUS.include?(status)
|
||||
end
|
||||
|
|
|
@ -27,8 +27,8 @@ module Ci
|
|||
false
|
||||
end
|
||||
|
||||
condition(:prevent_rollback) do
|
||||
@subject.prevent_rollback_deployment?
|
||||
condition(:outdated_deployment) do
|
||||
@subject.outdated_deployment?
|
||||
end
|
||||
|
||||
condition(:owner_of_job) do
|
||||
|
@ -77,12 +77,14 @@ module Ci
|
|||
# Authorizing the user to access to protected entities.
|
||||
# There is a "jailbreak" mode to exceptionally bypass the authorization,
|
||||
# however, you should NEVER allow it, rather suspect it's a wrong feature/product design.
|
||||
rule { ~can?(:jailbreak) & (archived | protected_ref | protected_environment | prevent_rollback) }.policy do
|
||||
rule { ~can?(:jailbreak) & (archived | protected_ref | protected_environment) }.policy do
|
||||
prevent :update_build
|
||||
prevent :update_commit_status
|
||||
prevent :erase_build
|
||||
end
|
||||
|
||||
rule { outdated_deployment }.prevent :update_build
|
||||
|
||||
rule { can?(:admin_build) | (can?(:update_build) & owner_of_job & unprotected_ref) }.enable :erase_build
|
||||
|
||||
rule { can?(:public_access) & branch_allows_collaboration }.policy do
|
||||
|
|
|
@ -52,15 +52,13 @@ class EnvironmentSerializer < BaseSerializer
|
|||
end
|
||||
|
||||
def batch_load(resource)
|
||||
temp_deployment_associations = deployment_associations
|
||||
|
||||
resource = resource.preload(environment_associations)
|
||||
|
||||
Preloaders::Environments::DeploymentPreloader.new(resource)
|
||||
.execute_with_union(:last_deployment, temp_deployment_associations)
|
||||
.execute_with_union(:last_deployment, deployment_associations)
|
||||
|
||||
Preloaders::Environments::DeploymentPreloader.new(resource)
|
||||
.execute_with_union(:upcoming_deployment, temp_deployment_associations)
|
||||
.execute_with_union(:upcoming_deployment, deployment_associations)
|
||||
|
||||
resource.to_a.tap do |environments|
|
||||
environments.each do |environment|
|
||||
|
|
|
@ -25,7 +25,7 @@ module Ci
|
|||
end
|
||||
|
||||
def enqueue(build)
|
||||
return build.drop!(:failed_outdated_deployment_job) if build.prevent_rollback_deployment?
|
||||
return build.drop!(:failed_outdated_deployment_job) if build.outdated_deployment?
|
||||
|
||||
build.enqueue
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: scan_result_role_action
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101464
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/377866
|
||||
milestone: '15.6'
|
||||
type: development
|
||||
group: group::security policies
|
||||
default_enabled: false
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropFingerprintFromSbomSources < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
remove_column :sbom_sources, :fingerprint, :bytea
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
8449de1e73e2fb46698e0e160641c4132b99918792b0b3379d6009bab9eab0b7
|
|
@ -21098,8 +21098,7 @@ CREATE TABLE sbom_sources (
|
|||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
source_type smallint NOT NULL,
|
||||
source jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
fingerprint bytea
|
||||
source jsonb DEFAULT '{}'::jsonb NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE sbom_sources_id_seq
|
||||
|
|
|
@ -30,7 +30,7 @@ The tables lists features on the left and provides their capabilities to the rig
|
|||
|
||||
## Geo Capabilities
|
||||
|
||||
If your availability needs to span multiple zones or multiple locations, please read about [Geo](geo/index.md).
|
||||
If your availability needs to span multiple zones or multiple locations, read about [Geo](geo/index.md).
|
||||
|
||||
| | Availability | Recoverability | Data Resiliency | Performance | Risks/Trade-offs|
|
||||
|-|--------------|----------------|-----------------|-------------|-----------------|
|
||||
|
|
|
@ -19,7 +19,7 @@ length of this window is determined by your replication capacity - once the
|
|||
data loss.
|
||||
|
||||
This document assumes you already have a fully configured, working Geo setup.
|
||||
Please read it and the [Disaster Recovery](index.md) failover
|
||||
Read this document and the [Disaster Recovery](index.md) failover
|
||||
documentation in full before proceeding. Planned failover is a major operation,
|
||||
and if performed incorrectly, there is a high risk of data loss. Consider
|
||||
rehearsing the procedure until you are comfortable with the necessary steps and
|
||||
|
|
|
@ -45,7 +45,7 @@ repository storage is either:
|
|||
## Before deploying Gitaly Cluster
|
||||
|
||||
Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management.
|
||||
Before deploying Gitaly Cluster, please review:
|
||||
Before deploying Gitaly Cluster, review:
|
||||
|
||||
- Existing [known issues](#known-issues).
|
||||
- [Snapshot limitations](#snapshot-backup-and-recovery-limitations).
|
||||
|
@ -66,7 +66,7 @@ Contact your Technical Account Manager or customer support if you have any quest
|
|||
### Known issues
|
||||
|
||||
The following table outlines current known issues impacting the use of Gitaly Cluster. For
|
||||
the current status of these issues, please refer to the referenced issues and epics.
|
||||
the current status of these issues, refer to the referenced issues and epics.
|
||||
|
||||
| Issue | Summary | How to avoid |
|
||||
|:--------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------|
|
||||
|
@ -83,11 +83,11 @@ during a restore, we recommend using the [official backup and restore Rake tasks
|
|||
The [incremental backup method](../../raketasks/backup_gitlab.md#incremental-repository-backups)
|
||||
can be used to speed up Gitaly Cluster backups.
|
||||
|
||||
If you are unable to use either method, please contact customer support for restoration help.
|
||||
If you are unable to use either method, contact customer support for restoration help.
|
||||
|
||||
### What to do if you are on Gitaly Cluster experiencing an issue or limitation
|
||||
|
||||
Please contact customer support for immediate help in restoration or recovery.
|
||||
Contact customer support for immediate help in restoration or recovery.
|
||||
|
||||
## Directly accessing repositories
|
||||
|
||||
|
@ -410,7 +410,7 @@ relative path of the repository in the metadata store.
|
|||
### Moving beyond NFS
|
||||
|
||||
Engineering support for NFS for Git repositories is deprecated. Technical support is planned to be unavailable starting
|
||||
November 22, 2022. Please see our [statement of support](https://about.gitlab.com/support/statement-of-support/#gitaly-and-nfs)
|
||||
November 22, 2022. See our [statement of support](https://about.gitlab.com/support/statement-of-support/#gitaly-and-nfs)
|
||||
for more details.
|
||||
|
||||
[Network File System (NFS)](https://en.wikipedia.org/wiki/Network_File_System)
|
||||
|
@ -718,4 +718,4 @@ The second facet presents the only real solution. For this, we developed
|
|||
## NFS deprecation notice
|
||||
|
||||
Engineering support for NFS for Git repositories is deprecated. Technical support is planned to be
|
||||
unavailable beginning November 22, 2022. For further information, please see our [NFS Deprecation](../nfs.md#gitaly-and-nfs-deprecation) documentation.
|
||||
unavailable beginning November 22, 2022. For further information, see our [NFS Deprecation](../nfs.md#gitaly-and-nfs-deprecation) documentation.
|
||||
|
|
|
@ -359,7 +359,7 @@ necessary because [this issue](https://gitlab.com/gitlab-org/gitaly/-/issues/252
|
|||
If this error occurs even though file permissions are correct, it's likely that the Gitaly node is
|
||||
experiencing [clock drift](https://en.wikipedia.org/wiki/Clock_drift).
|
||||
|
||||
Please ensure that the GitLab and Gitaly nodes are synchronized and use an NTP time
|
||||
Ensure that the GitLab and Gitaly nodes are synchronized and use an NTP time
|
||||
server to keep them synchronized if possible.
|
||||
|
||||
### Health check warnings
|
||||
|
|
|
@ -141,7 +141,7 @@ These actions pose a temporary vulnerability while your old Grafana data is in u
|
|||
Deciding to take any of these actions should be weighed carefully with your need to access
|
||||
existing data and dashboards.
|
||||
|
||||
For more information and further mitigation details, please refer to our
|
||||
For more information and further mitigation details, refer to our
|
||||
[blog post on the security release](https://about.gitlab.com/releases/2019/08/12/critical-security-release-gitlab-12-dot-1-dot-6-released/).
|
||||
|
||||
Read more on:
|
||||
|
|
|
@ -52,7 +52,7 @@ If the issue is reproducible, or if it happens intermittently but regularly, Git
|
|||
|
||||
NFS is not well-suited to a workload consisting of many small files, like Git repositories. NFS does provide a number of configuration options designed to improve performance. However, over time, a number of these mount options have proven to result in inconsistencies across multiple nodes mounting the NFS volume, up to and including data loss. Addressing these inconsistencies consume extraordinary development and support engineer time that hamper our ability to develop [Gitaly Cluster](gitaly/praefect.md), our purpose-built solution to addressing the deficiencies of NFS in this environment.
|
||||
|
||||
Please note that Gitaly Cluster provides highly-available Git repository storage. If this is not a requirement, single-node Gitaly backed by block storage is a suitable substitute.
|
||||
Gitaly Cluster provides highly-available Git repository storage. If this is not a requirement, single-node Gitaly backed by block storage is a suitable substitute.
|
||||
|
||||
Engineering support for NFS for Git repositories is deprecated. Technical support is planned to be
|
||||
unavailable from GitLab 15.0. No further enhancements are planned for this feature.
|
||||
|
|
|
@ -68,7 +68,7 @@ over a network which will require, based on implementation, ports `111` and
|
|||
`2049` to be open.
|
||||
|
||||
NOTE:
|
||||
In some cases, the GitLab Registry will be automatically enabled by default. Please see [our documentation](../packages/container_registry.md) for more details
|
||||
In some cases, the GitLab Registry will be automatically enabled by default. See [our documentation](../packages/container_registry.md) for more details.
|
||||
|
||||
[^Consul-notes]: If using additional Consul functionality, more ports may need to be opened. See the [official documentation](https://www.consul.io/docs/install/ports#ports-table) for the list.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Package Signatures **(FREE SELF)**
|
||||
|
||||
As of the release of GitLab 9.5 on August 22, 2017, GitLab provides signed Omnibus GitLab packages for RPM and DEB based distributions. This means that all packages provided on <https://packages.gitlab.com> are signed, starting with `9.5.0`, and all future versions of supported branches (for example `9.3.x` and `9.4.x` after August 22, 2017). Any package version prior to August 22, 2017, will not be signed. Please pass the appropriate argument to your package manager. (Example: `yum --nogpgcheck`)
|
||||
As of the release of GitLab 9.5 on August 22, 2017, GitLab provides signed Omnibus GitLab packages for RPM and DEB based distributions. This means that all packages provided on <https://packages.gitlab.com> are signed, starting with `9.5.0`, and all future versions of supported branches (for example `9.3.x` and `9.4.x` after August 22, 2017). Any package version prior to August 22, 2017, will not be signed. Pass the appropriate argument to your package manager. (Example: `yum --nogpgcheck`)
|
||||
|
||||
Omnibus GitLab packages produced by GitLab are created via the [Omnibus](https://github.com/chef/omnibus) tool, for which GitLab has added DEB signing via `debsigs` in [our own fork](https://gitlab.com/gitlab-org/omnibus). This addition, combined with the existing functionality of RPM signing, allows GitLab to provide signed packages for all supported distributions using DEB or RPM.
|
||||
|
||||
|
|
|
@ -606,7 +606,7 @@ Here is a list and description of each machine and the assigned IP:
|
|||
- `10.6.0.33`: PostgreSQL 3
|
||||
- `10.6.0.41`: GitLab application
|
||||
|
||||
All passwords are set to `toomanysecrets`. Please do not use this password or derived hashes and the `external_url` for GitLab is `http://gitlab.example.com`.
|
||||
All passwords are set to `toomanysecrets`. Do not use this password or derived hashes and the `external_url` for GitLab is `http://gitlab.example.com`.
|
||||
|
||||
After the initial configuration, if a failover occurs, the PostgresSQL leader node changes to one of the available secondaries until it is failed back.
|
||||
|
||||
|
@ -957,7 +957,7 @@ For further details, see [Patroni documentation on this subject](https://patroni
|
|||
### Switching from repmgr to Patroni
|
||||
|
||||
WARNING:
|
||||
Switching from repmgr to Patroni is straightforward, the other way around is *not*. Rolling back from Patroni to repmgr can be complicated and may involve deletion of data directory. If you need to do that, please contact GitLab support.
|
||||
Switching from repmgr to Patroni is straightforward, the other way around is *not*. Rolling back from Patroni to repmgr can be complicated and may involve deletion of data directory. If you need to do that, contact GitLab support.
|
||||
|
||||
You can switch an exiting database cluster to use Patroni instead of repmgr with the following steps:
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ When a **Primary** fails to respond, it's the application's responsibility
|
|||
(in our case GitLab) to handle timeout and reconnect (querying a **Sentinel**
|
||||
for a new **Primary**).
|
||||
|
||||
To get a better understanding on how to correctly set up Sentinel, please read
|
||||
To get a better understanding on how to correctly set up Sentinel, read
|
||||
the [Redis Sentinel](https://redis.io/docs/manual/sentinel/) documentation first, as
|
||||
failing to configure it correctly can lead to data loss or can bring your
|
||||
whole cluster down, invalidating the failover effort.
|
||||
|
@ -350,7 +350,7 @@ Now that the Redis servers are all set up, let's configure the Sentinel
|
|||
servers.
|
||||
|
||||
If you are not sure if your Redis servers are working and replicating
|
||||
correctly, please read the [Troubleshooting Replication](troubleshooting.md#troubleshooting-redis-replication)
|
||||
correctly, read the [Troubleshooting Replication](troubleshooting.md#troubleshooting-redis-replication)
|
||||
and fix it before proceeding with Sentinel setup.
|
||||
|
||||
You must have at least `3` Redis Sentinel servers, and they need to
|
||||
|
|
|
@ -64,7 +64,7 @@ settings outlined in
|
|||
We cannot stress enough the importance of reading the
|
||||
[replication and failover](replication_and_failover.md) documentation of the
|
||||
Omnibus Redis HA as it provides some invaluable information to the configuration
|
||||
of Redis. Please proceed to read it before going forward with this guide.
|
||||
of Redis. Read it before going forward with this guide.
|
||||
|
||||
Before proceeding on setting up the new Redis instances, here are some
|
||||
requirements:
|
||||
|
|
|
@ -134,7 +134,7 @@ X-Gitlab-Event: System Hook
|
|||
```
|
||||
|
||||
Note that `project_rename` is not triggered if the namespace changes.
|
||||
Please refer to `group_rename` and `user_rename` for that case.
|
||||
Refer to `group_rename` and `user_rename` for that case.
|
||||
|
||||
**Project transferred:**
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ are only available internally at GitLab.
|
|||
## Docker
|
||||
|
||||
The following were tested on Docker containers running in the cloud. Support Engineers,
|
||||
please see [these docs](https://gitlab.com/gitlab-com/dev-resources/tree/master/dev-resources#running-docker-containers)
|
||||
see [these docs](https://gitlab.com/gitlab-com/dev-resources/tree/master/dev-resources#running-docker-containers)
|
||||
on how to run Docker containers on `dev-resources`. Other setups haven't been tested,
|
||||
but contributions are welcome.
|
||||
|
||||
### GitLab
|
||||
|
||||
Please see [our official Docker installation method](../../install/docker.md)
|
||||
See [our official Docker installation method](../../install/docker.md)
|
||||
for how to run GitLab on Docker.
|
||||
|
||||
### SAML
|
||||
|
|
|
@ -503,8 +503,7 @@ Example responses:
|
|||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35739) in GitLab 12.7.
|
||||
|
||||
NOTE:
|
||||
Not all deployments can be associated with merge requests.
|
||||
Please see
|
||||
Not all deployments can be associated with merge requests. See
|
||||
[Track what merge requests were deployed to an environment](../ci/environments/index.md#track-newly-included-merge-requests-per-deployment)
|
||||
for more information.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Monitor
|
||||
group: Respond
|
||||
group: Observability
|
||||
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
|
||||
---
|
||||
|
||||
|
|
|
@ -9,4 +9,4 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in GitLab 12.5.
|
||||
|
||||
This API was removed in [GitLab 14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/213369).
|
||||
Please use [the new API](feature_flags.md) instead.
|
||||
Use [the new API](feature_flags.md) instead.
|
||||
|
|
|
@ -16230,6 +16230,7 @@ Represents vulnerability finding of a security report on the pipeline.
|
|||
| <a id="pipelinesecurityreportfindingconfidence"></a>`confidence` **{warning-solid}** | [`String`](#string) | **Deprecated** in 15.4. This field will be removed from the Finding domain model. |
|
||||
| <a id="pipelinesecurityreportfindingdescription"></a>`description` | [`String`](#string) | Description of the vulnerability finding. |
|
||||
| <a id="pipelinesecurityreportfindingdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
|
||||
| <a id="pipelinesecurityreportfindingdetails"></a>`details` | [`[VulnerabilityDetail!]!`](#vulnerabilitydetail) | Details of the security finding. |
|
||||
| <a id="pipelinesecurityreportfindingevidence"></a>`evidence` | [`VulnerabilityEvidence`](#vulnerabilityevidence) | Evidence for the vulnerability. |
|
||||
| <a id="pipelinesecurityreportfindingfalsepositive"></a>`falsePositive` | [`Boolean`](#boolean) | Indicates whether the vulnerability is a false positive. |
|
||||
| <a id="pipelinesecurityreportfindingidentifiers"></a>`identifiers` | [`[VulnerabilityIdentifier!]!`](#vulnerabilityidentifier) | Identifiers of the vulnerability finding. |
|
||||
|
|
|
@ -1413,7 +1413,7 @@ Parameters:
|
|||
|
||||
## Group members
|
||||
|
||||
Please consult the [Group Members](members.md) documentation.
|
||||
See the [Group Members](members.md) documentation.
|
||||
|
||||
## LDAP Group Links
|
||||
|
||||
|
|
|
@ -91,12 +91,13 @@ can be prevented in some circumstances.
|
|||
|
||||
### How to rollback to an outdated deployment
|
||||
|
||||
In some cases, you need to rollback to an outdated deployment. Current workarounds are:
|
||||
> In GitLab 15.6, [rollback via job retry was introduced back](https://gitlab.com/gitlab-org/gitlab/-/issues/378359).
|
||||
|
||||
- Temporarily disable this feature, rollback and re-enable.
|
||||
- Run a new pipeline with previous commit. It contains newer deployment jobs than the latest deployment.
|
||||
In some cases, you need to rollback to an outdated deployment.
|
||||
This feature explicitly allows rollback via [Environment Rollback](index.md#environment-rollback),
|
||||
so that you can quickly rollback in an urgent case.
|
||||
|
||||
Please see [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/378359) for more information about improving the usability.
|
||||
Alternatively, you can run a new pipeline with a previous commit. It contains newer deployment jobs than the latest deployment.
|
||||
|
||||
### Example
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Package
|
||||
group: Package
|
||||
group: Container Registry
|
||||
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
|
||||
---
|
||||
|
||||
|
|
|
@ -36,3 +36,4 @@ Development and architectural documentation for the container registry
|
|||
- [Dependency proxy structure](dependency_proxy.md)
|
||||
- [Settings](settings.md)
|
||||
- [Structure / Schema](structure.md)
|
||||
- [Cleanup policies](cleanup_policies.md)
|
||||
|
|
|
@ -282,7 +282,7 @@ end
|
|||
|
||||
#### Stubbing methods within factories
|
||||
|
||||
You should avoid using `allow(object).to receive(:method)` in factories, as this makes the factory unable to be used with `let_it_be`.
|
||||
You should avoid using `allow(object).to receive(:method)` in factories, as this makes the factory unable to be used with `let_it_be`, as described in [common test setup](#common-test-setup).
|
||||
|
||||
Instead, you can use `stub_method` to stub the method:
|
||||
|
||||
|
@ -921,13 +921,16 @@ them unspecified, and look up the value after the row is created.
|
|||
#### Redis
|
||||
|
||||
GitLab stores two main categories of data in Redis: cached items, and Sidekiq
|
||||
jobs.
|
||||
jobs. [View the full list of `Gitlab::Redis::Wrapper` descendants](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/redis.rb) that are backed by
|
||||
a separate Redis instance.
|
||||
|
||||
In most specs, the Rails cache is actually an in-memory store. This is replaced
|
||||
between specs, so calls to `Rails.cache.read` and `Rails.cache.write` are safe.
|
||||
However, if a spec makes direct Redis calls, it should mark itself with the
|
||||
`:clean_gitlab_redis_cache`, `:clean_gitlab_redis_shared_state` or
|
||||
`:clean_gitlab_redis_queues` traits as appropriate.
|
||||
`:clean_gitlab_redis_queues` traits as appropriate. To avoid triggering rate
|
||||
limiting in specs, mark the spec with the `:clean_gitlab_redis_rate_limiting`
|
||||
trait.
|
||||
|
||||
#### Background jobs / Sidekiq
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ PowerShell has aliases for all of the following commands so you don't have to le
|
|||
- `ls` ---> `dir`
|
||||
- `rm` ---> `del`
|
||||
- `rm -rf nonemptydir` ---> `rmdir /S nonemptydir`
|
||||
- `/` ---> `\` (path separator)
|
||||
- `/` ---> <code>\</code> (path separator)
|
||||
- `cat` ---> `type`
|
||||
- `mv` ---> `move`
|
||||
- Redirection works the same (for example, `>` and `2>&1`)
|
||||
|
|
|
@ -331,7 +331,7 @@ However, you cannot mix the wrapping tags:
|
|||
```
|
||||
|
||||
If your diff includes words in `` `code` `` font, make sure to escape each backtick `` ` `` with a
|
||||
backslash `\`. Otherwise the diff highlight does not render correctly:
|
||||
backslash <code>\</code>. Otherwise the diff highlight does not render correctly:
|
||||
|
||||
```markdown
|
||||
- {+ Just regular text +}
|
||||
|
|
|
@ -81,9 +81,9 @@ Images follow this naming convention:
|
|||
```
|
||||
|
||||
If your project is `gitlab.example.com/mynamespace/myproject`, for example,
|
||||
then your image must be named `gitlab.example.com/mynamespace/myproject/my-app` at a minimum.
|
||||
then your image must be named `gitlab.example.com/mynamespace/myproject` at a minimum.
|
||||
|
||||
You can append additional names to the end of an image name, up to three levels deep.
|
||||
You can append additional names to the end of an image name, up to two levels deep.
|
||||
|
||||
For example, these are all valid image names for images within the project named `myproject`:
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ Advanced Search searches default project branches only.
|
|||
| `+` | And | [`display +banner`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=display+%2Bbanner&snippets=) |
|
||||
| `-` | Exclude | [`display -banner`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=display+-banner) |
|
||||
| `*` | Partial | [`bug error 50*`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=bug+error+50%2A&snippets=) |
|
||||
| `\` | Escape | [`\*md`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=%5C*md&group_id=9970&project_id=278964) |
|
||||
| <code>\</code> | Escape | [`\*md`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=%5C*md&group_id=9970&project_id=278964) |
|
||||
|
||||
## Code search
|
||||
|
||||
|
|
|
@ -499,4 +499,4 @@ You can troubleshoot this by trying the following:
|
|||
- Verify your IDO/U2F hardware security key supports
|
||||
the key type provided.
|
||||
- Verify the version of OpenSSH is 8.2 or greater by
|
||||
running `ssh -v`.
|
||||
running `ssh -V`.
|
||||
|
|
|
@ -47,6 +47,8 @@ module Gitlab
|
|||
{ key: key, name: name, content: content }
|
||||
end
|
||||
|
||||
alias_method :as_json, :to_json
|
||||
|
||||
def <=>(other)
|
||||
name <=> other.name
|
||||
end
|
||||
|
|
|
@ -22137,9 +22137,6 @@ msgstr ""
|
|||
msgid "Invite \"%{email}\" by email"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invite \"%{trimmed}\" by email"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invite Members"
|
||||
msgstr ""
|
||||
|
||||
|
@ -35687,9 +35684,6 @@ msgstr ""
|
|||
msgid "Search for a group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search for a user"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search for an emoji"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "3.5.0",
|
||||
"@gitlab/ui": "46.1.0",
|
||||
"@gitlab/ui": "49.0.0",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "0.0.1-dev-20220815034418",
|
||||
"@rails/actioncable": "6.1.4-7",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Environment' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:user) { create(:user) }
|
||||
let(:role) { :developer }
|
||||
|
||||
|
@ -17,7 +17,7 @@ RSpec.describe 'Environment' do
|
|||
end
|
||||
|
||||
describe 'environment details page' do
|
||||
let!(:environment) { create(:environment, project: project) }
|
||||
let_it_be(:environment) { create(:environment, project: project) }
|
||||
let!(:permissions) {}
|
||||
let!(:deployment) {}
|
||||
let!(:action) {}
|
||||
|
@ -160,10 +160,20 @@ RSpec.describe 'Environment' do
|
|||
end
|
||||
|
||||
context 'with related deployable present' do
|
||||
let(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
let(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) }
|
||||
let_it_be(:previous_pipeline) { create(:ci_pipeline, project: project) }
|
||||
|
||||
let(:deployment) do
|
||||
let_it_be(:previous_build) do
|
||||
create(:ci_build, :success, pipeline: previous_pipeline, environment: environment.name)
|
||||
end
|
||||
|
||||
let_it_be(:previous_deployment) do
|
||||
create(:deployment, :success, environment: environment, deployable: previous_build)
|
||||
end
|
||||
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
let_it_be(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) }
|
||||
|
||||
let_it_be(:deployment) do
|
||||
create(:deployment, :success, environment: environment, deployable: build)
|
||||
end
|
||||
|
||||
|
@ -171,12 +181,10 @@ RSpec.describe 'Environment' do
|
|||
visit_environment(environment)
|
||||
end
|
||||
|
||||
it 'does show build name' do
|
||||
expect(page).to have_link("#{build.name} (##{build.id})")
|
||||
end
|
||||
|
||||
it 'shows the re-deploy button' do
|
||||
it 'shows deployment information and buttons', :js do
|
||||
expect(page).to have_button('Re-deploy to environment')
|
||||
expect(page).to have_button('Rollback environment')
|
||||
expect(page).to have_link("#{build.name} (##{build.id})")
|
||||
end
|
||||
|
||||
context 'with manual action' do
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
import $ from 'jquery';
|
||||
import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from '~/users_select/utils';
|
||||
import { getAjaxUsersSelectParams } from '~/users_select/utils';
|
||||
|
||||
const options = {
|
||||
fooBar: 'baz',
|
||||
activeUserId: 1,
|
||||
};
|
||||
|
||||
describe('getAjaxUsersSelectOptions', () => {
|
||||
it('returns options built from select data attributes', () => {
|
||||
const $select = $('<select />', { 'data-foo-bar': 'baz', 'data-user-id': 1 });
|
||||
|
||||
expect(
|
||||
getAjaxUsersSelectOptions($select, { fooBar: 'fooBar', activeUserId: 'user-id' }),
|
||||
).toEqual(options);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAjaxUsersSelectParams', () => {
|
||||
it('returns query parameters built from provided options', () => {
|
||||
expect(
|
||||
|
|
|
@ -140,7 +140,7 @@ describe('WorkItemDueDate component', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
createComponent({ canUpdate: true, dueDate: '2022-12-31', startDate: '2022-12-31' });
|
||||
datePickerOpenSpy = jest.spyOn(wrapper.vm.$refs.dueDatePicker.calendar, 'show');
|
||||
datePickerOpenSpy = jest.spyOn(wrapper.vm.$refs.dueDatePicker, 'show');
|
||||
findStartDatePicker().vm.$emit('input', startDate);
|
||||
findStartDatePicker().vm.$emit('close');
|
||||
});
|
||||
|
|
|
@ -7,16 +7,6 @@ RSpec.describe Groups::GroupMembersHelper do
|
|||
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
describe '.group_member_select_options' do
|
||||
before do
|
||||
helper.instance_variable_set(:@group, group)
|
||||
end
|
||||
|
||||
it 'returns an options hash' do
|
||||
expect(helper.group_member_select_options).to include(multiple: true, scope: :all, email_user: true)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#group_members_app_data' do
|
||||
include_context 'group_group_link'
|
||||
|
||||
|
|
|
@ -940,10 +940,8 @@ RSpec.describe Gitlab::Git::Repository do
|
|||
let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } }
|
||||
|
||||
def commit_files(commit)
|
||||
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
|
||||
commit.deltas.flat_map do |delta|
|
||||
[delta.old_path, delta.new_path].uniq.compact
|
||||
end
|
||||
commit.deltas.flat_map do |delta|
|
||||
[delta.old_path, delta.new_path].uniq.compact
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ RSpec.describe Gitlab::GithubImport::AttachmentsDownloader do
|
|||
let_it_be(:content_type) { 'application/octet-stream' }
|
||||
|
||||
let(:content_length) { 1000 }
|
||||
let(:chunk_double) { instance_double(HTTParty::FragmentWithResponse, code: 200) }
|
||||
let(:chunk_double) { instance_double(HTTParty::ResponseFragment, code: 200) }
|
||||
let(:headers_double) do
|
||||
instance_double(
|
||||
HTTParty::Response,
|
||||
|
|
|
@ -31,8 +31,8 @@ RSpec.describe Gitlab::Webpack::FileLoader do
|
|||
stub_request(:get, "http://hostname:2000/public_path/#{error_file_path}").to_raise(StandardError)
|
||||
end
|
||||
|
||||
it "returns content when respondes succesfully" do
|
||||
expect(Gitlab::Webpack::FileLoader.load(file_path)).to be(file_contents)
|
||||
it "returns content when responds successfully" do
|
||||
expect(Gitlab::Webpack::FileLoader.load(file_path)).to eq(file_contents)
|
||||
end
|
||||
|
||||
it "raises error when 404" do
|
||||
|
|
|
@ -605,8 +605,8 @@ RSpec.describe Ci::Build do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#prevent_rollback_deployment?' do
|
||||
subject { build.prevent_rollback_deployment? }
|
||||
describe '#outdated_deployment?' do
|
||||
subject { build.outdated_deployment? }
|
||||
|
||||
let(:build) { create(:ci_build, :created, :with_deployment, project: project, environment: 'production') }
|
||||
|
||||
|
@ -624,21 +624,33 @@ RSpec.describe Ci::Build do
|
|||
it { expect(subject).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when deployment cannot rollback' do
|
||||
context 'when build is not an outdated deployment' do
|
||||
before do
|
||||
expect(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(false)
|
||||
allow(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(false)
|
||||
end
|
||||
|
||||
it { expect(subject).to be_falsey }
|
||||
end
|
||||
|
||||
context 'when build can prevent rollback deployment' do
|
||||
context 'when build is older than the latest deployment and still pending status' do
|
||||
before do
|
||||
expect(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(true)
|
||||
allow(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(true)
|
||||
end
|
||||
|
||||
it { expect(subject).to be_truthy }
|
||||
end
|
||||
|
||||
context 'when build is older than the latest deployment but succeeded once' do
|
||||
let(:build) { create(:ci_build, :success, :with_deployment, project: project, environment: 'production') }
|
||||
|
||||
before do
|
||||
allow(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(true)
|
||||
end
|
||||
|
||||
it 'returns false for allowing rollback' do
|
||||
expect(subject).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#schedulable?' do
|
||||
|
|
|
@ -159,7 +159,6 @@ func (c *Config) RegisterGoCloudURLOpeners() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.ObjectStorageConfig.URLMux.RegisterBucket(azureblob.Scheme, urlOpener)
|
||||
}
|
||||
|
||||
|
@ -168,14 +167,13 @@ func (c *Config) RegisterGoCloudURLOpeners() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.ObjectStorageConfig.URLMux.RegisterBucket(gcsblob.Scheme, urlOpener)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (creds *AzureCredentials) getURLOpener() (*azureURLOpener, error) {
|
||||
func (creds *AzureCredentials) getURLOpener() (*azureblob.URLOpener, error) {
|
||||
accountName := azureblob.AccountName(creds.AccountName)
|
||||
accountKey := azureblob.AccountKey(creds.AccountKey)
|
||||
|
||||
|
@ -184,14 +182,10 @@ func (creds *AzureCredentials) getURLOpener() (*azureURLOpener, error) {
|
|||
return nil, fmt.Errorf("error creating Azure credentials: %w", err)
|
||||
}
|
||||
|
||||
pipeline := azureblob.NewPipeline(credential, azblob.PipelineOptions{})
|
||||
|
||||
return &azureURLOpener{
|
||||
&azureblob.URLOpener{
|
||||
AccountName: accountName,
|
||||
Pipeline: pipeline,
|
||||
Options: azureblob.Options{Credential: credential},
|
||||
},
|
||||
return &azureblob.URLOpener{
|
||||
AccountName: accountName,
|
||||
Pipeline: azureblob.NewPipeline(credential, azblob.PipelineOptions{}),
|
||||
Options: azureblob.Options{Credential: credential},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"gocloud.dev/blob"
|
||||
"gocloud.dev/blob/azureblob"
|
||||
)
|
||||
|
||||
// This code can be removed once https://github.com/google/go-cloud/pull/2851 is merged.
|
||||
|
||||
// URLOpener opens Azure URLs like "azblob://mybucket".
|
||||
//
|
||||
// The URL host is used as the bucket name.
|
||||
//
|
||||
// The following query options are supported:
|
||||
// - domain: The domain name used to access the Azure Blob storage (e.g. blob.core.windows.net)
|
||||
type azureURLOpener struct {
|
||||
*azureblob.URLOpener
|
||||
}
|
||||
|
||||
func (o *azureURLOpener) OpenBucketURL(ctx context.Context, u *url.URL) (*blob.Bucket, error) {
|
||||
opts := new(azureblob.Options)
|
||||
*opts = o.Options
|
||||
|
||||
err := setOptionsFromURLParams(u.Query(), opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return azureblob.OpenBucket(ctx, o.Pipeline, o.AccountName, u.Host, opts)
|
||||
}
|
||||
|
||||
func setOptionsFromURLParams(q url.Values, opts *azureblob.Options) error {
|
||||
for param, values := range q {
|
||||
if len(values) > 1 {
|
||||
return fmt.Errorf("multiple values of %v not allowed", param)
|
||||
}
|
||||
|
||||
value := values[0]
|
||||
switch param {
|
||||
case "domain":
|
||||
opts.StorageDomain = azureblob.StorageDomain(value)
|
||||
default:
|
||||
return fmt.Errorf("unknown query parameter %q", param)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gocloud.dev/blob/azureblob"
|
||||
)
|
||||
|
||||
func TestURLOpeners(t *testing.T) {
|
||||
cfg, err := LoadConfig(azureConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, cfg.ObjectStorageCredentials, "Expected object storage credentials")
|
||||
|
||||
require.NoError(t, cfg.RegisterGoCloudURLOpeners())
|
||||
require.NotNil(t, cfg.ObjectStorageConfig.URLMux)
|
||||
|
||||
tests := []struct {
|
||||
url string
|
||||
valid bool
|
||||
}{
|
||||
|
||||
{
|
||||
url: "azblob://container/object",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
url: "azblob://container/object?domain=core.windows.net",
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
url: "azblob://container/object?domain=core.windows.net&domain=test",
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
url: "azblob://container/object?param=value",
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
url: "s3://bucket/object",
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.url, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
url, err := url.Parse(test.url)
|
||||
require.NoError(t, err)
|
||||
|
||||
bucket, err := cfg.ObjectStorageConfig.URLMux.OpenBucketURL(ctx, url)
|
||||
if bucket != nil {
|
||||
defer bucket.Close()
|
||||
}
|
||||
|
||||
if test.valid {
|
||||
require.NotNil(t, bucket)
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTestURLOpenersForParams(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
currOpts azureblob.Options
|
||||
query url.Values
|
||||
wantOpts azureblob.Options
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "InvalidParam",
|
||||
query: url.Values{
|
||||
"foo": {"bar"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "StorageDomain",
|
||||
query: url.Values{
|
||||
"domain": {"blob.core.usgovcloudapi.net"},
|
||||
},
|
||||
wantOpts: azureblob.Options{StorageDomain: "blob.core.usgovcloudapi.net"},
|
||||
},
|
||||
{
|
||||
name: "duplicate StorageDomain",
|
||||
query: url.Values{
|
||||
"domain": {"blob.core.usgovcloudapi.net", "blob.core.windows.net"},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
o := &azureURLOpener{
|
||||
URLOpener: &azureblob.URLOpener{
|
||||
Options: test.currOpts,
|
||||
},
|
||||
}
|
||||
err := setOptionsFromURLParams(test.query, &o.Options)
|
||||
|
||||
if test.wantErr {
|
||||
require.NotNil(t, err)
|
||||
} else {
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, test.wantOpts, o.Options)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1113,10 +1113,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.5.0.tgz#226240b7aa93db986f4c6f7738ca2a1846b5234d"
|
||||
integrity sha512-/djPsJzUY7i/FaydRVt3ZyXiFf5HGNo1rg2mfLn1EpXvT4zc2ag5ECwnYcPb97KgqFCJX6Tk+Ndu8Wh3GoOW1g==
|
||||
|
||||
"@gitlab/ui@46.1.0":
|
||||
version "46.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-46.1.0.tgz#df5918dfcf76ee444ad587f325d55555e8001de7"
|
||||
integrity sha512-11zdly3bDWRqlbPo5kmhoDzcJ0n16kuhuxk2U4N8TMfHXgu6vUYp5NgjPrxzZRHlNVXsYiz7cAqifbr56fxTPg==
|
||||
"@gitlab/ui@49.0.0":
|
||||
version "49.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-49.0.0.tgz#dee2b7de7e4d7e281cd7ccf324d0fb5ad3086a5c"
|
||||
integrity sha512-UOPiGi12wTvbqzJAWo1PDmtZXvcSzy5/auh8qKO9l3uYo4j0RpqYeloSkLvRSKs3V82lpVi0pyJt/S+mMzPjxA==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.11.2"
|
||||
bootstrap-vue "2.20.1"
|
||||
|
|
Loading…
Reference in New Issue