Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
bce6d50b9c
commit
5ca56fbe46
43 changed files with 151 additions and 230 deletions
3
Gemfile
3
Gemfile
|
@ -561,3 +561,6 @@ gem 'ed25519', '~> 1.3.0'
|
|||
# Error Tracking OpenAPI client
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/rake_tasks.md#update-openapi-client-for-error-tracking-feature
|
||||
gem 'error_tracking_open_api', path: 'vendor/gems/error_tracking_open_api'
|
||||
|
||||
# Vulnerability advisories
|
||||
gem 'cvss-suite', '~> 3.0.1', require: 'cvss_suite'
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
{"name":"creole","version":"0.5.0","platform":"ruby","checksum":"951701e2d80760f156b1cb2a93471ca97c076289becc067a33b745133ed32c03"},
|
||||
{"name":"crystalball","version":"0.7.0","platform":"ruby","checksum":"6e729f372a5071daec877adb40c5df4cb25fe21f350635e2a9624373fc151ef2"},
|
||||
{"name":"css_parser","version":"1.11.0","platform":"ruby","checksum":"568926c3193579446ad3e3f9d761c73e2918ee5b3b7757a1a49ec166c67d6de1"},
|
||||
{"name":"cvss-suite","version":"3.0.1","platform":"ruby","checksum":"b5ca9e9e94032a42fd0dc28c1e305378b62c949e35ed7111fc4a1d76f68ad3f9"},
|
||||
{"name":"danger","version":"8.6.1","platform":"ruby","checksum":"d95eb58b41f68d3aaa9bbef697916b6b4d161a38819517c98562531be75cdfd8"},
|
||||
{"name":"danger-gitlab","version":"8.0.0","platform":"ruby","checksum":"497dd7d0f6513913de651019223d8058cf494df10acbd17de92b175dfa04a3a8"},
|
||||
{"name":"database_cleaner","version":"1.7.0","platform":"ruby","checksum":"bdf833c197afac7054015bcde2567c3834c366bbfe6a377c30151ca984b32016"},
|
||||
|
|
|
@ -303,6 +303,7 @@ GEM
|
|||
git
|
||||
css_parser (1.11.0)
|
||||
addressable
|
||||
cvss-suite (3.0.1)
|
||||
danger (8.6.1)
|
||||
claide (~> 1.0)
|
||||
claide-plugins (>= 0.9.2)
|
||||
|
@ -1562,6 +1563,7 @@ DEPENDENCIES
|
|||
countries (~> 3.0)
|
||||
creole (~> 0.5.0)
|
||||
crystalball (~> 0.7.0)
|
||||
cvss-suite (~> 3.0.1)
|
||||
database_cleaner (~> 1.7.0)
|
||||
deckar01-task_list (= 2.3.1)
|
||||
declarative_policy (~> 1.1.0)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { GlModal, GlTabs, GlTab, GlSearchBoxByType, GlSprintf, GlBadge } from '@gitlab/ui';
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import ReviewTabContainer from '~/add_context_commits_modal/components/review_tab_container.vue';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
|
||||
import { s__ } from '~/locale';
|
||||
import eventHub from '../event_hub';
|
||||
|
@ -193,7 +193,7 @@ export default {
|
|||
window.location.reload();
|
||||
}
|
||||
if (!values[0] && !values[1]) {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__(
|
||||
'ContextCommits|Failed to create/remove context commits. Please try again.',
|
||||
),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import Api from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { s__ } from '~/locale';
|
||||
import * as types from './mutation_types';
|
||||
|
@ -71,7 +71,7 @@ export const createContextCommits = ({ state }, { commits, forceReload = false }
|
|||
})
|
||||
.catch(() => {
|
||||
if (forceReload) {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__('ContextCommits|Failed to create context commits. Please try again.'),
|
||||
});
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ export const removeContextCommits = ({ state }, forceReload = false) =>
|
|||
})
|
||||
.catch(() => {
|
||||
if (forceReload) {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__('ContextCommits|Failed to delete context commits. Please try again.'),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import { __ } from '~/locale';
|
|||
import Api, { DEFAULT_PER_PAGE } from '~/api';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import csrf from '~/lib/utils/csrf';
|
||||
|
||||
export default {
|
||||
|
@ -151,7 +151,7 @@ export default {
|
|||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: this.$options.i18n.apiErrorMessage,
|
||||
captureError: true,
|
||||
error,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Api from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||
import { s__ } from '~/locale';
|
||||
import * as types from './mutation_types';
|
||||
|
@ -21,7 +21,7 @@ export const receiveStatisticsSuccess = ({ commit }, statistics) =>
|
|||
|
||||
export const receiveStatisticsError = ({ commit }, error) => {
|
||||
commit(types.RECEIVE_STATISTICS_ERROR, error);
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__('AdminDashboard|Error loading the statistics. Please try again'),
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlSkeletonLoader, GlTable } from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { convertNodeIdsFromGraphQLIds } from '~/graphql_shared/utils';
|
||||
import { thWidthPercent } from '~/lib/utils/table_utility';
|
||||
import { s__, __ } from '~/locale';
|
||||
|
@ -50,7 +50,7 @@ export default {
|
|||
}, {});
|
||||
},
|
||||
error(error) {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: this.$options.i18n.groupCountFetchError,
|
||||
captureError: true,
|
||||
error,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { GlButton, GlAlert, GlTabs, GlTab } from '@gitlab/ui';
|
||||
import createHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql';
|
||||
import updateHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql';
|
||||
import createFlash, { FLASH_TYPES } from '~/flash';
|
||||
import { createAlert, VARIANT_SUCCESS } from '~/flash';
|
||||
import { fetchPolicies } from '~/lib/graphql';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
import { typeSet, i18n, tabIndices } from '../constants';
|
||||
|
@ -75,7 +75,7 @@ export default {
|
|||
return nodes;
|
||||
},
|
||||
error(err) {
|
||||
createFlash({ message: err });
|
||||
createAlert({ message: err });
|
||||
},
|
||||
},
|
||||
currentIntegration: {
|
||||
|
@ -125,7 +125,7 @@ export default {
|
|||
.then(({ data: { httpIntegrationCreate, prometheusIntegrationCreate } = {} } = {}) => {
|
||||
const error = httpIntegrationCreate?.errors[0] || prometheusIntegrationCreate?.errors[0];
|
||||
if (error) {
|
||||
createFlash({ message: error });
|
||||
createAlert({ message: error });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ export default {
|
|||
}
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({ message: ADD_INTEGRATION_ERROR });
|
||||
createAlert({ message: ADD_INTEGRATION_ERROR });
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
|
@ -161,7 +161,7 @@ export default {
|
|||
.then(({ data: { httpIntegrationUpdate, prometheusIntegrationUpdate } = {} } = {}) => {
|
||||
const error = httpIntegrationUpdate?.errors[0] || prometheusIntegrationUpdate?.errors[0];
|
||||
if (error) {
|
||||
createFlash({ message: error });
|
||||
createAlert({ message: error });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -174,13 +174,13 @@ export default {
|
|||
this.clearCurrentIntegration({ type });
|
||||
}
|
||||
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: this.$options.i18n.changesSaved,
|
||||
type: FLASH_TYPES.SUCCESS,
|
||||
variant: VARIANT_SUCCESS,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({ message: UPDATE_INTEGRATION_ERROR });
|
||||
createAlert({ message: UPDATE_INTEGRATION_ERROR });
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
|
@ -198,7 +198,7 @@ export default {
|
|||
const [error] =
|
||||
httpIntegrationResetToken?.errors || prometheusIntegrationResetToken.errors;
|
||||
if (error) {
|
||||
return createFlash({ message: error });
|
||||
return createAlert({ message: error });
|
||||
}
|
||||
|
||||
const integration =
|
||||
|
@ -212,14 +212,14 @@ export default {
|
|||
variables: integration,
|
||||
});
|
||||
|
||||
return createFlash({
|
||||
return createAlert({
|
||||
message: this.$options.i18n.changesSaved,
|
||||
type: FLASH_TYPES.SUCCESS,
|
||||
variant: VARIANT_SUCCESS,
|
||||
});
|
||||
},
|
||||
)
|
||||
.catch(() => {
|
||||
createFlash({ message: RESET_INTEGRATION_TOKEN_ERROR });
|
||||
createAlert({ message: RESET_INTEGRATION_TOKEN_ERROR });
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
|
@ -252,7 +252,7 @@ export default {
|
|||
);
|
||||
},
|
||||
error() {
|
||||
createFlash({ message: DEFAULT_ERROR });
|
||||
createAlert({ message: DEFAULT_ERROR });
|
||||
},
|
||||
});
|
||||
} else {
|
||||
|
@ -272,7 +272,7 @@ export default {
|
|||
this.tabIndex = tabIndex;
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({ message: DEFAULT_ERROR });
|
||||
createAlert({ message: DEFAULT_ERROR });
|
||||
});
|
||||
},
|
||||
deleteIntegration({ id, type }) {
|
||||
|
@ -290,16 +290,16 @@ export default {
|
|||
.then(({ data: { httpIntegrationDestroy } = {} } = {}) => {
|
||||
const error = httpIntegrationDestroy?.errors[0];
|
||||
if (error) {
|
||||
return createFlash({ message: error });
|
||||
return createAlert({ message: error });
|
||||
}
|
||||
this.clearCurrentIntegration({ type });
|
||||
return createFlash({
|
||||
return createAlert({
|
||||
message: this.$options.i18n.integrationRemoved,
|
||||
type: FLASH_TYPES.SUCCESS,
|
||||
variant: VARIANT_SUCCESS,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({ message: DELETE_INTEGRATION_ERROR });
|
||||
createAlert({ message: DELETE_INTEGRATION_ERROR });
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdating = false;
|
||||
|
@ -320,9 +320,9 @@ export default {
|
|||
return service
|
||||
.updateTestAlert(payload)
|
||||
.then(() => {
|
||||
return createFlash({
|
||||
return createAlert({
|
||||
message: this.$options.i18n.alertSent,
|
||||
type: FLASH_TYPES.SUCCESS,
|
||||
variant: VARIANT_SUCCESS,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -330,7 +330,7 @@ export default {
|
|||
if (error.response?.status === httpStatusCodes.FORBIDDEN) {
|
||||
message = INTEGRATION_INACTIVE_PAYLOAD_TEST_ERROR;
|
||||
}
|
||||
createFlash({ message });
|
||||
createAlert({ message });
|
||||
});
|
||||
},
|
||||
saveAndTestAlertPayload(integration, payload) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import produce from 'immer';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
|
||||
import { DELETE_INTEGRATION_ERROR, ADD_INTEGRATION_ERROR } from './error_messages';
|
||||
|
||||
|
@ -59,7 +59,7 @@ const addIntegrationToStore = (
|
|||
};
|
||||
|
||||
const onError = (data, message) => {
|
||||
createFlash({ message });
|
||||
createAlert({ message });
|
||||
throw new Error(data.errors);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
import { flatten, isEqual, keyBy } from 'lodash';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { sprintf, s__ } from '~/locale';
|
||||
import { METRICS_POPOVER_CONTENT } from '../constants';
|
||||
import { removeFlash, prepareTimeMetricsData } from '../utils';
|
||||
|
@ -17,7 +17,7 @@ const requestData = ({ request, endpoint, path, params, name }) => {
|
|||
),
|
||||
{ requestTypeName: name },
|
||||
);
|
||||
createFlash({ message });
|
||||
createAlert({ message });
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
import { GlSingleStat } from '@gitlab/ui/dist/charts';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { number } from '~/lib/utils/unit_format';
|
||||
import { __, s__ } from '~/locale';
|
||||
import usageTrendsCountQuery from '../graphql/queries/usage_trends_count.query.graphql';
|
||||
|
@ -35,7 +35,7 @@ export default {
|
|||
});
|
||||
},
|
||||
error(error) {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: this.$options.i18n.loadCountsError,
|
||||
captureError: true,
|
||||
error,
|
||||
|
|
|
@ -52,11 +52,6 @@ export default {
|
|||
:compact="true"
|
||||
@toggledPaused="onToggledPaused"
|
||||
/>
|
||||
<runner-delete-button
|
||||
:disabled="!canDelete"
|
||||
:runner="runner"
|
||||
:compact="true"
|
||||
@deleted="onDeleted"
|
||||
/>
|
||||
<runner-delete-button v-if="canDelete" :runner="runner" :compact="true" @deleted="onDeleted" />
|
||||
</gl-button-group>
|
||||
</template>
|
||||
|
|
|
@ -5,12 +5,7 @@ import { createAlert } from '~/flash';
|
|||
import { sprintf } from '~/locale';
|
||||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import {
|
||||
I18N_DELETE_DISABLED_MANY_PROJECTS,
|
||||
I18N_DELETE_DISABLED_UNKNOWN_REASON,
|
||||
I18N_DELETE_RUNNER,
|
||||
I18N_DELETED_TOAST,
|
||||
} from '../constants';
|
||||
import { I18N_DELETE_RUNNER, I18N_DELETED_TOAST } from '../constants';
|
||||
import RunnerDeleteModal from './runner_delete_modal.vue';
|
||||
|
||||
export default {
|
||||
|
@ -31,11 +26,6 @@ export default {
|
|||
return runner?.id && runner?.shortSha;
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
compact: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
@ -85,29 +75,14 @@ export default {
|
|||
return null;
|
||||
},
|
||||
tooltip() {
|
||||
if (this.disabled && this.runner.projectCount > 1) {
|
||||
return I18N_DELETE_DISABLED_MANY_PROJECTS;
|
||||
}
|
||||
if (this.disabled) {
|
||||
return I18N_DELETE_DISABLED_UNKNOWN_REASON;
|
||||
}
|
||||
|
||||
// Only show basic "delete" tooltip when compact.
|
||||
// Also prevent a "sticky" tooltip: If this button is
|
||||
// disabled, mouseout listeners don't run leaving the tooltip stuck
|
||||
// loading, mouseout listeners don't run leaving the tooltip stuck
|
||||
if (this.compact && !this.deleting) {
|
||||
return I18N_DELETE_RUNNER;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
wrapperTabindex() {
|
||||
if (this.disabled) {
|
||||
// Trigger tooltip on keyboard-focusable wrapper
|
||||
// See https://bootstrap-vue.org/docs/directives/tooltip
|
||||
return '0';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async onDelete() {
|
||||
|
@ -156,14 +131,13 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div v-gl-tooltip="tooltip" class="btn-group" :tabindex="wrapperTabindex">
|
||||
<div v-gl-tooltip="tooltip" class="btn-group">
|
||||
<gl-button
|
||||
v-gl-modal="runnerDeleteModalId"
|
||||
:aria-label="ariaLabel"
|
||||
:icon="icon"
|
||||
:class="buttonClass"
|
||||
:loading="deleting"
|
||||
:disabled="disabled"
|
||||
variant="danger"
|
||||
category="secondary"
|
||||
v-bind="$attrs"
|
||||
|
|
|
@ -76,12 +76,6 @@ export const I18N_RESUME = __('Resume');
|
|||
export const I18N_RESUME_TOOLTIP = s__('Runners|Resume accepting jobs');
|
||||
|
||||
export const I18N_DELETE_RUNNER = s__('Runners|Delete runner');
|
||||
export const I18N_DELETE_DISABLED_MANY_PROJECTS = s__(
|
||||
'Runners|Multi-project runners cannot be deleted',
|
||||
);
|
||||
export const I18N_DELETE_DISABLED_UNKNOWN_REASON = s__(
|
||||
'Runners|Runner cannot be deleted, please contact your administrator',
|
||||
);
|
||||
export const I18N_DELETED_TOAST = s__('Runners|Runner %{name} was deleted');
|
||||
|
||||
// List
|
||||
|
|
|
@ -8,13 +8,15 @@
|
|||
font-size: 95%;
|
||||
}
|
||||
|
||||
.gfm-project_member {
|
||||
.gfm-project_member,
|
||||
.md a.gfm-project_member {
|
||||
padding: 0 2px;
|
||||
background-color: $blue-100;
|
||||
border-radius: $border-radius-default;
|
||||
color: $blue-700;
|
||||
|
||||
&.current-user {
|
||||
background-color: $orange-50;
|
||||
background-color: $orange-100;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,4 +19,4 @@
|
|||
.form-group
|
||||
= f.gitlab_ui_checkbox_component :floc_enabled,
|
||||
s_('FloC|Participate in FLoC')
|
||||
= f.submit _('Save changes'), class: 'gl-button btn btn-confirm'
|
||||
= f.submit _('Save changes'), pajamas_button: true
|
||||
|
|
|
@ -18,4 +18,4 @@
|
|||
.form-group
|
||||
= f.label :jira_connect_application_key, s_('JiraConnect|Jira Connect Application ID'), class: 'label-bold'
|
||||
= f.text_field :jira_connect_application_key, class: 'form-control gl-form-input'
|
||||
= f.submit _('Save changes'), class: 'gl-button btn btn-confirm'
|
||||
= f.submit _('Save changes'), pajamas_button: true
|
||||
|
|
|
@ -9,4 +9,4 @@
|
|||
|
||||
= render_if_exists 'admin/application_settings/mirror_settings', form: f
|
||||
|
||||
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
|
||||
= f.submit _('Save changes'), pajamas_button: true
|
||||
|
|
|
@ -29,4 +29,4 @@
|
|||
= f.text_field :sourcegraph_url, class: 'form-control gl-form-input', placeholder: s_('SourcegraphAdmin|https://sourcegraph.example.com')
|
||||
.form-text.text-muted
|
||||
= s_('SourcegraphAdmin|Configure the URL to a Sourcegraph instance which can read your GitLab projects.')
|
||||
= f.submit s_('SourcegraphAdmin|Save changes'), class: 'gl-button btn btn-confirm'
|
||||
= f.submit s_('SourcegraphAdmin|Save changes'), pajamas_button: true
|
||||
|
|
|
@ -50,4 +50,4 @@
|
|||
%li
|
||||
= s_('AdminSettings|Restrict group access by IP address. %{link_start}Learn more%{link_end}.').html_safe % { link_start: restrict_ip_link, link_end: link_end }
|
||||
|
||||
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
|
||||
= f.submit _('Save changes'), pajamas_button: true
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
.nav-sidebar-inner-scroll
|
||||
.context-header
|
||||
= link_to profile_path, title: _('Profile Settings'), class: 'has-tooltip', data: { container: 'body', placement: 'right' } do
|
||||
%span{ class: ['avatar-container', 'settings-avatar', 's32'] }
|
||||
= image_tag avatar_icon_for_user(current_user, 32), class: ['avatar', 'avatar-tile', 'js-sidebar-user-avatar', 's32', 'gl-rounded-full!'], alt: current_user.name, data: { testid: 'sidebar-user-avatar' }
|
||||
= render Pajamas::AvatarComponent.new(current_user, size: 32, alt: current_user.name, class: 'gl-mr-3 js-sidebar-user-avatar', avatar_options: { data: { testid: 'sidebar-user-avatar' } })
|
||||
%span.sidebar-context-title= _('User Settings')
|
||||
%ul.sidebar-top-level-items
|
||||
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
= s_("PipelineSchedules|Inactive")
|
||||
%td
|
||||
- if pipeline_schedule.owner
|
||||
= image_tag avatar_icon_for_user(pipeline_schedule.owner, 20), class: "avatar s20"
|
||||
= render Pajamas::AvatarComponent.new(pipeline_schedule.owner, size: 24, class: "gl-mr-2")
|
||||
= link_to user_path(pipeline_schedule.owner) do
|
||||
= pipeline_schedule.owner&.name
|
||||
%td
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
%ul.bordered-list
|
||||
- users.each do |user|
|
||||
%li
|
||||
= link_to user, title: user.name, class: "darken" do
|
||||
= image_tag avatar_icon_for_user(user, 32), class: "avatar s32"
|
||||
%strong= truncate(user.name, length: 40)
|
||||
%div
|
||||
= link_to user, title: user.name, class: "gl-display-flex" do
|
||||
= render Pajamas::AvatarComponent.new(user, size: 32, class: "gl-mr-3")
|
||||
.gl-display-flex.gl-flex-direction-column
|
||||
%strong= truncate(user.name, length: 40)
|
||||
%small.cgray= user.username
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
- else
|
||||
.timeline-avatar.gl-float-left
|
||||
%a.image-diff-avatar-link{ href: user_path(note.author) }
|
||||
= image_tag avatar_icon_for_user(note.author), alt: '', class: 'avatar s32'
|
||||
= render Pajamas::AvatarComponent.new(note.author, size: 32, alt: '')
|
||||
- if note.is_a?(DiffNote) && note.on_image?
|
||||
- if show_image_comment_badge && note_counter == 0
|
||||
-# Only show this for the first comment in the discussion
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
%li.project-row.d-flex{ class: css_class }
|
||||
= cache(cache_key) do
|
||||
- if avatar
|
||||
.avatar-container.s48.flex-grow-0.flex-shrink-0{ class: avatar_container_class }
|
||||
.flex-grow-0.flex-shrink-0{ class: avatar_container_class }
|
||||
= link_to project_path(project), class: dom_class(project) do
|
||||
- if project.creator && use_creator_avatar
|
||||
= image_tag avatar_icon_for_user(project.creator, 48), class: "avatar s48", alt: ''
|
||||
= render Pajamas::AvatarComponent.new(project.creator, size: 48, alt: '', class: 'gl-mr-5')
|
||||
- else
|
||||
= project_icon(project, alt: '', class: 'avatar project-avatar s48', width: 48, height: 48)
|
||||
.project-details.d-sm-flex.flex-sm-fill.align-items-center{ data: { qa_selector: 'project_content', qa_project_name: project.name } }
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: highlight_diffs_renewable_expiration
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95356
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370728
|
||||
milestone: '15.3'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: highlight_diffs_short_renewable_expiration
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95356
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370728
|
||||
milestone: '15.3'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
|
@ -156,6 +156,20 @@ deploy:
|
|||
# ... rest of your job configuration
|
||||
```
|
||||
|
||||
### Using the agent with Auto DevOps
|
||||
|
||||
If Auto DevOps is enabled, you must define the `KUBE_CONTEXT` CI/CD variable. Set the value of `KUBE_CONTEXT` to the context of the agent you want to use in your Auto DevOps pipeline jobs (`<PATH_TO_AGENT_CONFIG_REPOSITORY>:<AGENT_NAME>`).
|
||||
|
||||
You can also use different agents for different Auto DevOps jobs. For instance, you can use one agent for `staging` jobs and a different agent for `production` jobs. To use multiple agents, define a unique CI/CD variable for each agent.
|
||||
|
||||
For example:
|
||||
|
||||
1. Add two [environment-scoped CI/CD variables](../../../ci/variables/index.md#limit-the-environment-scope-of-a-cicd-variable) and name both `KUBE_CONTEXT`.
|
||||
1. Set the `environment` of the first variable to `staging`. Set the value of the variable to `<PATH_TO_AGENT_CONFIGURATION_PROJECT>:<STAGING_AGENT_NAME>`.
|
||||
1. Set the `environment` of the second variable to `production`. Set the value of the variable to `<PATH_TO_AGENT_CONFIGURATION_PROJECT>:<PRODUCTION_AGENT_NAME>`.
|
||||
|
||||
When the `staging` job runs, it will connect to the cluster via the agent named `<STAGING_AGENT_NAME>`, and when the `production` job runs it will connect to the cluster via the agent named `<PRODUCTION_AGENT_NAME>`.
|
||||
|
||||
## Restrict project and group access by using impersonation **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345014) in GitLab 14.5.
|
||||
|
@ -260,6 +274,7 @@ See the [official Kubernetes documentation for details](https://kubernetes.io/do
|
|||
## Related topics
|
||||
|
||||
- [Self-paced classroom workshop](https://gitlab-for-eks.awsworkshop.io) (Uses AWS EKS, but you can use for other Kubernetes clusters)
|
||||
- [Configure Auto DevOps](../../../topics/autodevops/cloud_deployments/auto_devops_with_gke.md#configure-auto-devops)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
@ -110,6 +110,9 @@ in your cluster. You can either:
|
|||
|
||||
If you do not know which one to choose, we recommend starting with Helm.
|
||||
|
||||
NOTE:
|
||||
To connect to multiple clusters, you must configure, register, and install an agent in each cluster. Make sure to give each agent a unique name.
|
||||
|
||||
#### Install the agent with Helm
|
||||
|
||||
To install the agent on your cluster using Helm:
|
||||
|
|
|
@ -4,9 +4,12 @@ module API
|
|||
module Entities
|
||||
module BulkImports
|
||||
class EntityFailure < Grape::Entity
|
||||
expose :exception_message do |failure|
|
||||
::Projects::ImportErrorFilter.filter_message(failure.exception_message.truncate(72))
|
||||
end
|
||||
expose :exception_class
|
||||
expose :pipeline_class
|
||||
expose :pipeline_step
|
||||
expose :exception_class
|
||||
expose :correlation_id_value
|
||||
expose :created_at
|
||||
end
|
||||
|
|
|
@ -82,16 +82,6 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def expiration
|
||||
return 1.day unless Feature.enabled?(:highlight_diffs_renewable_expiration, diffable.project)
|
||||
|
||||
if Feature.enabled?(:highlight_diffs_short_renewable_expiration, diffable.project)
|
||||
EXPIRATION
|
||||
else
|
||||
8.hours
|
||||
end
|
||||
end
|
||||
|
||||
def set_highlighted_diff_lines(diff_file, content)
|
||||
diff_file.highlighted_diff_lines = content.map do |line|
|
||||
Gitlab::Diff::Line.safe_init_from_hash(line)
|
||||
|
@ -147,7 +137,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
# HSETs have to have their expiration date manually updated
|
||||
pipeline.expire(key, expiration)
|
||||
pipeline.expire(key, EXPIRATION)
|
||||
end
|
||||
|
||||
record_memory_usage(fetch_memory_usage(redis, key))
|
||||
|
@ -197,14 +187,12 @@ module Gitlab
|
|||
return {} unless file_paths.any?
|
||||
|
||||
results = []
|
||||
cache_key = key
|
||||
highlight_diffs_renewable_expiration_enabled = Feature.enabled?(:highlight_diffs_renewable_expiration, diffable.project)
|
||||
expiration_period = expiration
|
||||
cache_key = key # Moving out redis calls for feature flags out of redis.pipelined
|
||||
|
||||
Gitlab::Redis::Cache.with do |redis|
|
||||
redis.pipelined do |pipeline|
|
||||
results = pipeline.hmget(cache_key, file_paths)
|
||||
pipeline.expire(key, expiration_period) if highlight_diffs_renewable_expiration_enabled
|
||||
pipeline.expire(key, EXPIRATION)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -34532,9 +34532,6 @@ msgstr ""
|
|||
msgid "Runners|Members of the %{type} can register runners"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Multi-project runners cannot be deleted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Name"
|
||||
msgstr ""
|
||||
|
||||
|
@ -34648,9 +34645,6 @@ msgstr ""
|
|||
msgid "Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Runner cannot be deleted, please contact your administrator"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ RSpec.describe "Group Runners" do
|
|||
visit group_runners_path(group)
|
||||
|
||||
within_runner_row(runner.id) do
|
||||
expect(page).to have_button 'Delete runner', disabled: true
|
||||
expect(page).not_to have_button 'Delete runner'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ import { stubComponent } from 'helpers/stub_component';
|
|||
import DeployKeysTable from '~/admin/deploy_keys/components/table.vue';
|
||||
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import Api, { DEFAULT_PER_PAGE } from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
|
||||
jest.mock('~/api');
|
||||
jest.mock('~/flash');
|
||||
|
@ -243,7 +243,7 @@ describe('DeployKeysTable', () => {
|
|||
itRendersTheEmptyState();
|
||||
|
||||
it('displays flash', () => {
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: DeployKeysTable.i18n.apiErrorMessage,
|
||||
captureError: true,
|
||||
error,
|
||||
|
|
|
@ -10,7 +10,7 @@ import AdminUserActions from '~/admin/users/components/user_actions.vue';
|
|||
import AdminUserAvatar from '~/admin/users/components/user_avatar.vue';
|
||||
import AdminUsersTable from '~/admin/users/components/users_table.vue';
|
||||
import getUsersGroupCountsQuery from '~/admin/users/graphql/queries/get_users_group_counts.query.graphql';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import AdminUserDate from '~/vue_shared/components/user_date.vue';
|
||||
|
||||
import { users, paths, createGroupCountResponse } from '../mock_data';
|
||||
|
@ -135,7 +135,7 @@ describe('AdminUsersTable component', () => {
|
|||
});
|
||||
|
||||
it('creates a flash message and captures the error', () => {
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: 'Could not load user group counts. Please refresh the page to try again.',
|
||||
captureError: true,
|
||||
error: expect.any(Error),
|
||||
|
|
|
@ -30,7 +30,7 @@ import {
|
|||
INTEGRATION_INACTIVE_PAYLOAD_TEST_ERROR,
|
||||
DELETE_INTEGRATION_ERROR,
|
||||
} from '~/alerts_settings/utils/error_messages';
|
||||
import createFlash, { FLASH_TYPES } from '~/flash';
|
||||
import { createAlert, VARIANT_SUCCESS } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
import {
|
||||
|
@ -327,7 +327,7 @@ describe('AlertsSettingsWrapper', () => {
|
|||
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({ message: ADD_INTEGRATION_ERROR });
|
||||
expect(createAlert).toHaveBeenCalledWith({ message: ADD_INTEGRATION_ERROR });
|
||||
});
|
||||
|
||||
it('shows an error alert when integration token reset fails', async () => {
|
||||
|
@ -336,7 +336,7 @@ describe('AlertsSettingsWrapper', () => {
|
|||
findAlertsSettingsForm().vm.$emit('reset-token', {});
|
||||
|
||||
await waitForPromises();
|
||||
expect(createFlash).toHaveBeenCalledWith({ message: RESET_INTEGRATION_TOKEN_ERROR });
|
||||
expect(createAlert).toHaveBeenCalledWith({ message: RESET_INTEGRATION_TOKEN_ERROR });
|
||||
});
|
||||
|
||||
it('shows an error alert when integration update fails', async () => {
|
||||
|
@ -345,7 +345,7 @@ describe('AlertsSettingsWrapper', () => {
|
|||
findAlertsSettingsForm().vm.$emit('update-integration', {});
|
||||
|
||||
await waitForPromises();
|
||||
expect(createFlash).toHaveBeenCalledWith({ message: UPDATE_INTEGRATION_ERROR });
|
||||
expect(createAlert).toHaveBeenCalledWith({ message: UPDATE_INTEGRATION_ERROR });
|
||||
});
|
||||
|
||||
describe('Test alert failure', () => {
|
||||
|
@ -360,17 +360,17 @@ describe('AlertsSettingsWrapper', () => {
|
|||
it('shows an error alert when integration test payload is invalid', async () => {
|
||||
mock.onPost(/(.*)/).replyOnce(httpStatusCodes.UNPROCESSABLE_ENTITY);
|
||||
await wrapper.vm.testAlertPayload({ endpoint: '', data: '', token: '' });
|
||||
expect(createFlash).toHaveBeenCalledWith({ message: INTEGRATION_PAYLOAD_TEST_ERROR });
|
||||
expect(createFlash).toHaveBeenCalledTimes(1);
|
||||
expect(createAlert).toHaveBeenCalledWith({ message: INTEGRATION_PAYLOAD_TEST_ERROR });
|
||||
expect(createAlert).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('shows an error alert when integration is not activated', async () => {
|
||||
mock.onPost(/(.*)/).replyOnce(httpStatusCodes.FORBIDDEN);
|
||||
await wrapper.vm.testAlertPayload({ endpoint: '', data: '', token: '' });
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: INTEGRATION_INACTIVE_PAYLOAD_TEST_ERROR,
|
||||
});
|
||||
expect(createFlash).toHaveBeenCalledTimes(1);
|
||||
expect(createAlert).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -444,9 +444,9 @@ describe('AlertsSettingsWrapper', () => {
|
|||
jest.spyOn(alertsUpdateService, 'updateTestAlert').mockResolvedValueOnce({});
|
||||
findAlertsSettingsForm().vm.$emit('test-alert-payload', '');
|
||||
await waitForPromises();
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: i18n.alertSent,
|
||||
type: FLASH_TYPES.SUCCESS,
|
||||
variant: VARIANT_SUCCESS,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -454,7 +454,7 @@ describe('AlertsSettingsWrapper', () => {
|
|||
jest.spyOn(alertsUpdateService, 'updateTestAlert').mockRejectedValueOnce({});
|
||||
findAlertsSettingsForm().vm.$emit('test-alert-payload', '');
|
||||
await waitForPromises();
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: INTEGRATION_PAYLOAD_TEST_ERROR,
|
||||
});
|
||||
});
|
||||
|
@ -486,7 +486,7 @@ describe('AlertsSettingsWrapper', () => {
|
|||
await destroyHttpIntegration(wrapper);
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
|
||||
expect(createAlert).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
|
||||
});
|
||||
|
||||
it('displays flash if mutation had a non-recoverable error', async () => {
|
||||
|
@ -497,7 +497,7 @@ describe('AlertsSettingsWrapper', () => {
|
|||
await destroyHttpIntegration(wrapper);
|
||||
await waitForPromises();
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: DELETE_INTEGRATION_ERROR,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@ import { METRIC_TYPE_SUMMARY } from '~/api/analytics_api';
|
|||
import { VSA_METRICS_GROUPS, METRICS_POPOVER_CONTENT } from '~/analytics/shared/constants';
|
||||
import { prepareTimeMetricsData } from '~/analytics/shared/utils';
|
||||
import MetricTile from '~/analytics/shared/components/metric_tile.vue';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { group } from './mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
@ -177,7 +177,7 @@ describe('ValueStreamMetrics', () => {
|
|||
});
|
||||
|
||||
it('should render an error message', () => {
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: `There was an error while fetching value stream analytics ${fakeReqName} data.`,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -122,7 +122,7 @@ describe('RunnerActionsCell', () => {
|
|||
expect(wrapper.emitted('deleted')).toEqual([[value]]);
|
||||
});
|
||||
|
||||
it('Renders the runner delete disabled button when user cannot delete', () => {
|
||||
it('Does not render the runner delete button when user cannot delete', () => {
|
||||
createComponent({
|
||||
runner: {
|
||||
userPermissions: {
|
||||
|
@ -132,7 +132,7 @@ describe('RunnerActionsCell', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(findDeleteBtn().props('disabled')).toBe(true);
|
||||
expect(findDeleteBtn().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,11 +9,7 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import { captureException } from '~/runner/sentry_utils';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import { createAlert } from '~/flash';
|
||||
import {
|
||||
I18N_DELETE_RUNNER,
|
||||
I18N_DELETE_DISABLED_MANY_PROJECTS,
|
||||
I18N_DELETE_DISABLED_UNKNOWN_REASON,
|
||||
} from '~/runner/constants';
|
||||
import { I18N_DELETE_RUNNER } from '~/runner/constants';
|
||||
|
||||
import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue';
|
||||
import RunnerDeleteModal from '~/runner/components/runner_delete_modal.vue';
|
||||
|
@ -267,29 +263,4 @@ describe('RunnerDeleteButton', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe.each`
|
||||
reason | runner | tooltip
|
||||
${'runner belongs to more than 1 project'} | ${{ projectCount: 2 }} | ${I18N_DELETE_DISABLED_MANY_PROJECTS}
|
||||
${'unknown reason'} | ${{}} | ${I18N_DELETE_DISABLED_UNKNOWN_REASON}
|
||||
`('When button is disabled because $reason', ({ runner, tooltip }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
props: {
|
||||
disabled: true,
|
||||
runner,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Displays a disabled delete button', () => {
|
||||
expect(findBtn().props('disabled')).toBe(true);
|
||||
});
|
||||
|
||||
it(`Tooltip "${tooltip}" is shown`, () => {
|
||||
// tabindex is required for a11y
|
||||
expect(wrapper.attributes('tabindex')).toBe('0');
|
||||
expect(getTooltip()).toBe(tooltip);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,8 +12,23 @@ RSpec.describe API::Entities::BulkImports::EntityFailure do
|
|||
:pipeline_class,
|
||||
:pipeline_step,
|
||||
:exception_class,
|
||||
:exception_message,
|
||||
:correlation_id_value,
|
||||
:created_at
|
||||
)
|
||||
end
|
||||
|
||||
describe 'exception message' do
|
||||
it 'truncates exception message to 72 characters' do
|
||||
failure.update!(exception_message: 'a' * 100)
|
||||
|
||||
expect(subject[:exception_message].length).to eq(72)
|
||||
end
|
||||
|
||||
it 'removes paths from the message' do
|
||||
failure.update!(exception_message: 'Test /foo/bar')
|
||||
|
||||
expect(subject[:exception_message]).to eq('Test [FILTERED]')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -109,58 +109,36 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
|
|||
end
|
||||
|
||||
shared_examples 'caches missing entries' do
|
||||
where(:expiration_period, :renewable_expiration_ff, :short_renewable_expiration_ff) do
|
||||
[
|
||||
[1.day, false, true],
|
||||
[1.day, false, false],
|
||||
[1.hour, true, true],
|
||||
[8.hours, true, false]
|
||||
]
|
||||
it 'filters the key/value list of entries to be caches for each invocation' do
|
||||
expect(cache).to receive(:write_to_redis_hash)
|
||||
.with(hash_including(*paths))
|
||||
.once
|
||||
.and_call_original
|
||||
|
||||
2.times { cache.write_if_empty }
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
stub_feature_flags(
|
||||
highlight_diffs_renewable_expiration: renewable_expiration_ff,
|
||||
highlight_diffs_short_renewable_expiration: short_renewable_expiration_ff
|
||||
)
|
||||
end
|
||||
it 'reads from cache once' do
|
||||
expect(cache).to receive(:read_cache).once.and_call_original
|
||||
|
||||
it 'filters the key/value list of entries to be caches for each invocation' do
|
||||
expect(cache).to receive(:write_to_redis_hash)
|
||||
.with(hash_including(*paths))
|
||||
.once
|
||||
.and_call_original
|
||||
cache.write_if_empty
|
||||
end
|
||||
|
||||
2.times { cache.write_if_empty }
|
||||
end
|
||||
it 'refreshes TTL of the key on read' do
|
||||
cache.write_if_empty
|
||||
|
||||
it 'reads from cache once' do
|
||||
expect(cache).to receive(:read_cache).once.and_call_original
|
||||
time_until_expire = 30.minutes
|
||||
|
||||
cache.write_if_empty
|
||||
end
|
||||
Gitlab::Redis::Cache.with do |redis|
|
||||
# Emulate that a key is going to expire soon
|
||||
redis.expire(cache.key, time_until_expire)
|
||||
|
||||
it 'refreshes TTL of the key on read' do
|
||||
cache.write_if_empty
|
||||
expect(redis.ttl(cache.key)).to be <= time_until_expire
|
||||
|
||||
time_until_expire = 30.minutes
|
||||
cache.send(:read_cache)
|
||||
|
||||
Gitlab::Redis::Cache.with do |redis|
|
||||
# Emulate that a key is going to expire soon
|
||||
redis.expire(cache.key, time_until_expire)
|
||||
|
||||
expect(redis.ttl(cache.key)).to be <= time_until_expire
|
||||
|
||||
cache.send(:read_cache)
|
||||
|
||||
if renewable_expiration_ff
|
||||
expect(redis.ttl(cache.key)).to be > time_until_expire
|
||||
expect(redis.ttl(cache.key)).to be_within(1.minute).of(expiration_period)
|
||||
else
|
||||
expect(redis.ttl(cache.key)).to be <= time_until_expire
|
||||
end
|
||||
end
|
||||
expect(redis.ttl(cache.key)).to be > time_until_expire
|
||||
expect(redis.ttl(cache.key)).to be_within(1.minute).of(described_class::EXPIRATION)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ RSpec.describe 'shared/projects/_project.html.haml' do
|
|||
it 'renders creator avatar if project has a creator' do
|
||||
render 'shared/projects/project', use_creator_avatar: true, project: project
|
||||
|
||||
expect(rendered).to have_selector('img.avatar')
|
||||
expect(rendered).to have_selector('img.gl-avatar')
|
||||
end
|
||||
|
||||
it 'renders a generic avatar if project does not have a creator' do
|
||||
|
|
Loading…
Reference in a new issue