Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
5d3eac1cf8
commit
c1f785fe21
|
@ -5,6 +5,7 @@ tasks:
|
|||
- name: GDK
|
||||
command: |
|
||||
echo START_TIME_IN_SECONDS="$(date +%s)" | tee /workspace/gitpod_start_time.sh
|
||||
gp sync-done gitpod-start
|
||||
gp sync-await gdk-copied && cd /workspace/gitlab-development-kit && gdk help
|
||||
|
||||
- init: |
|
||||
|
@ -35,9 +36,10 @@ tasks:
|
|||
)
|
||||
command: |
|
||||
(
|
||||
gp sync-await gitpod-start
|
||||
set -e
|
||||
gp sync-done gdk-copied
|
||||
source /workspace/gitpod_start_time.sh
|
||||
[[ -f /workspace/gitpod_start_time.sh ]] && source /workspace/gitpod_start_time.sh
|
||||
SECONDS=0
|
||||
cd /workspace/gitlab-development-kit
|
||||
# update GDK
|
||||
|
@ -72,7 +74,7 @@ tasks:
|
|||
git checkout db/structure.sql
|
||||
cd /workspace/gitlab-development-kit
|
||||
# Waiting for GitLab ...
|
||||
gp await-port 3000
|
||||
gp ports await 3000
|
||||
printf "Waiting for GitLab at $(gp url 3000) ..."
|
||||
# Check /-/readiness which returns JSON, but we're only interested in the exit code
|
||||
#
|
||||
|
@ -84,7 +86,7 @@ tasks:
|
|||
printf "$(date) – GitLab is up (took ~%.1f minutes)\n" "$((10*$SECONDS/60))e-1" | tee -a /workspace/startup.log
|
||||
gp preview $(gp url 3000) || true
|
||||
PREBUILD_LOG=(/workspace/.gitpod/prebuild-log-*)
|
||||
printf "Took %.1f minutes from https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitpod.yml being executed through to completion %s\n" "$((10*(($(date +%s)-${START_TIME_IN_SECONDS}))/60))e-1" "$([[ -f "$PREBUILD_LOG" ]] && echo "With Prebuilds")"
|
||||
[[ -f /workspace/gitpod_start_time.sh ]] && printf "Took %.1f minutes from https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitpod.yml being executed through to completion %s\n" "$((10*(($(date +%s)-${START_TIME_IN_SECONDS}))/60))e-1" "$([[ -f "$PREBUILD_LOG" ]] && echo "With Prebuilds")"
|
||||
)
|
||||
|
||||
ports:
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
<script>
|
||||
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlButton,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
props: {
|
||||
scrollUpButtonDisabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
scrollDownButtonDisabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scrollUpAvailable: Boolean(this.$listeners.scrollUp),
|
||||
scrollDownAvailable: Boolean(this.$listeners.scrollDown),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleRefreshClick() {
|
||||
this.$emit('refresh');
|
||||
},
|
||||
handleScrollUp() {
|
||||
this.$emit('scrollUp');
|
||||
},
|
||||
handleScrollDown() {
|
||||
this.$emit('scrollDown');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-if="scrollUpAvailable"
|
||||
v-gl-tooltip
|
||||
class="controllers-buttons"
|
||||
:title="__('Scroll to top')"
|
||||
aria-labelledby="scroll-to-top"
|
||||
>
|
||||
<gl-button
|
||||
id="scroll-to-top"
|
||||
class="js-scroll-to-top gl-mr-2 btn-blank"
|
||||
:aria-label="__('Scroll to top')"
|
||||
:disabled="scrollUpButtonDisabled"
|
||||
icon="scroll_up"
|
||||
category="primary"
|
||||
variant="default"
|
||||
@click="handleScrollUp()"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="scrollDownAvailable"
|
||||
v-gl-tooltip
|
||||
:disabled="scrollUpButtonDisabled"
|
||||
class="controllers-buttons"
|
||||
:title="__('Scroll to bottom')"
|
||||
aria-labelledby="scroll-to-bottom"
|
||||
>
|
||||
<gl-button
|
||||
id="scroll-to-bottom"
|
||||
class="js-scroll-to-bottom gl-mr-2 btn-blank"
|
||||
:aria-label="__('Scroll to bottom')"
|
||||
:v-if="scrollDownAvailable"
|
||||
:disabled="scrollDownButtonDisabled"
|
||||
icon="scroll_down"
|
||||
category="primary"
|
||||
variant="default"
|
||||
@click="handleScrollDown()"
|
||||
/>
|
||||
</div>
|
||||
<gl-button
|
||||
id="refresh-log"
|
||||
v-gl-tooltip
|
||||
class="js-refresh-log"
|
||||
:title="__('Refresh')"
|
||||
:aria-label="__('Refresh')"
|
||||
icon="retry"
|
||||
category="primary"
|
||||
variant="default"
|
||||
@click="handleRefreshClick"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
|
@ -1,68 +0,0 @@
|
|||
<script>
|
||||
import { GlDropdown, GlDropdownSectionHeader, GlDropdownItem } from '@gitlab/ui';
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlDropdown,
|
||||
GlDropdownSectionHeader,
|
||||
GlDropdownItem,
|
||||
},
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchQuery: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState('environmentLogs', ['pods']),
|
||||
|
||||
podDropdownText() {
|
||||
return this.pods.current || s__('Environments|No pod selected');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('environmentLogs', ['showPodLogs']),
|
||||
isCurrentPod(podName) {
|
||||
return podName === this.pods.current;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<gl-dropdown
|
||||
ref="podsDropdown"
|
||||
:text="podDropdownText"
|
||||
:disabled="disabled"
|
||||
class="gl-mr-3 gl-mb-3 gl-display-flex gl-md-display-block qa-pods-dropdown"
|
||||
>
|
||||
<gl-dropdown-section-header>
|
||||
{{ s__('Environments|Select pod') }}
|
||||
</gl-dropdown-section-header>
|
||||
|
||||
<gl-dropdown-item v-if="!pods.options.length" disabled>
|
||||
<span ref="noPodsMsg" class="text-muted">
|
||||
{{ s__('Environments|No pods to display') }}
|
||||
</span>
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item
|
||||
v-for="podName in pods.options"
|
||||
:key="podName"
|
||||
:is-check-item="true"
|
||||
:is-checked="isCurrentPod(podName)"
|
||||
class="text-nowrap"
|
||||
@click="showPodLogs(podName)"
|
||||
>
|
||||
{{ podName }}
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
</div>
|
||||
</template>
|
|
@ -1,30 +0,0 @@
|
|||
<script>
|
||||
import { GlFilteredSearchToken, GlLoadingIcon } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlFilteredSearchToken,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-filtered-search-token :config="config" v-bind="{ ...$attrs }" v-on="$listeners">
|
||||
<template #suggestions>
|
||||
<div class="m-1">
|
||||
<gl-loading-icon v-if="config.loading" size="sm" />
|
||||
<div v-else class="py-1 px-2 text-muted">
|
||||
{{ config.noOptionsText }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</gl-filtered-search-token>
|
||||
</template>
|
|
@ -1,26 +0,0 @@
|
|||
export const SET_PROJECT_ENVIRONMENT = 'SET_PROJECT_ENVIRONMENT';
|
||||
export const SET_SEARCH = 'SET_SEARCH';
|
||||
export const SET_MANAGED_APP = 'SET_MANAGED_APP';
|
||||
|
||||
export const SET_TIME_RANGE = 'SET_TIME_RANGE';
|
||||
export const SHOW_TIME_RANGE_INVALID_WARNING = 'SHOW_TIME_RANGE_INVALID_WARNING';
|
||||
export const HIDE_TIME_RANGE_INVALID_WARNING = 'HIDE_TIME_RANGE_INVALID_WARNING';
|
||||
|
||||
export const SET_CURRENT_POD_NAME = 'SET_CURRENT_POD_NAME';
|
||||
|
||||
export const REQUEST_ENVIRONMENTS_DATA = 'REQUEST_ENVIRONMENTS_DATA';
|
||||
export const RECEIVE_ENVIRONMENTS_DATA_SUCCESS = 'RECEIVE_ENVIRONMENTS_DATA_SUCCESS';
|
||||
export const RECEIVE_ENVIRONMENTS_DATA_ERROR = 'RECEIVE_ENVIRONMENTS_DATA_ERROR';
|
||||
export const HIDE_REQUEST_ENVIRONMENTS_ERROR = 'HIDE_REQUEST_ENVIRONMENTS_ERROR';
|
||||
|
||||
export const REQUEST_LOGS_DATA = 'REQUEST_LOGS_DATA';
|
||||
export const RECEIVE_LOGS_DATA_SUCCESS = 'RECEIVE_LOGS_DATA_SUCCESS';
|
||||
export const RECEIVE_LOGS_DATA_ERROR = 'RECEIVE_LOGS_DATA_ERROR';
|
||||
export const REQUEST_LOGS_DATA_PREPEND = 'REQUEST_LOGS_DATA_PREPEND';
|
||||
export const RECEIVE_LOGS_DATA_PREPEND_SUCCESS = 'RECEIVE_LOGS_DATA_PREPEND_SUCCESS';
|
||||
export const RECEIVE_LOGS_DATA_PREPEND_ERROR = 'RECEIVE_LOGS_DATA_PREPEND_ERROR';
|
||||
export const HIDE_REQUEST_LOGS_ERROR = 'HIDE_REQUEST_LOGS_ERROR';
|
||||
export const REFRESH_POD_LOGS = 'REFRESH_POD_LOGS';
|
||||
|
||||
export const RECEIVE_PODS_DATA_SUCCESS = 'RECEIVE_PODS_DATA_SUCCESS';
|
||||
export const RECEIVE_PODS_DATA_ERROR = 'RECEIVE_PODS_DATA_ERROR';
|
|
@ -1,110 +0,0 @@
|
|||
import { convertToFixedRange } from '~/lib/utils/datetime_range';
|
||||
import * as types from './mutation_types';
|
||||
|
||||
const mapLine = ({ timestamp, pod, message }) => ({
|
||||
timestamp,
|
||||
pod,
|
||||
message,
|
||||
});
|
||||
|
||||
export default {
|
||||
// Search Data
|
||||
[types.SET_SEARCH](state, searchQuery) {
|
||||
state.search = searchQuery;
|
||||
},
|
||||
|
||||
// Time Range Data
|
||||
[types.SET_TIME_RANGE](state, timeRange) {
|
||||
state.timeRange.selected = timeRange;
|
||||
state.timeRange.current = convertToFixedRange(timeRange);
|
||||
},
|
||||
[types.SHOW_TIME_RANGE_INVALID_WARNING](state) {
|
||||
state.timeRange.invalidWarning = true;
|
||||
},
|
||||
[types.HIDE_TIME_RANGE_INVALID_WARNING](state) {
|
||||
state.timeRange.invalidWarning = false;
|
||||
},
|
||||
|
||||
// Environments Data
|
||||
[types.SET_PROJECT_ENVIRONMENT](state, environmentName) {
|
||||
state.environments.current = environmentName;
|
||||
|
||||
// Clear current pod options
|
||||
state.pods.current = null;
|
||||
state.pods.options = [];
|
||||
},
|
||||
[types.REQUEST_ENVIRONMENTS_DATA](state) {
|
||||
state.environments.options = [];
|
||||
state.environments.isLoading = true;
|
||||
},
|
||||
[types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS](state, environmentOptions) {
|
||||
state.environments.options = environmentOptions;
|
||||
state.environments.isLoading = false;
|
||||
},
|
||||
[types.RECEIVE_ENVIRONMENTS_DATA_ERROR](state) {
|
||||
state.environments.options = [];
|
||||
state.environments.isLoading = false;
|
||||
state.environments.fetchError = true;
|
||||
},
|
||||
[types.HIDE_REQUEST_ENVIRONMENTS_ERROR](state) {
|
||||
state.environments.fetchError = false;
|
||||
},
|
||||
|
||||
// Logs data
|
||||
[types.REQUEST_LOGS_DATA](state) {
|
||||
state.timeRange.current = convertToFixedRange(state.timeRange.selected);
|
||||
|
||||
state.logs.lines = [];
|
||||
state.logs.isLoading = true;
|
||||
|
||||
// start pagination from the beginning
|
||||
state.logs.cursor = null;
|
||||
state.logs.isComplete = false;
|
||||
},
|
||||
[types.RECEIVE_LOGS_DATA_SUCCESS](state, { logs = [], cursor }) {
|
||||
state.logs.lines = logs.map(mapLine);
|
||||
state.logs.isLoading = false;
|
||||
state.logs.cursor = cursor;
|
||||
|
||||
if (!cursor) {
|
||||
state.logs.isComplete = true;
|
||||
}
|
||||
},
|
||||
[types.RECEIVE_LOGS_DATA_ERROR](state) {
|
||||
state.logs.lines = [];
|
||||
state.logs.isLoading = false;
|
||||
state.logs.fetchError = true;
|
||||
},
|
||||
|
||||
[types.REQUEST_LOGS_DATA_PREPEND](state) {
|
||||
state.logs.isLoading = true;
|
||||
},
|
||||
[types.RECEIVE_LOGS_DATA_PREPEND_SUCCESS](state, { logs = [], cursor }) {
|
||||
const lines = logs.map(mapLine);
|
||||
state.logs.lines = lines.concat(state.logs.lines);
|
||||
state.logs.isLoading = false;
|
||||
state.logs.cursor = cursor;
|
||||
|
||||
if (!cursor) {
|
||||
state.logs.isComplete = true;
|
||||
}
|
||||
},
|
||||
[types.RECEIVE_LOGS_DATA_PREPEND_ERROR](state) {
|
||||
state.logs.isLoading = false;
|
||||
state.logs.fetchError = true;
|
||||
},
|
||||
[types.HIDE_REQUEST_LOGS_ERROR](state) {
|
||||
state.logs.fetchError = false;
|
||||
},
|
||||
|
||||
// Pods data
|
||||
[types.SET_CURRENT_POD_NAME](state, podName) {
|
||||
state.pods.current = podName;
|
||||
},
|
||||
[types.RECEIVE_PODS_DATA_SUCCESS](state, podOptions) {
|
||||
state.pods.options = podOptions;
|
||||
},
|
||||
[types.RECEIVE_PODS_DATA_ERROR](state) {
|
||||
state.pods.options = [];
|
||||
},
|
||||
};
|
|
@ -1,56 +0,0 @@
|
|||
import { convertToFixedRange } from '~/lib/utils/datetime_range';
|
||||
import { timeRanges, defaultTimeRange } from '~/vue_shared/constants';
|
||||
|
||||
export default () => ({
|
||||
/**
|
||||
* Full text search
|
||||
*/
|
||||
search: '',
|
||||
|
||||
/**
|
||||
* Time range (Show last)
|
||||
*/
|
||||
timeRange: {
|
||||
options: timeRanges,
|
||||
// Selected time range, can be fixed or relative
|
||||
selected: defaultTimeRange,
|
||||
// Current time range, must be fixed
|
||||
current: convertToFixedRange(defaultTimeRange),
|
||||
|
||||
invalidWarning: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Environments list information
|
||||
*/
|
||||
environments: {
|
||||
options: [],
|
||||
isLoading: false,
|
||||
current: null,
|
||||
fetchError: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Jobs with logs
|
||||
*/
|
||||
logs: {
|
||||
lines: [],
|
||||
isLoading: false,
|
||||
/**
|
||||
* Logs `cursor` represents the current pagination position,
|
||||
* Should be sent in next batch (page) of logs to be fetched
|
||||
*/
|
||||
cursor: null,
|
||||
isComplete: false,
|
||||
|
||||
fetchError: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Pods list information
|
||||
*/
|
||||
pods: {
|
||||
options: [],
|
||||
current: null,
|
||||
},
|
||||
});
|
|
@ -1,7 +1,6 @@
|
|||
import { GlToast } from '@gitlab/ui';
|
||||
import Vue from 'vue';
|
||||
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import Translate from '~/vue_shared/translate';
|
||||
import SettingsApp from './components/group_settings_app.vue';
|
||||
import { apolloProvider } from './graphql';
|
||||
|
@ -20,7 +19,6 @@ export default () => {
|
|||
provide: {
|
||||
groupPath: el.dataset.groupPath,
|
||||
groupDependencyProxyPath: el.dataset.groupDependencyProxyPath,
|
||||
defaultExpanded: parseBoolean(el.dataset.defaultExpanded),
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(SettingsApp);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlToggle, GlSprintf, GlLink } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
|
||||
import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue';
|
||||
import updateDependencyProxySettings from '~/packages_and_registries/settings/group/graphql/mutations/update_dependency_proxy_settings.mutation.graphql';
|
||||
import updateDependencyProxyImageTtlGroupPolicy from '~/packages_and_registries/settings/group/graphql/mutations/update_dependency_proxy_image_ttl_group_policy.mutation.graphql';
|
||||
import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update';
|
||||
|
@ -39,7 +39,7 @@ export default {
|
|||
links: {
|
||||
DEPENDENCY_PROXY_DOCS_PATH,
|
||||
},
|
||||
inject: ['defaultExpanded', 'groupPath', 'groupDependencyProxyPath'],
|
||||
inject: ['groupPath', 'groupDependencyProxyPath'],
|
||||
props: {
|
||||
dependencyProxySettings: {
|
||||
type: Object,
|
||||
|
@ -129,10 +129,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<settings-block
|
||||
:default-expanded="defaultExpanded"
|
||||
data-qa-selector="dependency_proxy_settings_content"
|
||||
>
|
||||
<settings-block data-qa-selector="dependency_proxy_settings_content">
|
||||
<template #title> {{ $options.i18n.DEPENDENCY_PROXY_HEADER }} </template>
|
||||
<template #description> {{ $options.i18n.DEPENDENCY_PROXY_DESCRIPTION }} </template>
|
||||
<template #default>
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
|
||||
import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update';
|
||||
import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses';
|
||||
import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
|
||||
import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue';
|
||||
|
||||
export default {
|
||||
name: 'PackageSettings',
|
||||
|
@ -23,7 +23,7 @@ export default {
|
|||
GenericSettings,
|
||||
DuplicatesSettings,
|
||||
},
|
||||
inject: ['defaultExpanded', 'groupPath'],
|
||||
inject: ['groupPath'],
|
||||
props: {
|
||||
packageSettings: {
|
||||
type: Object,
|
||||
|
@ -84,10 +84,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<settings-block
|
||||
:default-expanded="defaultExpanded"
|
||||
data-qa-selector="package_registry_settings_content"
|
||||
>
|
||||
<settings-block data-qa-selector="package_registry_settings_content">
|
||||
<template #title> {{ $options.i18n.PACKAGE_SETTINGS_HEADER }}</template>
|
||||
<template #description>
|
||||
<span data-testid="description">
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<section class="settings gl-py-7">
|
||||
<div class="gl-lg-display-flex">
|
||||
<div class="gl-lg-w-half gl-pr-10">
|
||||
<h4>
|
||||
<slot name="title"></slot>
|
||||
</h4>
|
||||
<p>
|
||||
<slot name="description"></slot>
|
||||
</p>
|
||||
</div>
|
||||
<div class="gl-lg-w-half gl-pt-3">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
&:first-of-type {
|
||||
margin-top: 10px;
|
||||
padding-top: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ module Ci
|
|||
raise NotSupportedAdapterError, 'This file format requires a dedicated adapter'
|
||||
end
|
||||
|
||||
::Gitlab::ApplicationContext.push(artifact: file.model)
|
||||
|
||||
file.open do |stream|
|
||||
file_format_adapter_class.new(stream).each_blob(&blk)
|
||||
end
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
- help_path = local_assigns.fetch(:help_path)
|
||||
- label = local_assigns.fetch(:label)
|
||||
- last = local_assigns.fetch(:last, false)
|
||||
- classes = ["btn btn-confirm gl-button btn-confirm-secondary gl-flex-direction-column gl-w-half"]
|
||||
- classes = ["btn btn-confirm gl-button btn-confirm-secondary gl-flex-direction-column gl-flex-basis-0 gl-flex-grow-1 gl-min-w-0"]
|
||||
- conditional_classes = [("gl-mr-5" unless last)]
|
||||
|
||||
= link_to help_path, class: classes + conditional_classes do
|
||||
.svg-content.gl-p-3= image_tag logo_path, alt: label, class: "gl-w-64 gl-h-64"
|
||||
%span
|
||||
%span.gl-display-flex.gl-align-items-center.gl-m-3.gl-h-64
|
||||
= image_tag logo_path, alt: label, class: "gl-w-15 gl-max-h-full gl-max-w-full"
|
||||
%span.gl-white-space-normal
|
||||
= label
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
- gke_label = s_('ClusterIntegration|Google GKE')
|
||||
- eks_label = s_('ClusterIntegration|Amazon EKS')
|
||||
- civo_label = s_('ClusterIntegration|Civo Kubernetes')
|
||||
- create_cluster_label = s_('ClusterIntegration|Where do you want to create a cluster?')
|
||||
- eks_help_path = help_page_path('user/infrastructure/clusters/connect/new_eks_cluster')
|
||||
- gke_help_path = help_page_path('user/infrastructure/clusters/connect/new_gke_cluster')
|
||||
- eks_help_path = help_page_path('user/infrastructure/clusters/connect/new_eks_cluster.md')
|
||||
- gke_help_path = help_page_path('user/infrastructure/clusters/connect/new_gke_cluster.md')
|
||||
- civo_help_path = help_page_path('user/infrastructure/clusters/connect/new_civo_cluster.md')
|
||||
|
||||
.gl-p-5
|
||||
.gl-py-5.gl-md-pl-5.gl-md-pr-5
|
||||
%h4.gl-mb-5
|
||||
= create_cluster_label
|
||||
.gl-display-flex
|
||||
= render partial: 'clusters/clusters/cloud_providers/cloud_provider_button',
|
||||
locals: { label: eks_label, logo_path: 'illustrations/logos/amazon_eks.svg', help_path: eks_help_path }
|
||||
= render partial: 'clusters/clusters/cloud_providers/cloud_provider_button',
|
||||
locals: { label: civo_label, logo_path: 'illustrations/third-party-logos/civo.svg', help_path: civo_help_path }
|
||||
= render partial: 'clusters/clusters/cloud_providers/cloud_provider_button',
|
||||
locals: { label: gke_label, logo_path: 'illustrations/logos/google_gke.svg', help_path: gke_help_path, last: true }
|
||||
|
|
|
@ -2,6 +2,5 @@
|
|||
- page_title _('Packages & Registries')
|
||||
- @content_class = 'limit-container-width' unless fluid_layout
|
||||
|
||||
%section#js-packages-and-registries-settings{ data: { default_expanded: expanded_by_default?.to_s,
|
||||
group_path: @group.full_path,
|
||||
%section#js-packages-and-registries-settings{ data: { group_path: @group.full_path,
|
||||
group_dependency_proxy_path: group_dependency_proxy_path(@group) } }
|
||||
|
|
|
@ -9,11 +9,15 @@ end
|
|||
if log_deprecations?
|
||||
# Log deprecation warnings emitted through Kernel#warn, such as from gems or
|
||||
# the Ruby VM.
|
||||
Warning.process(/.+is deprecated$/) do |warning|
|
||||
actions = {
|
||||
/.+is deprecated$/ => lambda do |warning|
|
||||
Gitlab::DeprecationJsonLogger.info(message: warning.strip, source: 'ruby')
|
||||
# Returning :default means we continue emitting this to stderr as well.
|
||||
:default
|
||||
end
|
||||
}
|
||||
|
||||
Warning.process('', actions)
|
||||
|
||||
# Log deprecation warnings emitted from Rails (see ActiveSupport::Deprecation).
|
||||
ActiveSupport::Notifications.subscribe('deprecation.rails') do |name, start, finish, id, payload|
|
||||
|
|
|
@ -6,19 +6,91 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Configure an external Sidekiq instance **(FREE SELF)**
|
||||
|
||||
You can configure an external Sidekiq instance by using the Sidekiq that's
|
||||
bundled in the GitLab package. Sidekiq requires connection to the Redis,
|
||||
You can configure an external Sidekiq instance by using the Sidekiq that's bundled in the GitLab package. Sidekiq requires connection to the Redis,
|
||||
PostgreSQL, and Gitaly instances.
|
||||
|
||||
## Required configuration
|
||||
## Configure TCP access for PostgreSQL, Gitaly, and Redis
|
||||
|
||||
To configure Sidekiq:
|
||||
By default, GitLab uses UNIX sockets and is not set up to communicate via TCP. To change this:
|
||||
|
||||
1. Edit the `/etc/gitlab/gitlab.rb` file on your GitLab instance and add the following:
|
||||
|
||||
```ruby
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
|
||||
postgresql['sql_user_password'] = 'POSTGRESQL_PASSWORD_HASH'
|
||||
postgresql['listen_address'] = '0.0.0.0'
|
||||
postgresql['port'] = 5432
|
||||
|
||||
# Add the Sidekiq nodes to PostgreSQL's trusted addresses.
|
||||
# In the following example, 10.10.1.30/32 is the private IP
|
||||
# of the Sidekiq server.
|
||||
postgresql['md5_auth_cidr_addresses'] = %w(127.0.0.1/32 10.10.1.30/32)
|
||||
postgresql['trust_auth_cidr_addresses'] = %w(127.0.0.1/32 10.10.1.30/32)
|
||||
|
||||
## Gitaly
|
||||
|
||||
# Make Gitaly accept connections on all network interfaces
|
||||
gitaly['listen_addr'] = "0.0.0.0:8075"
|
||||
## Set up the Gitaly token as a form of authentication since you are accessing Gitaly over the network
|
||||
## https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#about-the-gitaly-token
|
||||
gitaly['auth_token'] = 'abc123secret'
|
||||
praefect['auth_token'] = 'abc123secret'
|
||||
gitlab_rails['gitaly_token'] = 'abc123secret'
|
||||
|
||||
## Redis configuration
|
||||
|
||||
redis['bind'] = '0.0.0.0'
|
||||
redis['port'] = 6379
|
||||
# Password to Authenticate Redis
|
||||
redis['password'] = 'redis-password-goes-here'
|
||||
|
||||
gitlab_rails['auto_migrate'] = false
|
||||
```
|
||||
|
||||
1. Run `reconfigure`:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. Restart the `PostgreSQL` server:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl restart postgresql
|
||||
```
|
||||
|
||||
1. After the restart, set `auto_migrate` to `true` or comment to use the default settings:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['auto_migrate'] = true
|
||||
```
|
||||
|
||||
1. Run `reconfigure` again:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
## Set up Sidekiq instance
|
||||
|
||||
1. SSH into the Sidekiq server.
|
||||
|
||||
1. Confirm that you can access the PostgreSQL, Gitaly, and Redis ports:
|
||||
|
||||
```shell
|
||||
telnet <GitLab host> 5432 # PostgreSQL
|
||||
telnet <GitLab host> 8075 # Gitaly
|
||||
telnet <GitLab host> 6379 # Redis
|
||||
```
|
||||
|
||||
1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab package
|
||||
using steps 1 and 2. **Do not complete any other steps.**
|
||||
1. Edit `/etc/gitlab/gitlab.rb` with the following information and make sure
|
||||
to replace with your values:
|
||||
|
||||
1. Copy the `/etc/gitlab/gitlab.rb` file from the GitLab instance and add the following settings. Make sure
|
||||
to replace them with your values:
|
||||
|
||||
<!--
|
||||
Updates to example must be made at:
|
||||
|
@ -59,16 +131,25 @@ Updates to example must be made at:
|
|||
##
|
||||
external_url 'https://gitlab.example.com'
|
||||
|
||||
# Configure the gitlab-shell API callback URL. Without this, `git push` will
|
||||
# fail. This can be your 'front door' GitLab URL or an internal load
|
||||
# balancer.
|
||||
gitlab_rails['internal_api_url'] = 'GITLAB_URL'
|
||||
gitlab_shell['secret_token'] = 'SHELL_TOKEN'
|
||||
|
||||
########################################
|
||||
#### Redis ###
|
||||
########################################
|
||||
|
||||
## Must be the same in every sentinel node
|
||||
redis['master_name'] = 'gitlab-redis'
|
||||
|
||||
## Must be the same in every sentinel node.
|
||||
redis['master_name'] = 'gitlab-redis' # Required if you have setup redis cluster
|
||||
## The same password for Redis authentication you set up for the master node.
|
||||
redis['master_password'] = '<redis_master_password>'
|
||||
|
||||
### If redis is running on the main Gitlab instance and you have opened the TCP port as above add the following
|
||||
gitlab_rails['redis_host'] = '<gitlab host>'
|
||||
gitlab_rails['redis_port'] = 6379
|
||||
|
||||
#######################################
|
||||
### Gitaly ###
|
||||
#######################################
|
||||
|
@ -90,12 +171,6 @@ Updates to example must be made at:
|
|||
gitlab_rails['db_host'] = '<database_host>'
|
||||
gitlab_rails['db_port'] = '5432'
|
||||
gitlab_rails['db_password'] = '<database_password>'
|
||||
|
||||
# Add the Sidekiq nodes to PostgreSQL's trusted addresses.
|
||||
# In the following example, 10.10.1.30/32 is the private IP
|
||||
# of the Sidekiq server.
|
||||
postgresql['trust_auth_cidr_addresses'] = %w(127.0.0.1/32 10.10.1.30/32)
|
||||
|
||||
## Prevent database migrations from running on upgrade automatically
|
||||
gitlab_rails['auto_migrate'] = false
|
||||
|
||||
|
@ -112,13 +187,15 @@ Updates to example must be made at:
|
|||
sidekiq['max_concurrency'] = 10
|
||||
```
|
||||
|
||||
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the GitLab instance and replace the file in the Sidekiq instance.
|
||||
|
||||
1. Reconfigure GitLab:
|
||||
|
||||
```shell
|
||||
sudo gitlab-ctl reconfigure
|
||||
```
|
||||
|
||||
1. Restart the Sidekiq nodes after completing the process and finishing the database migrations.
|
||||
1. Restart the Sidekiq instance after completing the process and finishing the database migrations.
|
||||
|
||||
## Configure multiple Sidekiq nodes with shared storage
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ module Gitlab
|
|||
field_name = field.try(:attribute_name) || field
|
||||
field_value = node[field_name]
|
||||
ordering[field_name] = if field_value.is_a?(Time)
|
||||
field_value.strftime('%Y-%m-%d %H:%M:%S.%N %Z')
|
||||
field_value.to_s(:inspect)
|
||||
else
|
||||
field_value.to_s
|
||||
end
|
||||
|
|
|
@ -96,7 +96,9 @@ module Gitlab
|
|||
column_definitions.each_with_object({}.with_indifferent_access) do |column_definition, hash|
|
||||
field_value = node[column_definition.attribute_name]
|
||||
hash[column_definition.attribute_name] = if field_value.is_a?(Time)
|
||||
field_value.strftime('%Y-%m-%d %H:%M:%S.%N %Z')
|
||||
# use :inspect formatter to provide specific timezone info
|
||||
# eg 2022-07-05 21:57:56.041499000 +0800
|
||||
field_value.to_s(:inspect)
|
||||
elsif field_value.nil?
|
||||
nil
|
||||
elsif lower_named_function?(column_definition)
|
||||
|
|
|
@ -8812,6 +8812,9 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Choose which of your environments will use this cluster."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Civo Kubernetes"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Clear cluster cache"
|
||||
msgstr ""
|
||||
|
||||
|
@ -14665,12 +14668,6 @@ msgstr ""
|
|||
msgid "Environments|No deployments yet"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|No pod selected"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|No pods to display"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Note that this action will stop the environment, but it will %{emphasisStart}not%{emphasisEnd} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd} file."
|
||||
msgstr ""
|
||||
|
||||
|
@ -14695,9 +14692,6 @@ msgstr ""
|
|||
msgid "Environments|Rollback environment %{name}?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Select pod"
|
||||
msgstr ""
|
||||
|
||||
msgid "Environments|Show all"
|
||||
msgstr ""
|
||||
|
||||
|
@ -31748,9 +31742,6 @@ msgstr ""
|
|||
msgid "Refine your search criteria (select a %{strong_open}group%{strong_close} and %{strong_open}project%{strong_close} when possible)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Refresh"
|
||||
msgstr ""
|
||||
|
||||
msgid "Refresh the page and try again."
|
||||
msgstr ""
|
||||
|
||||
|
@ -34359,7 +34350,7 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|After dismissing the alert, the information will never be shown again."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|After enabling a group-level policy, this policy automatically applies to all projects in this group."
|
||||
msgid "SecurityOrchestration|After enabling a group-level policy, this policy automatically applies to all projects and sub-groups in this group."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|All policies"
|
||||
|
|
|
@ -72,6 +72,10 @@ class PipelineTestReportBuilder
|
|||
# Please see for more info: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69053#note_709939709
|
||||
def test_report_for_build(pipeline, build_id)
|
||||
fetch("#{pipeline['web_url']}/tests/suite.json?build_ids[]=#{build_id}")
|
||||
rescue Net::HTTPServerException => e
|
||||
raise e unless e.response.code == 404
|
||||
|
||||
puts "Artifacts not found. They may have expired. Skipping this build."
|
||||
end
|
||||
|
||||
def build_test_report_json_for_pipeline(pipeline)
|
||||
|
@ -92,7 +96,8 @@ class PipelineTestReportBuilder
|
|||
test_report['suites'] ||= []
|
||||
|
||||
failed_builds_for_test_stage.each do |failed_build|
|
||||
test_report['suites'] << test_report_for_build(pipeline, failed_build['id'])
|
||||
suite = test_report_for_build(pipeline, failed_build['id'])
|
||||
test_report['suites'] << suite if suite
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -60,7 +60,6 @@ RSpec.describe 'Group Packages & Registries settings' do
|
|||
visit_settings_page
|
||||
|
||||
expect(page).to have_content('Duplicate packages')
|
||||
expect(page).to have_button('Collapse')
|
||||
end
|
||||
|
||||
it 'automatically saves changes to the server', :js do
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
import { GlButton } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import LogControlButtons from '~/logs/components/log_control_buttons.vue';
|
||||
|
||||
describe('LogControlButtons', () => {
|
||||
let wrapper;
|
||||
|
||||
const findScrollToTop = () => wrapper.find('.js-scroll-to-top');
|
||||
const findScrollToBottom = () => wrapper.find('.js-scroll-to-bottom');
|
||||
const findRefreshBtn = () => wrapper.find('.js-refresh-log');
|
||||
|
||||
const initWrapper = (opts) => {
|
||||
wrapper = shallowMount(LogControlButtons, {
|
||||
listeners: {
|
||||
scrollUp: () => {},
|
||||
scrollDown: () => {},
|
||||
},
|
||||
...opts,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
it('displays UI elements', () => {
|
||||
initWrapper();
|
||||
|
||||
expect(findScrollToTop().is(GlButton)).toBe(true);
|
||||
expect(findScrollToBottom().is(GlButton)).toBe(true);
|
||||
expect(findRefreshBtn().is(GlButton)).toBe(true);
|
||||
});
|
||||
|
||||
it('emits a `refresh` event on click on `refresh` button', async () => {
|
||||
initWrapper();
|
||||
|
||||
// An `undefined` value means no event was emitted
|
||||
expect(wrapper.emitted('refresh')).toBe(undefined);
|
||||
|
||||
findRefreshBtn().vm.$emit('click');
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.emitted('refresh')).toHaveLength(1);
|
||||
});
|
||||
|
||||
describe('when scrolling actions are enabled', () => {
|
||||
beforeEach(async () => {
|
||||
// mock scrolled to the middle of a long page
|
||||
initWrapper();
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
it('click on "scroll to top" scrolls up', () => {
|
||||
expect(findScrollToTop().attributes('disabled')).toBeUndefined();
|
||||
|
||||
findScrollToTop().vm.$emit('click');
|
||||
|
||||
expect(wrapper.emitted('scrollUp')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('click on "scroll to bottom" scrolls down', () => {
|
||||
expect(findScrollToBottom().attributes('disabled')).toBeUndefined();
|
||||
|
||||
findScrollToBottom().vm.$emit('click');
|
||||
|
||||
expect(wrapper.emitted('scrollDown')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when scrolling actions are disabled', () => {
|
||||
beforeEach(async () => {
|
||||
initWrapper({ listeners: {} });
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
it('buttons are disabled', async () => {
|
||||
await nextTick();
|
||||
expect(findScrollToTop().exists()).toBe(false);
|
||||
expect(findScrollToBottom().exists()).toBe(false);
|
||||
// This should be enabled when gitlab-ui contains:
|
||||
// https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/1149
|
||||
// expect(findScrollToBottom().is('[disabled]')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,71 +0,0 @@
|
|||
import { GlFilteredSearchToken, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
|
||||
import TokenWithLoadingState from '~/logs/components/tokens/token_with_loading_state.vue';
|
||||
|
||||
describe('TokenWithLoadingState', () => {
|
||||
let wrapper;
|
||||
|
||||
const findFilteredSearchToken = () => wrapper.find(GlFilteredSearchToken);
|
||||
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
|
||||
|
||||
const initWrapper = (props = {}, options) => {
|
||||
wrapper = shallowMount(TokenWithLoadingState, {
|
||||
propsData: {
|
||||
cursorPosition: 'start',
|
||||
...props,
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {});
|
||||
|
||||
it('passes entire config correctly', () => {
|
||||
const config = {
|
||||
icon: 'pod',
|
||||
type: 'pod',
|
||||
title: 'Pod name',
|
||||
unique: true,
|
||||
};
|
||||
|
||||
initWrapper({ config });
|
||||
|
||||
expect(findFilteredSearchToken().props('config')).toEqual(config);
|
||||
});
|
||||
|
||||
describe('suggestions are replaced', () => {
|
||||
let mockNoOptsText;
|
||||
let config;
|
||||
let stubs;
|
||||
|
||||
beforeEach(() => {
|
||||
mockNoOptsText = 'No suggestions available';
|
||||
config = {
|
||||
loading: false,
|
||||
noOptionsText: mockNoOptsText,
|
||||
};
|
||||
stubs = {
|
||||
GlFilteredSearchToken: {
|
||||
template: `<div><slot name="suggestions"></slot></div>`,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('renders a loading icon', () => {
|
||||
config.loading = true;
|
||||
|
||||
initWrapper({ config }, { stubs });
|
||||
|
||||
expect(findLoadingIcon().exists()).toBe(true);
|
||||
expect(wrapper.text()).toBe('');
|
||||
});
|
||||
|
||||
it('renders an empty results message', () => {
|
||||
initWrapper({ config }, { stubs });
|
||||
|
||||
expect(findLoadingIcon().exists()).toBe(false);
|
||||
expect(wrapper.text()).toBe(mockNoOptsText);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,71 +0,0 @@
|
|||
const mockProjectPath = 'root/autodevops-deploy';
|
||||
|
||||
export const mockEnvName = 'production';
|
||||
export const mockEnvironmentsEndpoint = `${mockProjectPath}/environments.json`;
|
||||
export const mockEnvId = '99';
|
||||
export const mockDocumentationPath = '/documentation.md';
|
||||
export const mockLogsEndpoint = '/dummy_logs_path.json';
|
||||
export const mockCursor = 'MOCK_CURSOR';
|
||||
export const mockNextCursor = 'MOCK_NEXT_CURSOR';
|
||||
|
||||
const makeMockEnvironment = (id, name, advancedQuerying) => ({
|
||||
id,
|
||||
project_path: mockProjectPath,
|
||||
name,
|
||||
logs_api_path: mockLogsEndpoint,
|
||||
enable_advanced_logs_querying: advancedQuerying,
|
||||
});
|
||||
|
||||
export const mockEnvironment = makeMockEnvironment(mockEnvId, mockEnvName, true);
|
||||
export const mockEnvironments = [
|
||||
mockEnvironment,
|
||||
makeMockEnvironment(101, 'staging', false),
|
||||
makeMockEnvironment(102, 'review/a-feature', false),
|
||||
];
|
||||
|
||||
export const mockPodName = 'production-764c58d697-aaaaa';
|
||||
export const mockPods = [
|
||||
mockPodName,
|
||||
'production-764c58d697-bbbbb',
|
||||
'production-764c58d697-ccccc',
|
||||
'production-764c58d697-ddddd',
|
||||
];
|
||||
|
||||
export const mockLogsResult = [
|
||||
{
|
||||
timestamp: '2019-12-13T13:43:18.2760123Z',
|
||||
message: 'log line 1',
|
||||
pod: 'foo',
|
||||
},
|
||||
{
|
||||
timestamp: '2019-12-13T13:43:18.2760123Z',
|
||||
message: 'log line A',
|
||||
pod: 'bar',
|
||||
},
|
||||
{
|
||||
timestamp: '2019-12-13T13:43:26.8420123Z',
|
||||
message: 'log line 2',
|
||||
pod: 'foo',
|
||||
},
|
||||
{
|
||||
timestamp: '2019-12-13T13:43:26.8420123Z',
|
||||
message: 'log line B',
|
||||
pod: 'bar',
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTrace = [
|
||||
'Dec 13 13:43:18.276 | foo | log line 1',
|
||||
'Dec 13 13:43:18.276 | bar | log line A',
|
||||
'Dec 13 13:43:26.842 | foo | log line 2',
|
||||
'Dec 13 13:43:26.842 | bar | log line B',
|
||||
];
|
||||
|
||||
export const mockResponse = {
|
||||
pod_name: mockPodName,
|
||||
pods: mockPods,
|
||||
logs: mockLogsResult,
|
||||
cursor: mockNextCursor,
|
||||
};
|
||||
|
||||
export const mockSearch = 'foo +bar';
|
|
@ -1,257 +0,0 @@
|
|||
import * as types from '~/logs/stores/mutation_types';
|
||||
import mutations from '~/logs/stores/mutations';
|
||||
|
||||
import logsPageState from '~/logs/stores/state';
|
||||
import {
|
||||
mockEnvName,
|
||||
mockEnvironments,
|
||||
mockPods,
|
||||
mockPodName,
|
||||
mockLogsResult,
|
||||
mockSearch,
|
||||
mockCursor,
|
||||
mockNextCursor,
|
||||
} from '../mock_data';
|
||||
|
||||
describe('Logs Store Mutations', () => {
|
||||
let state;
|
||||
|
||||
beforeEach(() => {
|
||||
state = logsPageState();
|
||||
});
|
||||
|
||||
it('ensures mutation types are correctly named', () => {
|
||||
Object.keys(types).forEach((k) => {
|
||||
expect(k).toEqual(types[k]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SET_PROJECT_ENVIRONMENT', () => {
|
||||
it('sets the environment', () => {
|
||||
mutations[types.SET_PROJECT_ENVIRONMENT](state, mockEnvName);
|
||||
expect(state.environments.current).toEqual(mockEnvName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SET_SEARCH', () => {
|
||||
it('sets the search', () => {
|
||||
mutations[types.SET_SEARCH](state, mockSearch);
|
||||
expect(state.search).toEqual(mockSearch);
|
||||
});
|
||||
});
|
||||
|
||||
describe('REQUEST_ENVIRONMENTS_DATA', () => {
|
||||
it('inits data', () => {
|
||||
mutations[types.REQUEST_ENVIRONMENTS_DATA](state);
|
||||
expect(state.environments.options).toEqual([]);
|
||||
expect(state.environments.isLoading).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_ENVIRONMENTS_DATA_SUCCESS', () => {
|
||||
it('receives environments data and stores it as options', () => {
|
||||
expect(state.environments.options).toEqual([]);
|
||||
|
||||
mutations[types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS](state, mockEnvironments);
|
||||
|
||||
expect(state.environments.options).toEqual(mockEnvironments);
|
||||
expect(state.environments.isLoading).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_ENVIRONMENTS_DATA_ERROR', () => {
|
||||
it('captures an error loading environments', () => {
|
||||
mutations[types.RECEIVE_ENVIRONMENTS_DATA_ERROR](state);
|
||||
|
||||
expect(state.environments).toEqual({
|
||||
options: [],
|
||||
isLoading: false,
|
||||
current: null,
|
||||
fetchError: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('REQUEST_LOGS_DATA', () => {
|
||||
it('starts loading for logs', () => {
|
||||
mutations[types.REQUEST_LOGS_DATA](state);
|
||||
|
||||
expect(state.timeRange.current).toEqual({
|
||||
start: expect.any(String),
|
||||
end: expect.any(String),
|
||||
});
|
||||
|
||||
expect(state.logs).toEqual({
|
||||
lines: [],
|
||||
cursor: null,
|
||||
fetchError: false,
|
||||
isLoading: true,
|
||||
isComplete: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_LOGS_DATA_SUCCESS', () => {
|
||||
it('receives logs lines and cursor', () => {
|
||||
mutations[types.RECEIVE_LOGS_DATA_SUCCESS](state, {
|
||||
logs: mockLogsResult,
|
||||
cursor: mockCursor,
|
||||
});
|
||||
|
||||
expect(state.logs).toEqual({
|
||||
lines: mockLogsResult,
|
||||
isLoading: false,
|
||||
cursor: mockCursor,
|
||||
isComplete: false,
|
||||
fetchError: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('receives logs lines and a null cursor to indicate the end', () => {
|
||||
mutations[types.RECEIVE_LOGS_DATA_SUCCESS](state, {
|
||||
logs: mockLogsResult,
|
||||
cursor: null,
|
||||
});
|
||||
|
||||
expect(state.logs).toEqual({
|
||||
lines: mockLogsResult,
|
||||
isLoading: false,
|
||||
cursor: null,
|
||||
isComplete: true,
|
||||
fetchError: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_LOGS_DATA_ERROR', () => {
|
||||
it('receives log data error and stops loading', () => {
|
||||
mutations[types.RECEIVE_LOGS_DATA_ERROR](state);
|
||||
|
||||
expect(state.logs).toEqual({
|
||||
lines: [],
|
||||
isLoading: false,
|
||||
cursor: null,
|
||||
isComplete: false,
|
||||
fetchError: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('REQUEST_LOGS_DATA_PREPEND', () => {
|
||||
it('receives logs lines and cursor', () => {
|
||||
mutations[types.REQUEST_LOGS_DATA_PREPEND](state);
|
||||
|
||||
expect(state.logs.isLoading).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_LOGS_DATA_PREPEND_SUCCESS', () => {
|
||||
it('receives logs lines and cursor', () => {
|
||||
mutations[types.RECEIVE_LOGS_DATA_PREPEND_SUCCESS](state, {
|
||||
logs: mockLogsResult,
|
||||
cursor: mockCursor,
|
||||
});
|
||||
|
||||
expect(state.logs).toEqual({
|
||||
lines: mockLogsResult,
|
||||
isLoading: false,
|
||||
cursor: mockCursor,
|
||||
isComplete: false,
|
||||
fetchError: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('receives additional logs lines and a new cursor', () => {
|
||||
mutations[types.RECEIVE_LOGS_DATA_PREPEND_SUCCESS](state, {
|
||||
logs: mockLogsResult,
|
||||
cursor: mockCursor,
|
||||
});
|
||||
|
||||
mutations[types.RECEIVE_LOGS_DATA_PREPEND_SUCCESS](state, {
|
||||
logs: mockLogsResult,
|
||||
cursor: mockNextCursor,
|
||||
});
|
||||
|
||||
expect(state.logs).toEqual({
|
||||
lines: [...mockLogsResult, ...mockLogsResult],
|
||||
isLoading: false,
|
||||
cursor: mockNextCursor,
|
||||
isComplete: false,
|
||||
fetchError: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('receives logs lines and a null cursor to indicate is complete', () => {
|
||||
mutations[types.RECEIVE_LOGS_DATA_PREPEND_SUCCESS](state, {
|
||||
logs: mockLogsResult,
|
||||
cursor: null,
|
||||
});
|
||||
|
||||
expect(state.logs).toEqual({
|
||||
lines: mockLogsResult,
|
||||
isLoading: false,
|
||||
cursor: null,
|
||||
isComplete: true,
|
||||
fetchError: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_LOGS_DATA_PREPEND_ERROR', () => {
|
||||
it('receives logs lines and cursor', () => {
|
||||
mutations[types.RECEIVE_LOGS_DATA_PREPEND_ERROR](state);
|
||||
|
||||
expect(state.logs.isLoading).toBe(false);
|
||||
expect(state.logs.fetchError).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SET_CURRENT_POD_NAME', () => {
|
||||
it('set current pod name', () => {
|
||||
mutations[types.SET_CURRENT_POD_NAME](state, mockPodName);
|
||||
|
||||
expect(state.pods.current).toEqual(mockPodName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SET_TIME_RANGE', () => {
|
||||
it('sets a default range', () => {
|
||||
expect(state.timeRange.selected).toEqual(expect.any(Object));
|
||||
expect(state.timeRange.current).toEqual(expect.any(Object));
|
||||
});
|
||||
|
||||
it('sets a time range', () => {
|
||||
const mockRange = {
|
||||
start: '2020-01-10T18:00:00.000Z',
|
||||
end: '2020-01-10T10:00:00.000Z',
|
||||
};
|
||||
mutations[types.SET_TIME_RANGE](state, mockRange);
|
||||
|
||||
expect(state.timeRange.selected).toEqual(mockRange);
|
||||
expect(state.timeRange.current).toEqual(mockRange);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_PODS_DATA_SUCCESS', () => {
|
||||
it('receives pods data success', () => {
|
||||
mutations[types.RECEIVE_PODS_DATA_SUCCESS](state, mockPods);
|
||||
|
||||
expect(state.pods).toEqual(
|
||||
expect.objectContaining({
|
||||
options: mockPods,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('RECEIVE_PODS_DATA_ERROR', () => {
|
||||
it('receives pods data error', () => {
|
||||
mutations[types.RECEIVE_PODS_DATA_ERROR](state);
|
||||
|
||||
expect(state.pods).toEqual(
|
||||
expect.objectContaining({
|
||||
options: [],
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -38,7 +38,6 @@ describe('DependencyProxySettings', () => {
|
|||
let updateTtlPoliciesMutationResolver;
|
||||
|
||||
const defaultProvide = {
|
||||
defaultExpanded: false,
|
||||
groupPath: 'foo_group_path',
|
||||
groupDependencyProxyPath: 'group_dependency_proxy_path',
|
||||
};
|
||||
|
@ -109,12 +108,6 @@ describe('DependencyProxySettings', () => {
|
|||
expect(findSettingsBlock().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('passes the correct props to settings block', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findSettingsBlock().props('defaultExpanded')).toBe(false);
|
||||
});
|
||||
|
||||
it('has the correct header text and description', () => {
|
||||
mountComponent();
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ describe('Group Settings App', () => {
|
|||
let show;
|
||||
|
||||
const defaultProvide = {
|
||||
defaultExpanded: false,
|
||||
groupPath: 'foo_group_path',
|
||||
};
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ describe('Packages Settings', () => {
|
|||
let apolloProvider;
|
||||
|
||||
const defaultProvide = {
|
||||
defaultExpanded: false,
|
||||
groupPath: 'foo_group_path',
|
||||
};
|
||||
|
||||
|
@ -93,12 +92,6 @@ describe('Packages Settings', () => {
|
|||
expect(findSettingsBlock().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('passes the correct props to settings block', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findSettingsBlock().props('defaultExpanded')).toBe(false);
|
||||
});
|
||||
|
||||
it('has the correct header text', () => {
|
||||
mountComponent();
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue';
|
||||
|
||||
describe('SettingsBlock', () => {
|
||||
let wrapper;
|
||||
|
||||
const mountComponent = (propsData) => {
|
||||
wrapper = shallowMountExtended(SettingsBlock, {
|
||||
propsData,
|
||||
slots: {
|
||||
title: '<div data-testid="title-slot"></div>',
|
||||
description: '<div data-testid="description-slot"></div>',
|
||||
default: '<div data-testid="default-slot"></div>',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const findDefaultSlot = () => wrapper.findByTestId('default-slot');
|
||||
const findTitleSlot = () => wrapper.findByTestId('title-slot');
|
||||
const findDescriptionSlot = () => wrapper.findByTestId('description-slot');
|
||||
|
||||
it('has a default slot', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findDefaultSlot().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has a title slot', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findTitleSlot().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has a description slot', () => {
|
||||
mountComponent();
|
||||
|
||||
expect(findDescriptionSlot().exists()).toBe(true);
|
||||
});
|
||||
});
|
|
@ -196,10 +196,10 @@ Object {
|
|||
],
|
||||
"paginationInfo": Object {
|
||||
"__typename": "PageInfo",
|
||||
"endCursor": "eyJyZWxlYXNlZF9hdCI6IjIwMTgtMTItMTAgMDA6MDA6MDAuMDAwMDAwMDAwIFVUQyIsImlkIjoiMSJ9",
|
||||
"endCursor": "eyJyZWxlYXNlZF9hdCI6IjIwMTgtMTItMTAgMDA6MDA6MDAuMDAwMDAwMDAwICswMDAwIiwiaWQiOiIxIn0",
|
||||
"hasNextPage": false,
|
||||
"hasPreviousPage": false,
|
||||
"startCursor": "eyJyZWxlYXNlZF9hdCI6IjIwMTktMDEtMTAgMDA6MDA6MDAuMDAwMDAwMDAwIFVUQyIsImlkIjoiMiJ9",
|
||||
"startCursor": "eyJyZWxlYXNlZF9hdCI6IjIwMTktMDEtMTAgMDA6MDA6MDAuMDAwMDAwMDAwICswMDAwIiwiaWQiOiIyIn0",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe '0_log_deprecations' do
|
||||
def setup_other_deprecations
|
||||
Warning.process(__FILE__) { :raise }
|
||||
end
|
||||
|
||||
def load_initializer
|
||||
load Rails.root.join('config/initializers/0_log_deprecations.rb')
|
||||
end
|
||||
|
@ -11,6 +15,7 @@ RSpec.describe '0_log_deprecations' do
|
|||
|
||||
before do
|
||||
stub_env('GITLAB_LOG_DEPRECATIONS', env_var)
|
||||
setup_other_deprecations
|
||||
load_initializer
|
||||
end
|
||||
|
||||
|
@ -20,7 +25,7 @@ RSpec.describe '0_log_deprecations' do
|
|||
ActiveSupport::Notifications.unsubscribe('deprecation.rails')
|
||||
end
|
||||
|
||||
context 'for Ruby deprecations' do
|
||||
describe 'Ruby deprecations' do
|
||||
context 'when catching deprecations through Kernel#warn' do
|
||||
it 'also logs them to deprecation logger' do
|
||||
expect(Gitlab::DeprecationJsonLogger).to receive(:info).with(
|
||||
|
@ -32,7 +37,7 @@ RSpec.describe '0_log_deprecations' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'for other messages from Kernel#warn' do
|
||||
describe 'other messages from Kernel#warn' do
|
||||
it 'does not log them to deprecation logger' do
|
||||
expect(Gitlab::DeprecationJsonLogger).not_to receive(:info)
|
||||
|
||||
|
@ -51,7 +56,7 @@ RSpec.describe '0_log_deprecations' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'for Rails deprecations' do
|
||||
describe 'Rails deprecations' do
|
||||
it 'logs them to deprecation logger' do
|
||||
expect(Gitlab::DeprecationJsonLogger).to receive(:info).with(
|
||||
message: match(/^DEPRECATION WARNING: ABC will be removed/),
|
||||
|
|
|
@ -79,7 +79,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
|
|||
let(:nodes) { Project.all.order(Gitlab::Pagination::Keyset::Order.build([column_order_updated_at, column_order_created_at, column_order_id])) }
|
||||
|
||||
it 'returns the encoded value of the order' do
|
||||
expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.strftime('%Y-%m-%d %H:%M:%S.%N %Z'))
|
||||
expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_s(:inspect))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -92,7 +92,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
|
|||
let(:nodes) { Project.order(:updated_at) }
|
||||
|
||||
it 'returns the encoded value of the order' do
|
||||
expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.strftime('%Y-%m-%d %H:%M:%S.%N %Z'))
|
||||
expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_s(:inspect))
|
||||
end
|
||||
|
||||
it 'includes the :id even when not specified in the order' do
|
||||
|
@ -104,7 +104,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
|
|||
let(:nodes) { Project.order(:updated_at).order(:created_at) }
|
||||
|
||||
it 'returns the encoded value of the order' do
|
||||
expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.strftime('%Y-%m-%d %H:%M:%S.%N %Z'))
|
||||
expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_s(:inspect))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -112,7 +112,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
|
|||
let(:nodes) { Project.order(Arel.sql('projects.updated_at IS NULL')).order(:updated_at).order(:id) }
|
||||
|
||||
it 'returns the encoded value of the order' do
|
||||
expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.strftime('%Y-%m-%d %H:%M:%S.%N %Z'))
|
||||
expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_s(:inspect))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -53,6 +53,15 @@ RSpec.describe Ci::Artifactable do
|
|||
expect { |b| artifact.each_blob(&b) }.to raise_error(described_class::NotSupportedAdapterError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'pushes artifact_size to application context' do
|
||||
let(:artifact) { create(:ci_job_artifact, :junit) }
|
||||
|
||||
it 'logs artifact size', :aggregate_failures do
|
||||
expect { |b| artifact.each_blob(&b) }.to yield_control.once
|
||||
expect(Gitlab::ApplicationContext.current).to include("meta.artifact_size" => artifact.size)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'ActiveRecord scopes' do
|
||||
|
|
|
@ -103,16 +103,18 @@ RSpec.describe PipelineTestReportBuilder do
|
|||
end
|
||||
|
||||
describe '#test_report_for_latest_pipeline' do
|
||||
let(:failed_build_uri) { "#{failed_pipeline_url}/tests/suite.json?build_ids[]=#{failed_build_id}" }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:fetch).with(failed_build_uri).and_return(failed_builds_for_pipeline)
|
||||
end
|
||||
|
||||
it 'fetches builds from pipeline related to MR' do
|
||||
expect(subject).to receive(:fetch).with("#{failed_pipeline_url}/tests/suite.json?build_ids[]=#{failed_build_id}").and_return(failed_builds_for_pipeline)
|
||||
subject.test_report_for_latest_pipeline
|
||||
expected = { "suites" => [failed_builds_for_pipeline] }.to_json
|
||||
expect(subject.test_report_for_latest_pipeline).to eq(expected)
|
||||
end
|
||||
|
||||
context 'canonical pipeline' do
|
||||
before do
|
||||
allow(subject).to receive(:test_report_for_build).and_return(test_report_for_build)
|
||||
end
|
||||
|
||||
context 'no previous pipeline' do
|
||||
let(:mr_pipelines) { [] }
|
||||
|
||||
|
@ -171,6 +173,10 @@ RSpec.describe PipelineTestReportBuilder do
|
|||
end
|
||||
|
||||
context 'failed pipeline and failed test builds' do
|
||||
before do
|
||||
allow(subject).to receive(:fetch).with(failed_build_uri).and_return(test_report_for_build)
|
||||
end
|
||||
|
||||
it 'returns populated test list for suites' do
|
||||
actual = subject.test_report_for_latest_pipeline
|
||||
expected = {
|
||||
|
@ -180,6 +186,36 @@ RSpec.describe PipelineTestReportBuilder do
|
|||
expect(actual).to eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when receiving a server error' do
|
||||
let(:response) { instance_double('Net::HTTPResponse') }
|
||||
let(:error) { Net::HTTPServerException.new('server error', response) }
|
||||
let(:test_report_for_latest_pipeline) { subject.test_report_for_latest_pipeline }
|
||||
|
||||
before do
|
||||
allow(response).to receive(:code).and_return(response_code)
|
||||
allow(subject).to receive(:fetch).with(failed_build_uri).and_raise(error)
|
||||
end
|
||||
|
||||
context 'when response code is 404' do
|
||||
let(:response_code) { 404 }
|
||||
|
||||
it 'continues without the missing reports' do
|
||||
expected = { 'suites' => [] }.to_json
|
||||
|
||||
expect { test_report_for_latest_pipeline }.not_to raise_error
|
||||
expect(test_report_for_latest_pipeline).to eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when response code is unexpected' do
|
||||
let(:response_code) { 500 }
|
||||
|
||||
it 'raises HTTPServerException' do
|
||||
expect { test_report_for_latest_pipeline }.to raise_error(error)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue