Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
674e7e2c3d
commit
87f286558d
|
@ -46,8 +46,6 @@
|
|||
- name: redis:alpine
|
||||
variables:
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
cache:
|
||||
key: "debian-stretch-ruby-2.6.6-pg11-node-12.x"
|
||||
|
||||
.use-pg11-ee:
|
||||
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34"
|
||||
|
@ -58,8 +56,6 @@
|
|||
- name: elasticsearch:6.4.2
|
||||
variables:
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
cache:
|
||||
key: "debian-stretch-ruby-2.6.6-pg11-node-12.x"
|
||||
|
||||
# Pin kaniko to v0.16.0 due to https://github.com/GoogleContainerTools/kaniko/issues/1162
|
||||
.use-kaniko:
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
.rails:needs:setup-and-assets:
|
||||
needs: ["setup-test-env", "compile-assets pull-cache"]
|
||||
|
||||
.rails-cache:
|
||||
cache:
|
||||
key: "ruby-go-cache-v1"
|
||||
paths:
|
||||
- vendor/ruby
|
||||
- vendor/gitaly-ruby
|
||||
- .go/pkg/mod
|
||||
policy: pull
|
||||
|
||||
.rails-job-base:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .default-cache
|
||||
- .default-before_script
|
||||
- .rails-cache
|
||||
|
||||
#######################################################
|
||||
# EE/FOSS: default refs (MRs, master, schedules) jobs #
|
||||
|
@ -13,15 +22,25 @@
|
|||
extends:
|
||||
- .rails-job-base
|
||||
stage: prepare
|
||||
variables:
|
||||
GITLAB_TEST_EAGER_LOAD: "0"
|
||||
script:
|
||||
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
|
||||
- scripts/gitaly-test-build # Do not use 'bundle exec' here
|
||||
- run_timed_command "bundle exec ruby -I. -e 'require \"config/environment\"; TestEnv.init'"
|
||||
- run_timed_command "scripts/gitaly-test-build" # Do not use 'bundle exec' here
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
- tmp/tests
|
||||
- config/secrets.yml
|
||||
- vendor/gitaly-ruby
|
||||
- tmp/tests/gitaly
|
||||
- tmp/tests/gitlab-elasticsearch-indexer
|
||||
- tmp/tests/gitlab-shell
|
||||
- tmp/tests/gitlab-test-fork
|
||||
- tmp/tests/gitlab-test-fork_bare
|
||||
- tmp/tests/gitlab-test
|
||||
- tmp/tests/gitlab-workhorse
|
||||
- tmp/tests/repositories
|
||||
- tmp/tests/second_storage
|
||||
when: always
|
||||
cache:
|
||||
policy: pull-push
|
||||
|
||||
|
@ -52,8 +71,8 @@ static-analysis:
|
|||
downtime_check:
|
||||
extends:
|
||||
- .rails-job-base
|
||||
- .rails:needs:setup-and-assets
|
||||
- .rails:rules:downtime_check
|
||||
needs: ["setup-test-env"]
|
||||
stage: test
|
||||
variables:
|
||||
SETUP_DB: "false"
|
||||
|
@ -176,7 +195,7 @@ gitlab:setup:
|
|||
# db/fixtures/development/04_project.rb thanks to SIZE=1 below
|
||||
- git clone https://gitlab.com/gitlab-org/gitlab-test.git
|
||||
/home/git/repositories/gitlab-org/gitlab-test.git
|
||||
- scripts/gitaly-test-spawn
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- force=yes SIZE=1 FIXTURE_PATH="db/fixtures/development" bundle exec rake gitlab:setup
|
||||
artifacts:
|
||||
when: on_failure
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
"Elasticsearch",
|
||||
"Facebook",
|
||||
"GDK",
|
||||
"Geo",
|
||||
"Git LFS",
|
||||
"git-annex",
|
||||
"Git",
|
||||
|
|
|
@ -1 +1 @@
|
|||
12.2.0
|
||||
13.2.0
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
<script>
|
||||
import ActiveToggle from './active_toggle.vue';
|
||||
import JiraTriggerFields from './jira_trigger_fields.vue';
|
||||
import TriggerFields from './trigger_fields.vue';
|
||||
|
||||
export default {
|
||||
name: 'IntegrationForm',
|
||||
components: {
|
||||
ActiveToggle,
|
||||
JiraTriggerFields,
|
||||
TriggerFields,
|
||||
},
|
||||
props: {
|
||||
activeToggleProps: {
|
||||
|
@ -21,6 +23,11 @@ export default {
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
triggerEvents: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -38,5 +45,6 @@ export default {
|
|||
<div>
|
||||
<active-toggle v-if="showActive" v-bind="activeToggleProps" />
|
||||
<jira-trigger-fields v-if="isJira" v-bind="triggerFieldsProps" />
|
||||
<trigger-fields v-else-if="triggerEvents.length" :events="triggerEvents" :type="type" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<script>
|
||||
import { startCase } from 'lodash';
|
||||
import { __ } from '~/locale';
|
||||
import { GlFormGroup, GlFormCheckbox, GlFormInput } from '@gitlab/ui';
|
||||
|
||||
const typeWithPlaceholder = {
|
||||
SLACK: 'slack',
|
||||
MATTERMOST: 'mattermost',
|
||||
};
|
||||
|
||||
const placeholderForType = {
|
||||
[typeWithPlaceholder.SLACK]: __('Slack channels (e.g. general, development)'),
|
||||
[typeWithPlaceholder.MATTERMOST]: __('Channel handle (e.g. town-square)'),
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'TriggerFields',
|
||||
components: {
|
||||
GlFormGroup,
|
||||
GlFormCheckbox,
|
||||
GlFormInput,
|
||||
},
|
||||
props: {
|
||||
events: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
placeholder() {
|
||||
return placeholderForType[this.type];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
checkboxName(name) {
|
||||
return `service[${name}]`;
|
||||
},
|
||||
fieldName(name) {
|
||||
return `service[${name}]`;
|
||||
},
|
||||
startCase,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-form-group
|
||||
class="gl-pt-3"
|
||||
:label="__('Trigger')"
|
||||
label-for="trigger-fields"
|
||||
data-testid="trigger-fields-group"
|
||||
>
|
||||
<div id="trigger-fields" class="gl-pt-3">
|
||||
<gl-form-group v-for="event in events" :key="event.title" :description="event.description">
|
||||
<input :name="checkboxName(event.name)" type="hidden" value="false" />
|
||||
<gl-form-checkbox v-model="event.value" :name="checkboxName(event.name)">
|
||||
{{ startCase(event.title) }}
|
||||
</gl-form-checkbox>
|
||||
<gl-form-input
|
||||
v-if="event.field"
|
||||
v-model="event.field.value"
|
||||
:name="fieldName(event.field.name)"
|
||||
:placeholder="placeholder"
|
||||
/>
|
||||
</gl-form-group>
|
||||
</div>
|
||||
</gl-form-group>
|
||||
</template>
|
|
@ -15,7 +15,7 @@ export default el => {
|
|||
return result;
|
||||
}
|
||||
|
||||
const { type, commentDetail, ...booleanAttributes } = el.dataset;
|
||||
const { type, commentDetail, triggerEvents, ...booleanAttributes } = el.dataset;
|
||||
const {
|
||||
showActive,
|
||||
activated,
|
||||
|
@ -40,6 +40,7 @@ export default el => {
|
|||
initialEnableComments: enableComments,
|
||||
initialCommentDetail: commentDetail,
|
||||
},
|
||||
triggerEvents: JSON.parse(triggerEvents),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
@ -226,6 +226,7 @@ export default {
|
|||
'environmentsLoading',
|
||||
'expandedPanel',
|
||||
'promVariables',
|
||||
'isUpdatingStarredValue',
|
||||
]),
|
||||
...mapGetters('monitoringDashboard', ['getMetricStates', 'filteredEnvironments']),
|
||||
firstDashboard() {
|
||||
|
@ -312,6 +313,7 @@ export default {
|
|||
'filterEnvironments',
|
||||
'setExpandedPanel',
|
||||
'clearExpandedPanel',
|
||||
'toggleStarredValue',
|
||||
]),
|
||||
updatePanels(key, panels) {
|
||||
this.setPanelGroupMetrics({
|
||||
|
@ -422,6 +424,8 @@ export default {
|
|||
},
|
||||
i18n: {
|
||||
goBackLabel: s__('Metrics|Go back (Esc)'),
|
||||
starDashboard: s__('Metrics|Star dashboard'),
|
||||
unstarDashboard: s__('Metrics|Unstar dashboard'),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -518,6 +522,32 @@ export default {
|
|||
<div class="flex-grow-1"></div>
|
||||
|
||||
<div class="d-sm-flex">
|
||||
<div v-if="selectedDashboard" class="mb-2 mr-2 d-flex">
|
||||
<!--
|
||||
wrapper for tooltip as button can be `disabled`
|
||||
https://bootstrap-vue.org/docs/components/tooltip#disabled-elements
|
||||
-->
|
||||
<div
|
||||
v-gl-tooltip
|
||||
class="flex-grow-1"
|
||||
:title="
|
||||
selectedDashboard.starred
|
||||
? $options.i18n.unstarDashboard
|
||||
: $options.i18n.starDashboard
|
||||
"
|
||||
>
|
||||
<gl-deprecated-button
|
||||
ref="toggleStarBtn"
|
||||
class="w-100"
|
||||
:disabled="isUpdatingStarredValue"
|
||||
variant="default"
|
||||
@click="toggleStarredValue()"
|
||||
>
|
||||
<gl-icon :name="selectedDashboard.starred ? 'star' : 'star-o'" />
|
||||
</gl-deprecated-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="showRearrangePanelsBtn" class="mb-2 mr-2 d-flex">
|
||||
<gl-deprecated-button
|
||||
:pressed="isRearrangingPanels"
|
||||
|
|
|
@ -7,17 +7,28 @@ import TreePage from './pages/tree.vue';
|
|||
Vue.use(VueRouter);
|
||||
|
||||
export default function createRouter(base, baseRef) {
|
||||
const treePathRoute = {
|
||||
component: TreePage,
|
||||
props: route => ({
|
||||
path: route.params.path?.replace(/^\//, '') || '/',
|
||||
}),
|
||||
};
|
||||
|
||||
return new VueRouter({
|
||||
mode: 'history',
|
||||
base: joinPaths(gon.relative_url_root || '', base),
|
||||
routes: [
|
||||
{
|
||||
path: `(/-)?/tree/${baseRef}/:path*`,
|
||||
name: 'treePathDecoded',
|
||||
// Sometimes the ref needs decoding depending on how the backend sends it to us
|
||||
path: `(/-)?/tree/${decodeURI(baseRef)}/:path*`,
|
||||
...treePathRoute,
|
||||
},
|
||||
{
|
||||
name: 'treePath',
|
||||
component: TreePage,
|
||||
props: route => ({
|
||||
path: route.params.path?.replace(/^\//, '') || '/',
|
||||
}),
|
||||
// Support without decoding as well just in case the ref doesn't need to be decoded
|
||||
path: `(/-)?/tree/${baseRef}/:path*`,
|
||||
...treePathRoute,
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
|
|
|
@ -1,20 +1,14 @@
|
|||
<script>
|
||||
import { GlFormTextarea } from '@gitlab/ui';
|
||||
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
|
||||
import PublishToolbar from '../components/publish_toolbar.vue';
|
||||
import EditHeader from '../components/edit_header.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlFormTextarea,
|
||||
RichContentEditor,
|
||||
PublishToolbar,
|
||||
EditHeader,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
|
@ -55,8 +49,7 @@ export default {
|
|||
<template>
|
||||
<div class="d-flex flex-grow-1 flex-column">
|
||||
<edit-header class="py-2" :title="title" />
|
||||
<rich-content-editor v-if="glFeatures.richContentEditor" v-model="editableContent" />
|
||||
<gl-form-textarea v-else v-model="editableContent" class="h-100 shadow-none" />
|
||||
<rich-content-editor v-model="editableContent" class="mb-9" />
|
||||
<publish-toolbar
|
||||
class="gl-fixed gl-left-0 gl-bottom-0 gl-w-full"
|
||||
:return-url="returnUrl"
|
||||
|
|
|
@ -19,6 +19,7 @@ class GraphqlController < ApplicationController
|
|||
|
||||
before_action :authorize_access_api!
|
||||
before_action(only: [:execute]) { authenticate_sessionless_user!(:api) }
|
||||
before_action :set_user_last_activity
|
||||
|
||||
# Since we deactivate authentication from the main ApplicationController and
|
||||
# defer it to :authorize_access_api!, we need to override the bypass session
|
||||
|
@ -47,6 +48,12 @@ class GraphqlController < ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def set_user_last_activity
|
||||
return unless current_user
|
||||
|
||||
Users::ActivityService.new(current_user).execute
|
||||
end
|
||||
|
||||
def execute_multiplex
|
||||
GitlabSchema.multiplex(multiplex_queries, context: context)
|
||||
end
|
||||
|
|
|
@ -10,10 +10,6 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
|
|||
before_action :assign_ref_and_path, only: [:show]
|
||||
before_action :authorize_edit_tree!, only: [:show]
|
||||
|
||||
before_action do
|
||||
push_frontend_feature_flag(:rich_content_editor)
|
||||
end
|
||||
|
||||
def show
|
||||
@config = Gitlab::StaticSiteEditor::Config.new(@repository, @ref, @path, params[:return_url])
|
||||
end
|
||||
|
|
|
@ -17,6 +17,6 @@ class MilestoneNote < SyntheticNote
|
|||
|
||||
def note_text(html: false)
|
||||
format = milestone&.group_milestone? ? :name : :iid
|
||||
milestone.nil? ? 'removed milestone' : "changed milestone to #{milestone.to_reference(project, format: format)}"
|
||||
event.remove? ? 'removed milestone' : "changed milestone to #{milestone.to_reference(project, format: format)}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Namespace::RootStorageSize
|
||||
ALERT_USAGE_THRESHOLD = 0.5
|
||||
|
||||
def initialize(root_namespace)
|
||||
@root_namespace = root_namespace
|
||||
end
|
||||
|
@ -27,12 +25,6 @@ class Namespace::RootStorageSize
|
|||
@limit ||= Gitlab::CurrentSettings.namespace_storage_size_limit.megabytes
|
||||
end
|
||||
|
||||
def show_alert?
|
||||
return false if limit == 0
|
||||
|
||||
usage_ratio >= ALERT_USAGE_THRESHOLD
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :root_namespace
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ServiceEventEntity < Grape::Entity
|
||||
include RequestAwareEntity
|
||||
|
||||
expose :title do |event|
|
||||
event
|
||||
end
|
||||
|
||||
expose :event_field_name, as: :name
|
||||
|
||||
expose :value do |event|
|
||||
service[event_field_name]
|
||||
end
|
||||
|
||||
expose :description do |event|
|
||||
service.class.event_description(event)
|
||||
end
|
||||
|
||||
expose :field, if: -> (_, _) { event_field } do
|
||||
expose :name do |event|
|
||||
event_field[:name]
|
||||
end
|
||||
expose :value do |event|
|
||||
service.public_send(event_field[:name]) # rubocop:disable GitlabSecurity/PublicSend
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
alias_method :event, :object
|
||||
|
||||
def event_field_name
|
||||
ServicesHelper.service_event_field_name(event)
|
||||
end
|
||||
|
||||
def event_field
|
||||
@event_field ||= service.event_field(event)
|
||||
end
|
||||
|
||||
def service
|
||||
request.service
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ServiceEventSerializer < BaseSerializer
|
||||
entity ServiceEventEntity
|
||||
end
|
|
@ -4,7 +4,7 @@ module Issuable
|
|||
class CommonSystemNotesService < ::BaseService
|
||||
attr_reader :issuable
|
||||
|
||||
def execute(issuable, old_labels: [], is_update: true)
|
||||
def execute(issuable, old_labels: [], old_milestone: nil, is_update: true)
|
||||
@issuable = issuable
|
||||
|
||||
# We disable touch so that created system notes do not update
|
||||
|
@ -22,17 +22,13 @@ module Issuable
|
|||
end
|
||||
|
||||
create_due_date_note if issuable.previous_changes.include?('due_date')
|
||||
create_milestone_note if has_milestone_changes?
|
||||
create_milestone_note(old_milestone) if issuable.previous_changes.include?('milestone_id')
|
||||
create_labels_note(old_labels) if old_labels && issuable.labels != old_labels
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def has_milestone_changes?
|
||||
issuable.previous_changes.include?('milestone_id')
|
||||
end
|
||||
|
||||
def handle_time_tracking_note
|
||||
if issuable.previous_changes.include?('time_estimate')
|
||||
create_time_estimate_note
|
||||
|
@ -98,15 +94,19 @@ module Issuable
|
|||
SystemNoteService.change_time_spent(issuable, issuable.project, issuable.time_spent_user)
|
||||
end
|
||||
|
||||
def create_milestone_note
|
||||
def create_milestone_note(old_milestone)
|
||||
if milestone_changes_tracking_enabled?
|
||||
# Creates a synthetic note
|
||||
ResourceEvents::ChangeMilestoneService.new(issuable, current_user).execute
|
||||
create_milestone_change_event(old_milestone)
|
||||
else
|
||||
SystemNoteService.change_milestone(issuable, issuable.project, current_user, issuable.milestone)
|
||||
end
|
||||
end
|
||||
|
||||
def create_milestone_change_event(old_milestone)
|
||||
ResourceEvents::ChangeMilestoneService.new(issuable, current_user, old_milestone: old_milestone)
|
||||
.execute
|
||||
end
|
||||
|
||||
def milestone_changes_tracking_enabled?
|
||||
::Feature.enabled?(:track_resource_milestone_change_events, issuable.project)
|
||||
end
|
||||
|
|
|
@ -241,7 +241,8 @@ class IssuableBaseService < BaseService
|
|||
end
|
||||
|
||||
if issuable_saved
|
||||
Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: old_associations[:labels])
|
||||
Issuable::CommonSystemNotesService.new(project, current_user).execute(
|
||||
issuable, old_labels: old_associations[:labels], old_milestone: old_associations[:milestone])
|
||||
|
||||
handle_changes(issuable, old_associations: old_associations)
|
||||
|
||||
|
@ -364,7 +365,8 @@ class IssuableBaseService < BaseService
|
|||
{
|
||||
labels: issuable.labels.to_a,
|
||||
mentioned_users: issuable.mentioned_users(current_user).to_a,
|
||||
assignees: issuable.assignees.to_a
|
||||
assignees: issuable.assignees.to_a,
|
||||
milestone: issuable.try(:milestone)
|
||||
}
|
||||
associations[:total_time_spent] = issuable.total_time_spent if issuable.respond_to?(:total_time_spent)
|
||||
associations[:description] = issuable.description
|
||||
|
|
|
@ -3,45 +3,70 @@
|
|||
module Namespaces
|
||||
class CheckStorageSizeService
|
||||
include ActiveSupport::NumberHelper
|
||||
include Gitlab::Allowable
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
def initialize(namespace)
|
||||
def initialize(namespace, user)
|
||||
@root_namespace = namespace.root_ancestor
|
||||
@root_storage_size = Namespace::RootStorageSize.new(root_namespace)
|
||||
@user = user
|
||||
end
|
||||
|
||||
def execute
|
||||
return ServiceResponse.success unless Feature.enabled?(:namespace_storage_limit, root_namespace)
|
||||
return ServiceResponse.success unless root_storage_size.show_alert?
|
||||
return ServiceResponse.success if alert_level == :none
|
||||
|
||||
if root_storage_size.above_size_limit?
|
||||
ServiceResponse.error(message: above_size_limit_message, payload: payload)
|
||||
else
|
||||
ServiceResponse.success(message: info_message, payload: payload)
|
||||
ServiceResponse.success(payload: payload)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :root_namespace, :root_storage_size
|
||||
attr_reader :root_namespace, :root_storage_size, :user
|
||||
|
||||
USAGE_THRESHOLDS = {
|
||||
none: 0.0,
|
||||
info: 0.5,
|
||||
warning: 0.75,
|
||||
alert: 0.95,
|
||||
error: 1.0
|
||||
}.freeze
|
||||
|
||||
def payload
|
||||
return {} unless can?(user, :admin_namespace, root_namespace)
|
||||
|
||||
{
|
||||
current_usage_message: current_usage_message,
|
||||
usage_ratio: root_storage_size.usage_ratio
|
||||
explanation_message: explanation_message,
|
||||
usage_message: usage_message,
|
||||
alert_level: alert_level
|
||||
}
|
||||
end
|
||||
|
||||
def current_usage_message
|
||||
params = {
|
||||
usage_in_percent: number_to_percentage(root_storage_size.usage_ratio * 100, precision: 0),
|
||||
namespace_name: root_namespace.name,
|
||||
used_storage: formatted(root_storage_size.current_size),
|
||||
storage_limit: formatted(root_storage_size.limit)
|
||||
}
|
||||
s_("You reached %{usage_in_percent} of %{namespace_name}'s capacity (%{used_storage} of %{storage_limit})" % params)
|
||||
def explanation_message
|
||||
root_storage_size.above_size_limit? ? above_size_limit_message : below_size_limit_message
|
||||
end
|
||||
|
||||
def info_message
|
||||
def usage_message
|
||||
s_("You reached %{usage_in_percent} of %{namespace_name}'s capacity (%{used_storage} of %{storage_limit})" % current_usage_params)
|
||||
end
|
||||
|
||||
def alert_level
|
||||
strong_memoize(:alert_level) do
|
||||
usage_ratio = root_storage_size.usage_ratio
|
||||
current_level = USAGE_THRESHOLDS.each_key.first
|
||||
|
||||
USAGE_THRESHOLDS.each do |level, threshold|
|
||||
current_level = level if usage_ratio >= threshold
|
||||
end
|
||||
|
||||
current_level
|
||||
end
|
||||
end
|
||||
|
||||
def below_size_limit_message
|
||||
s_("If you reach 100%% storage capacity, you will not be able to: %{base_message}" % { base_message: base_message } )
|
||||
end
|
||||
|
||||
|
@ -53,6 +78,15 @@ module Namespaces
|
|||
s_("push to your repository, create pipelines, create issues or add comments. To reduce storage capacity, delete unused repositories, artifacts, wikis, issues, and pipelines.")
|
||||
end
|
||||
|
||||
def current_usage_params
|
||||
{
|
||||
usage_in_percent: number_to_percentage(root_storage_size.usage_ratio * 100, precision: 0),
|
||||
namespace_name: root_namespace.name,
|
||||
used_storage: formatted(root_storage_size.current_size),
|
||||
storage_limit: formatted(root_storage_size.limit)
|
||||
}
|
||||
end
|
||||
|
||||
def formatted(number)
|
||||
number_to_human_size(number, delimiter: ',', precision: 2)
|
||||
end
|
||||
|
|
|
@ -29,6 +29,8 @@ class PostReceiveService
|
|||
response.add_alert_message(message)
|
||||
end
|
||||
|
||||
response.add_alert_message(storage_size_limit_alert)
|
||||
|
||||
broadcast_message = BroadcastMessage.current_banner_messages&.last&.message
|
||||
response.add_alert_message(broadcast_message)
|
||||
|
||||
|
@ -74,6 +76,19 @@ class PostReceiveService
|
|||
|
||||
::MergeRequests::GetUrlsService.new(project).execute(params[:changes])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def storage_size_limit_alert
|
||||
return unless repository&.repo_type&.project?
|
||||
|
||||
payload = Namespaces::CheckStorageSizeService.new(project.namespace, user).execute.payload
|
||||
return unless payload.present?
|
||||
|
||||
alert_level = "##### #{payload[:alert_level].to_s.upcase} #####"
|
||||
|
||||
[alert_level, payload[:usage_message], payload[:explanation_message]].join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
PostReceiveService.prepend_if_ee('EE::PostReceiveService')
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
module ResourceEvents
|
||||
class ChangeMilestoneService
|
||||
attr_reader :resource, :user, :event_created_at, :milestone
|
||||
attr_reader :resource, :user, :event_created_at, :milestone, :old_milestone
|
||||
|
||||
def initialize(resource, user, created_at: Time.now)
|
||||
def initialize(resource, user, created_at: Time.now, old_milestone:)
|
||||
@resource = resource
|
||||
@user = user
|
||||
@event_created_at = created_at
|
||||
@milestone = resource&.milestone
|
||||
@old_milestone = old_milestone
|
||||
end
|
||||
|
||||
def execute
|
||||
|
@ -26,7 +27,7 @@ module ResourceEvents
|
|||
{
|
||||
user_id: user.id,
|
||||
created_at: event_created_at,
|
||||
milestone_id: milestone&.id,
|
||||
milestone_id: action == :add ? milestone&.id : old_milestone&.id,
|
||||
state: ResourceMilestoneEvent.states[resource.state],
|
||||
action: ResourceMilestoneEvent.actions[action],
|
||||
key => resource.id
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.row.prepend-top-default.append-bottom-default
|
||||
.col-lg-3
|
||||
.col-lg-4
|
||||
%h4.prepend-top-0
|
||||
= @service.title
|
||||
- [true, false].each do |value|
|
||||
|
@ -9,7 +9,7 @@
|
|||
|
||||
- if @service.respond_to?(:detailed_description)
|
||||
%p= @service.detailed_description
|
||||
.col-lg-9
|
||||
.col-lg-8
|
||||
= form_for(@service, as: :service, url: scoped_integration_path(@service), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
|
||||
= render 'shared/service_settings', form: form, service: @service
|
||||
.footer-block.row-content-block
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
- breadcrumb_title @service.title
|
||||
- add_to_breadcrumbs _('Integration Settings'), project_settings_integrations_path(@project)
|
||||
- page_title @service.title, _('Integrations')
|
||||
- @content_class = 'limit-container-width' unless fluid_layout
|
||||
|
||||
= render 'form'
|
||||
- if @web_hook_logs
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- if milestone.expired? and not milestone.closed?
|
||||
.status-box.status-box-expired.append-bottom-5 Expired
|
||||
.status-box.status-box-expired.append-bottom-5 = _('Expired')
|
||||
- if milestone.upcoming?
|
||||
.status-box.status-box-mr-merged.append-bottom-5 Upcoming
|
||||
.status-box.status-box-mr-merged.append-bottom-5 = _('Upcoming')
|
||||
- if milestone.closed?
|
||||
.status-box.status-box-closed.append-bottom-5 Closed
|
||||
.status-box.status-box-closed.append-bottom-5 = _('Closed')
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
= form_errors(@service)
|
||||
- trigger_events = Feature.enabled?(:integration_form_refactor) ? ServiceEventSerializer.new(service: @service).represent(@service.configurable_events).to_json : []
|
||||
|
||||
- if lookup_context.template_exists?('help', "projects/services/#{@service.to_param}", true)
|
||||
= render "projects/services/#{@service.to_param}/help", subject: @service
|
||||
|
@ -9,9 +10,9 @@
|
|||
|
||||
.service-settings
|
||||
.js-vue-integration-settings{ data: { show_active: @service.show_active_box?.to_s, activated: (@service.active || @service.new_record?).to_s, type: @service.to_param, merge_request_events: @service.merge_requests_events.to_s,
|
||||
commit_events: @service.commit_events.to_s, enable_comments: @service.comment_on_event_enabled.to_s, comment_detail: @service.comment_detail } }
|
||||
commit_events: @service.commit_events.to_s, enable_comments: @service.comment_on_event_enabled.to_s, comment_detail: @service.comment_detail, trigger_events: trigger_events } }
|
||||
|
||||
- if @service.configurable_events.present? && !@service.is_a?(JiraService)
|
||||
- if @service.configurable_events.present? && !@service.is_a?(JiraService) && Feature.disabled?(:integration_form_refactor)
|
||||
.form-group.row
|
||||
%label.col-form-label.col-sm-2= _('Trigger')
|
||||
|
||||
|
@ -33,15 +34,4 @@ commit_events: @service.commit_events.to_s, enable_comments: @service.comment_on
|
|||
= @service.class.event_description(event)
|
||||
|
||||
- @service.global_fields.each do |field|
|
||||
- type = field[:type]
|
||||
|
||||
- if type == 'fieldset'
|
||||
- fields = field[:fields]
|
||||
- legend = field[:legend]
|
||||
|
||||
%fieldset
|
||||
%legend= legend
|
||||
- fields.each do |subfield|
|
||||
= render 'shared/field', form: form, field: subfield
|
||||
- else
|
||||
= render 'shared/field', form: form, field: field
|
||||
= render 'shared/field', form: form, field: field
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Enable deploy token authentication for the NPM registry
|
||||
merge_request: 31264
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Allow users to star/unstar dashboards which will appear at the top of their
|
||||
dashboards options
|
||||
merge_request: 31597
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add WYSIWYG editor to the Static Site Editor
|
||||
merge_request: 31099
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Externalize i18n strings from ./app/views/shared/_milestone_expired.html.haml
|
||||
merge_request: 32121
|
||||
author: Gilang Gumilar
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'Disable Docker-in-Docker for Dependency Scanning by default'
|
||||
merge_request: 31588
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'Disable Docker-in-Docker for SAST by default'
|
||||
merge_request: 31589
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add user last_activity logging in GraphQL
|
||||
merge_request: 23063
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove detection of file in Dependency Scanning template
|
||||
merge_request: 31819
|
||||
author:
|
||||
type: fixed
|
|
@ -1,6 +1,7 @@
|
|||
require 'gitlab/testing/request_blocker_middleware'
|
||||
require 'gitlab/testing/request_inspector_middleware'
|
||||
require 'gitlab/testing/clear_process_memory_cache_middleware'
|
||||
require 'gitlab/utils'
|
||||
|
||||
Rails.application.configure do
|
||||
# Make sure the middleware is inserted first in middleware chain
|
||||
|
@ -43,7 +44,7 @@ Rails.application.configure do
|
|||
# Print deprecation notices to the stderr
|
||||
config.active_support.deprecation = :stderr
|
||||
|
||||
config.eager_load = true
|
||||
config.eager_load = Gitlab::Utils.to_boolean(ENV['GITLAB_TEST_EAGER_LOAD'], default: true)
|
||||
|
||||
config.cache_store = :null_store
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ swap:
|
|||
gitlab omnibus: Omnibus GitLab
|
||||
param: parameter
|
||||
params: parameters
|
||||
pg: PostgreSQL
|
||||
postgres: PostgreSQL
|
||||
raketask: Rake task
|
||||
raketasks: Rake tasks
|
||||
|
|
|
@ -172,11 +172,12 @@ do this manually.
|
|||
The `gitlab-ctl promote-to-primary-node` command cannot be used in conjunction with
|
||||
an external PostgreSQL database, as it can only perform changes on a **secondary**
|
||||
node with GitLab and the database on the same machine. As a result, a manual process is
|
||||
required. For example, PostgreSQL databases hosted on Amazon RDS:
|
||||
required:
|
||||
|
||||
1. Promote the replica database associated with the **secondary** site. This will
|
||||
set the database to read-write:
|
||||
- Amazon RDS - [Promoting a Read Replica to Be a Standalone DB Instance](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReadRepl.html#USER_ReadRepl.Promote)
|
||||
- Azure Database for PostgreSQL - [Stop replication](https://docs.microsoft.com/en-us/azure/postgresql/howto-read-replicas-portal#stop-replication)
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb` on every node in the **secondary** site to
|
||||
reflect its new status as **primary** by removing any lines that enabled the
|
||||
|
|
|
@ -262,7 +262,7 @@ You can login to the **secondary** node with the same credentials you used for t
|
|||
**secondary** Geo node and if Geo is enabled.
|
||||
|
||||
The initial replication, or 'backfill', will probably still be in progress. You
|
||||
can monitor the synchronization process on each geo node from the **primary**
|
||||
can monitor the synchronization process on each Geo node from the **primary**
|
||||
node's **Geo Nodes** dashboard in your browser.
|
||||
|
||||
![Geo dashboard](img/geo_node_dashboard.png)
|
||||
|
|
|
@ -38,7 +38,14 @@ Given you have a primary node set up on AWS EC2 that uses RDS.
|
|||
You can now just create a read-only replica in a different region and the
|
||||
replication process will be managed by AWS. Make sure you've set Network ACL, Subnet, and
|
||||
Security Group according to your needs, so the secondary application node can access the database.
|
||||
Skip to the [Configure secondary application node](#configure-secondary-application-nodes-to-use-the-external-read-replica) section below.
|
||||
|
||||
The following instructions detail how to create a read-only replica for common
|
||||
cloud providers:
|
||||
|
||||
- Amazon RDS - [Creating a Read Replica](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReadRepl.html#USER_ReadRepl.Create)
|
||||
- Azure Database for PostgreSQL - [Create and manage read replicas in Azure Database for PostgreSQL](https://docs.microsoft.com/en-us/azure/postgresql/howto-read-replicas-portal)
|
||||
|
||||
Once your read-only replica is set up, you can skip to [configure you secondary application node](#configure-secondary-application-nodes-to-use-the-external-read-replica).
|
||||
|
||||
#### Manually configure the primary database for replication
|
||||
|
||||
|
@ -133,6 +140,10 @@ To configure the connection to the external read-replica database and enable Log
|
|||
|
||||
gitlab_rails['db_username'] = 'gitlab'
|
||||
gitlab_rails['db_host'] = '<database_read_replica_host>'
|
||||
|
||||
# Disable the bundled Omnibus PostgreSQL, since we are
|
||||
# using an external PostgreSQL
|
||||
postgresql['enable'] = false
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure)
|
||||
|
|
|
@ -1,85 +1,101 @@
|
|||
# Geo validation tests
|
||||
|
||||
The Geo team performs manual testing and validation on common deployment configurations to ensure that Geo works when upgrading between minor GitLab versions and major PostgreSQL database versions. This section contains a journal of recent validation tests and links to the relevant issues.
|
||||
The Geo team performs manual testing and validation on common deployment configurations to ensure
|
||||
that Geo works when upgrading between minor GitLab versions and major PostgreSQL database versions.
|
||||
|
||||
## GitLab Upgrades
|
||||
This section contains a journal of recent validation tests and links to the relevant issues.
|
||||
|
||||
## GitLab upgrades
|
||||
|
||||
The following are GitLab upgrade validation tests we performed.
|
||||
|
||||
### February 2020
|
||||
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/201837)
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/201837):
|
||||
|
||||
- Description: Tested upgrading from GitLab 12.7.5 to the latest 12.8 package in a high availability configuration.
|
||||
- Outcome: Partial success because we did not run the looping pipeline during the demo to monitor downtime.
|
||||
- Description: Tested upgrading from GitLab 12.7.5 to the latest GitLab 12.8 package in a high
|
||||
availability configuration.
|
||||
- Outcome: Partial success because we did not run the looping pipeline during the demo to monitor
|
||||
downtime.
|
||||
|
||||
### January 2020
|
||||
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/200085)
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/200085):
|
||||
|
||||
- Description: Tested upgrading from GitLab 12.6.x to the latest 12.7 package in a high availability configuration.
|
||||
- Description: Tested upgrading from GitLab 12.6.x to the latest GitLab 12.7 package in a high
|
||||
availability configuration.
|
||||
- Outcome: Upgrade test was successful.
|
||||
- Follow up issues:
|
||||
- [Investigate Geo End to End Test Failures](https://gitlab.com/gitlab-org/gitlab/issues/201823)
|
||||
- [Add More Logging to Geo End to End Tests](https://gitlab.com/gitlab-org/gitlab/issues/201830)
|
||||
- [Excess Service Restarts During Zero-Downtime Upgrade](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5047)
|
||||
- [Investigate Geo end-to-end test failures](https://gitlab.com/gitlab-org/gitlab/issues/201823).
|
||||
- [Add more logging to Geo end-to-end tests](https://gitlab.com/gitlab-org/gitlab/issues/201830).
|
||||
- [Excess service restarts during zero-downtime upgrade](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5047).
|
||||
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/199836)
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/199836):
|
||||
|
||||
- Description: Tested upgrading from GitLab 12.5.7 to 12.6.6 in a high availability configuration
|
||||
- Description: Tested upgrading from GitLab 12.5.7 to GitLab 12.6.6 in a high availability
|
||||
configuration.
|
||||
- Outcome: Upgrade test was successful.
|
||||
- Follow up issue:
|
||||
[Update documentation for zero-downtime upgrades to ensure deploy node it not in use](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5046).
|
||||
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/37044):
|
||||
|
||||
- Description: Tested upgrading from GitLab 12.4.x to the latest GitLab 12.5 package in a high
|
||||
availability configuration.
|
||||
- Outcome: Upgrade test was successful.
|
||||
- Follow up issues:
|
||||
- [Update docs for zero-downtime upgrades to ensure deploy node it not in-use](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5046)
|
||||
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/37044)
|
||||
|
||||
- Description: Tested upgrading from GitLab 12.4.x to the latest 12.5 package in a high availability configuration.
|
||||
- Outcome: Upgrade test was successful.
|
||||
- Follow up issues:
|
||||
- [Investigate why http push spec failed on primary node](https://gitlab.com/gitlab-org/gitlab/issues/199825)
|
||||
- [Investigate if docs should be modified to include refresh foreign tables task](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5041)
|
||||
- [Investigate why HTTP push spec failed on primary node](https://gitlab.com/gitlab-org/gitlab/issues/199825).
|
||||
- [Investigate if documentation should be modified to include refresh foreign tables task](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5041).
|
||||
|
||||
### October 2019
|
||||
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/35262)
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/35262):
|
||||
|
||||
- Description: Tested uprgading from GitLab 12.3.5 to 12.4.1 in a high availability configuration.
|
||||
- Description: Tested upgrading from GitLab 12.3.5 to GitLab 12.4.1 in a high availability configuration.
|
||||
- Outcome: Upgrade test was successful.
|
||||
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/32437)
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/32437):
|
||||
|
||||
- Description: Tested upgrading from GitLab 12.2.8 to 12.3.5
|
||||
- Description: Tested upgrading from GitLab 12.2.8 to GitLab 12.3.5.
|
||||
- Outcome: Upgrade test was successful.
|
||||
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/32435)
|
||||
[Upgrade Geo HA installation](https://gitlab.com/gitlab-org/gitlab/-/issues/32435):
|
||||
|
||||
- Description: Tested upgrading from GitLab 12.1.9 to 12.2.8
|
||||
- Description: Tested upgrading from GitLab 12.1.9 to GitLab 12.2.8.
|
||||
- Outcome: Partial success due to possible misconfiguration issues.
|
||||
|
||||
## PostgreSQL Upgrades
|
||||
## PostgreSQL upgrades
|
||||
|
||||
The following are PostgreSQL upgrade validation tests we performed.
|
||||
|
||||
### April 2020
|
||||
|
||||
[PostgreSQL 11 upgrade procedure for GEO installations](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4975)
|
||||
[PostgreSQL 11 upgrade procedure for Geo installations](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4975):
|
||||
|
||||
- Description: Prior to making PostgreSQL 11 the default version of PG in GitLab 12.10, we tested upgrading to PG 11 in Geo deployments on GitLab 12.9.
|
||||
- Outcome: Partially successful. Issues were discovered in HA configurations with a separate tracking database and concerns were raised about allowing automatic upgrades when Geo enabled.
|
||||
- Description: Prior to making PostgreSQL 11 the default version of PostgreSQL in GitLab 12.10, we
|
||||
tested upgrading to PostgreSQL 11 in Geo deployments on GitLab 12.9.
|
||||
- Outcome: Partially successful. Issues were discovered in HA configurations with a separate
|
||||
tracking database and concerns were raised about allowing automatic upgrades when Geo enabled.
|
||||
- Follow up issues:
|
||||
- [replicate-geo-database incorrectly tries to backup repos](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5241)
|
||||
- [pg-upgrade fails to upgrade a standalone Geo tracking DB](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5242)
|
||||
- [revert-pg-upgrade fails to downgrade a Geo secondary’s standalone tracking DB’s PG data](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5243)
|
||||
- [Timeout error on Geo secondary read-replica near the end of `gitlab-ctl pg-upgrade`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5235)
|
||||
- [`replicate-geo-database` incorrectly tries to back up repositories](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5241).
|
||||
- [`pg-upgrade` fails to upgrade a standalone Geo tracking database](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5242).
|
||||
- [`revert-pg-upgrade` fails to downgrade the PostgreSQL data of a Geo secondary’s standalone tracking database](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5243).
|
||||
- [Timeout error on Geo secondary read-replica near the end of `gitlab-ctl pg-upgrade`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5235).
|
||||
|
||||
[Verify GEO installation with PostgreSQL 11](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4971)
|
||||
[Verify Geo installation with PostgreSQL 11](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4971):
|
||||
|
||||
- Description: Prior to making PostgreSQL 11 the default version of PG in GitLab 12.10, we tested fresh installations of GitLab 12.9 with Geo, installed with PG 11.
|
||||
- Description: Prior to making PostgreSQL 11 the default version of PostgreSQL in GitLab 12.10, we
|
||||
tested fresh installations of GitLab 12.9 with Geo installed with PostgreSQL 11.
|
||||
- Outcome: Installation test was successful.
|
||||
|
||||
### September 2019
|
||||
|
||||
[Test and validate PostgreSQL 10.0 upgrade for Geo](https://gitlab.com/gitlab-org/gitlab/issues/12092)
|
||||
[Test and validate PostgreSQL 10.0 upgrade for Geo](https://gitlab.com/gitlab-org/gitlab/issues/12092):
|
||||
|
||||
- Description: With the 12.0 release, GitLab required an upgrade to PostgreSQL 10.0. We tested various upgrade scenarios from GitLab 11.11.5 through to 12.1.8.
|
||||
- Description: With the 12.0 release, GitLab required an upgrade to PostgreSQL 10.0. We tested
|
||||
various upgrade scenarios from GitLab 11.11.5 through to GitLab 12.1.8.
|
||||
- Outcome: Multiple issues were found when upgrading and addressed in follow-up issues.
|
||||
- Follow up issues:
|
||||
- [`gitlab-ctl` reconfigure fails on Redis node in HA Geo setup](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4706)
|
||||
- [HA with Geo upgrade from 12.0.9 to 12.1.9 does not upgrade PostgreSQL](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4705)
|
||||
- [refresh foreign tables fails on app server in HA setup after upgrade to 12.1.9](https://gitlab.com/gitlab-org/gitlab/-/issues/32119)
|
||||
- [`gitlab-ctl` reconfigure fails on Redis node in HA Geo setup](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4706).
|
||||
- [HA with Geo upgrade from 12.0.9 to 12.1.9 does not upgrade PostgreSQL](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4705).
|
||||
- [Refresh foreign tables fails on app server in HA setup after upgrade to 12.1.9](https://gitlab.com/gitlab-org/gitlab/-/issues/32119).
|
||||
|
|
|
@ -73,7 +73,7 @@ from [owasp.org](https://owasp.org/).
|
|||
- Nothing Geo-specific. Any user where `admin: true` is set in the database is
|
||||
considered an admin with super-user privileges.
|
||||
- See also: [more granular access control](https://gitlab.com/gitlab-org/gitlab-foss/issues/32730)
|
||||
(not geo-specific)
|
||||
(not Geo-specific).
|
||||
- Much of Geo’s integration (database replication, for instance) must be
|
||||
configured with the application, typically by system administrators.
|
||||
|
||||
|
|
|
@ -860,6 +860,8 @@ which Geo expects to have access to. It usually means, either:
|
|||
|
||||
- An unsupported replication method was used (for example, logical replication).
|
||||
- The instructions to setup a [Geo database replication](database.md) were not followed correctly.
|
||||
- Your database connection details are incorrect, that is you have specified the wrong
|
||||
user in your `/etc/gitlab/gitlab.rb` file.
|
||||
|
||||
A common source of confusion with **secondary** nodes is that it requires two separate
|
||||
PostgreSQL instances:
|
||||
|
|
|
@ -125,7 +125,7 @@ otherwise the networks will become a single point of failure.
|
|||
|
||||
#### Architecture
|
||||
|
||||
![PG HA Architecture](img/pg_ha_architecture.png)
|
||||
![PostgreSQL HA Architecture](img/pg_ha_architecture.png)
|
||||
|
||||
Database nodes run two services with PostgreSQL:
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ This section is for links to information elsewhere in the GitLab documentation.
|
|||
|
||||
- [More about external PostgreSQL](../external_database.md)
|
||||
|
||||
- [Running GEO with external PostgreSQL](../geo/replication/external_database.md)
|
||||
- [Running Geo with external PostgreSQL](../geo/replication/external_database.md)
|
||||
|
||||
- [Upgrades when running PostgreSQL configured for HA.](https://docs.gitlab.com/omnibus/settings/database.html#upgrading-a-gitlab-ha-cluster)
|
||||
|
||||
|
@ -71,7 +71,7 @@ This section is for links to information elsewhere in the GitLab documentation.
|
|||
HINT: Free one or increase max_replication_slots.
|
||||
```
|
||||
|
||||
- GEO [replication errors](../geo/replication/troubleshooting.md#fixing-replication-errors) including:
|
||||
- Geo [replication errors](../geo/replication/troubleshooting.md#fixing-replication-errors) including:
|
||||
|
||||
```plaintext
|
||||
ERROR: replication slots can only be used if max_replication_slots > 0
|
||||
|
@ -83,11 +83,11 @@ This section is for links to information elsewhere in the GitLab documentation.
|
|||
PANIC: could not write to file ‘pg_xlog/xlogtemp.123’: No space left on device
|
||||
```
|
||||
|
||||
- [Checking GEO configuration](../geo/replication/troubleshooting.md#checking-configuration) including
|
||||
- [Checking Geo configuration](../geo/replication/troubleshooting.md#checking-configuration) including
|
||||
- reconfiguring hosts/ports
|
||||
- checking and fixing user/password mappings
|
||||
|
||||
- [Common GEO errors](../geo/replication/troubleshooting.md#fixing-common-errors)
|
||||
- [Common Geo errors](../geo/replication/troubleshooting.md#fixing-common-errors)
|
||||
|
||||
## Support topics
|
||||
|
||||
|
|
|
@ -1409,6 +1409,7 @@ The activities that update the timestamp are:
|
|||
- User logging in into GitLab
|
||||
- User visiting pages related to Dashboards, Projects, Issues, and Merge Requests ([introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/54947) in GitLab 11.8)
|
||||
- User using the API
|
||||
- User using the GraphQL API
|
||||
|
||||
By default, it shows the activity for all users in the last 6 months, but this can be
|
||||
amended by using the `from` parameter.
|
||||
|
|
|
@ -64,7 +64,7 @@ It picks reviewers and maintainers from the list at the
|
|||
page, with these behaviors:
|
||||
|
||||
1. It will not pick people whose [GitLab status](../user/profile/index.md#current-status)
|
||||
contains the string 'OOO'.
|
||||
contains the string 'OOO', or the emoji is `:palm_tree:` or `:beach:`.
|
||||
1. [Trainee maintainers](https://about.gitlab.com/handbook/engineering/workflow/code-review/#trainee-maintainer)
|
||||
are three times as likely to be picked as other reviewers.
|
||||
1. It always picks the same reviewers and maintainers for the same
|
||||
|
|
|
@ -153,7 +153,7 @@ request, be sure to start the `dont-interrupt-me` job before pushing.
|
|||
|
||||
### Current versions testing
|
||||
|
||||
| Where? | PG version |
|
||||
| Where? | PostgreSQL version |
|
||||
| ------ | ------ |
|
||||
| MRs | 11 |
|
||||
| `master` (non-scheduled pipelines) | 11 |
|
||||
|
@ -163,7 +163,7 @@ request, be sure to start the `dont-interrupt-me` job before pushing.
|
|||
|
||||
We follow the [PostgreSQL versions shipped with Omnibus GitLab](https://docs.gitlab.com/omnibus/package-information/postgresql_versions.html):
|
||||
|
||||
| PG version | 12.10 (April 2020) | 13.0 (May 2020) | 13.1 (June 2020) | 13.2 (July 2020) | 13.3 (August 2020) | 13.4, 13.5 | 13.6 (November 2020) | 14.0 (May 2021?) |
|
||||
| PostgreSQL version | 12.10 (April 2020) | 13.0 (May 2020) | 13.1 (June 2020) | 13.2 (July 2020) | 13.3 (August 2020) | 13.4, 13.5 | 13.6 (November 2020) | 14.0 (May 2021?) |
|
||||
| ------ | ------------------ | --------------- | ---------------- | ---------------- | ------------------ | ------------ | -------------------- | ---------------- |
|
||||
| PG9.6 | MRs/`master`/`2-hour`/`nightly` | - | - | - | - | - | - | - |
|
||||
| PG10 | `nightly` | - | - | - | - | - | - | - |
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
# Jenkins CI service **(STARTER)**
|
||||
|
||||
NOTE: **Note:**
|
||||
This documentation focuses only on how to **configure** a Jenkins *integration* with
|
||||
GitLab. Learn how to **migrate** from Jenkins to GitLab CI/CD in our
|
||||
[Migrating from Jenkins](../ci/jenkins/index.md) documentation.
|
||||
|
||||
From GitLab, you can trigger a Jenkins build when you push code to a repository, or when a merge
|
||||
request is created. In return, Jenkins shows the pipeline status on merge requests widgets and
|
||||
on the GitLab project's home page.
|
||||
|
|
|
@ -26,3 +26,4 @@ How do we measure the activity of users? GitLab considers a user active if:
|
|||
- The user has Git activity (whether push or pull).
|
||||
- The user visits pages related to Dashboards, Projects, Issues, and Merge Requests ([introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/54947) in GitLab 11.8).
|
||||
- The user uses the API
|
||||
- The user uses the GraphQL API
|
||||
|
|
|
@ -100,14 +100,15 @@ configure GitLab as a remote registry.
|
|||
|
||||
If a project is private or you want to upload an NPM package to GitLab,
|
||||
credentials will need to be provided for authentication. [Personal access tokens](../../profile/personal_access_tokens.md)
|
||||
and [deploy tokens](../../project/deploy_tokens/index.md)
|
||||
are preferred, but support is available for [OAuth tokens](../../../api/oauth2.md#resource-owner-password-credentials-flow).
|
||||
|
||||
CAUTION: **2FA is only supported with personal access tokens:**
|
||||
If you have 2FA enabled, you need to use a [personal access token](../../profile/personal_access_tokens.md) with OAuth headers with the scope set to `api`. Standard OAuth tokens won't be able to authenticate to the GitLab NPM Registry.
|
||||
CAUTION: **Two-factor authentication (2FA) is only supported with personal access tokens:**
|
||||
If you have 2FA enabled, you need to use a [personal access token](../../profile/personal_access_tokens.md) with OAuth headers with the scope set to `api` or a [deploy token](../../project/deploy_tokens/index.md) with `read_package_registry` or `write_package_registry` scopes. Standard OAuth tokens won't be able to authenticate to the GitLab NPM Registry.
|
||||
|
||||
### Authenticating with a personal access token
|
||||
### Authenticating with a personal access token or deploy token
|
||||
|
||||
To authenticate with a [personal access token](../../profile/personal_access_tokens.md),
|
||||
To authenticate with a [personal access token](../../profile/personal_access_tokens.md) or [deploy token](../../project/deploy_tokens/index.md),
|
||||
set your NPM configuration:
|
||||
|
||||
```shell
|
||||
|
@ -125,7 +126,7 @@ npm config set '//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_au
|
|||
```
|
||||
|
||||
Replace `<your_project_id>` with your project ID which can be found on the home page
|
||||
of your project and `<your_token>` with your personal access token.
|
||||
of your project and `<your_token>` with your personal access token or deploy token.
|
||||
|
||||
If you have a self-managed GitLab installation, replace `gitlab.com` with your
|
||||
domain name.
|
||||
|
@ -160,7 +161,7 @@ Then, you could run `npm publish` either locally or via GitLab CI/CD:
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9104) in GitLab Premium 12.5.
|
||||
|
||||
If you’re using NPM with GitLab CI/CD, a CI job token can be used instead of a personal access token.
|
||||
If you’re using NPM with GitLab CI/CD, a CI job token can be used instead of a personal access token or deploy token.
|
||||
The token will inherit the permissions of the user that generates the pipeline.
|
||||
|
||||
Add a corresponding section to your `.npmrc` file:
|
||||
|
@ -286,7 +287,7 @@ page.
|
|||
## Publishing a package with CI/CD
|
||||
|
||||
To work with NPM commands within [GitLab CI/CD](./../../../ci/README.md), you can use
|
||||
`CI_JOB_TOKEN` in place of the personal access token in your commands.
|
||||
`CI_JOB_TOKEN` in place of the personal access token or deploy token in your commands.
|
||||
|
||||
A simple example `.gitlab-ci.yml` file for publishing NPM packages:
|
||||
|
||||
|
@ -323,7 +324,7 @@ info Visit https://classic.yarnpkg.com/en/docs/cli/install for documentation abo
|
|||
```
|
||||
|
||||
In this case, try adding this to your `.npmrc` file (and replace `<your_token>`
|
||||
with your personal access token):
|
||||
with your personal access token or deploy token):
|
||||
|
||||
```text
|
||||
//gitlab.com/api/v4/projects/:_authToken=<your_token>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
|
@ -5,7 +5,8 @@ description: "The static site editor enables users to edit content on static web
|
|||
|
||||
# Static Site Editor
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28758) in GitLab 12.10.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28758) in GitLab 12.10.
|
||||
> - WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214559) in GitLab 13.0.
|
||||
|
||||
Static Site Editor enables users to edit content on static websites without
|
||||
prior knowledge of the underlying templating language, site architecture, or
|
||||
|
@ -44,7 +45,7 @@ When clicking it, GitLab will open up an editor window from which the content
|
|||
can be directly edited. When you're ready, you can submit your changes in a
|
||||
click of a button:
|
||||
|
||||
![Static Site Editor](img/static_site_editor_v12_10.png)
|
||||
![Static Site Editor](img/wysiwyg_editor_v13_0.png)
|
||||
|
||||
When an editor submits their changes, in the background, GitLab automatically
|
||||
creates a new branch, commits their changes, and opens a merge request. The
|
||||
|
@ -79,7 +80,8 @@ company and a new feature has been added to the company product.
|
|||
1. You are assigned the task of updating the documentation.
|
||||
1. You visit a page and see content that needs to be edited.
|
||||
1. Click the **Edit this page** button on the production site.
|
||||
1. The file is opened in the Static Site Editor.
|
||||
1. The file is opened in the Static Site Editor in **WYSIWYG** mode. If you wish to edit the raw Markdown
|
||||
instead, you can toggle the **Markdown** mode in the bottom-right corner.
|
||||
1. You edit the file right there and click **Submit changes**.
|
||||
1. A new merge request is automatically created and you assign it to your colleague for review.
|
||||
|
||||
|
|
|
@ -107,9 +107,12 @@ module Gitlab
|
|||
def deploy_token_from_request
|
||||
return unless route_authentication_setting[:deploy_token_allowed]
|
||||
|
||||
token = current_request.env[DEPLOY_TOKEN_HEADER].presence
|
||||
token = current_request.env[DEPLOY_TOKEN_HEADER].presence || parsed_oauth_token
|
||||
|
||||
DeployToken.active.find_by_token(token)
|
||||
deploy_token = DeployToken.active.find_by_token(token)
|
||||
@current_authenticated_deploy_token = deploy_token # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
deploy_token
|
||||
end
|
||||
|
||||
def find_runner_from_token
|
||||
|
@ -122,6 +125,9 @@ module Gitlab
|
|||
end
|
||||
|
||||
def validate_access_token!(scopes: [])
|
||||
# return early if we've already authenticated via a deploy token
|
||||
return if @current_authenticated_deploy_token.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
return unless access_token
|
||||
|
||||
case AccessTokenValidationService.new(access_token, request: request).validate(scopes: scopes)
|
||||
|
|
|
@ -14,7 +14,7 @@ variables:
|
|||
|
||||
DS_DEFAULT_ANALYZERS: "bundler-audit, retire.js, gemnasium, gemnasium-maven, gemnasium-python"
|
||||
DS_MAJOR_VERSION: 2
|
||||
DS_DISABLE_DIND: "false"
|
||||
DS_DISABLE_DIND: "true"
|
||||
|
||||
dependency_scanning:
|
||||
stage: test
|
||||
|
@ -106,7 +106,6 @@ gemnasium-dependency_scanning:
|
|||
$DS_DEFAULT_ANALYZERS =~ /gemnasium([^-]|$)/
|
||||
exists:
|
||||
- 'Gemfile.lock'
|
||||
- 'Pipfile.lock'
|
||||
- 'composer.lock'
|
||||
- 'gems.locked'
|
||||
- 'go.sum'
|
||||
|
|
|
@ -14,7 +14,7 @@ variables:
|
|||
|
||||
SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, tslint, secrets, sobelow, pmd-apex, kubesec"
|
||||
SAST_ANALYZER_IMAGE_TAG: 2
|
||||
SAST_DISABLE_DIND: "false"
|
||||
SAST_DISABLE_DIND: "true"
|
||||
SCAN_KUBERNETES_MANIFESTS: "false"
|
||||
|
||||
sast:
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'cgi'
|
||||
require 'set'
|
||||
|
||||
module Gitlab
|
||||
module Danger
|
||||
class Teammate
|
||||
attr_reader :name, :username, :role, :projects
|
||||
|
||||
AT_CAPACITY_EMOJI = Set.new(%w[red_circle]).freeze
|
||||
OOO_EMOJI = Set.new(%w[
|
||||
palm_tree
|
||||
beach beach_umbrella beach_with_umbrella
|
||||
]).freeze
|
||||
|
||||
def initialize(options = {})
|
||||
@username = options['username']
|
||||
@name = options['name'] || @username
|
||||
|
@ -37,10 +44,14 @@ module Gitlab
|
|||
end
|
||||
|
||||
def status
|
||||
api_endpoint = "https://gitlab.com/api/v4/users/#{CGI.escape(username)}/status"
|
||||
@status ||= Gitlab::Danger::RequestHelper.http_get_json(api_endpoint)
|
||||
rescue Gitlab::Danger::RequestHelper::HTTPError, JSON::ParserError
|
||||
nil # better no status than a crashing Danger
|
||||
return @status if defined?(@status)
|
||||
|
||||
@status ||=
|
||||
begin
|
||||
Gitlab::Danger::RequestHelper.http_get_json(status_api_endpoint)
|
||||
rescue Gitlab::Danger::RequestHelper::HTTPError, JSON::ParserError
|
||||
nil # better no status than a crashing Danger
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
|
@ -50,14 +61,22 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def status_api_endpoint
|
||||
"https://gitlab.com/api/v4/users/#{CGI.escape(username)}/status"
|
||||
end
|
||||
|
||||
def status_emoji
|
||||
status&.dig("emoji")
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
def out_of_office?
|
||||
status&.dig("message")&.match?(/OOO/i) || false
|
||||
status&.dig("message")&.match?(/OOO/i) || OOO_EMOJI.include?(status_emoji)
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
def has_capacity?
|
||||
status&.dig("emoji") != 'red_circle'
|
||||
!AT_CAPACITY_EMOJI.include?(status_emoji)
|
||||
end
|
||||
|
||||
def has_capability?(project, category, kind, labels)
|
||||
|
|
|
@ -157,8 +157,8 @@ module Gitlab
|
|||
Rails.env.test? ? Rails.root.join('tmp/tests') : Gitlab.config.gitlab.user_home
|
||||
end
|
||||
|
||||
def checkout_or_clone_version(version:, repo:, target_dir:)
|
||||
clone_repo(repo, target_dir) unless Dir.exist?(target_dir)
|
||||
def checkout_or_clone_version(version:, repo:, target_dir:, clone_opts: [])
|
||||
clone_repo(repo, target_dir, clone_opts: clone_opts) unless Dir.exist?(target_dir)
|
||||
checkout_version(get_version(version), target_dir)
|
||||
end
|
||||
|
||||
|
@ -171,8 +171,8 @@ module Gitlab
|
|||
"v#{component_version}"
|
||||
end
|
||||
|
||||
def clone_repo(repo, target_dir)
|
||||
run_command!(%W[#{Gitlab.config.git.bin_path} clone -- #{repo} #{target_dir}])
|
||||
def clone_repo(repo, target_dir, clone_opts: [])
|
||||
run_command!(%W[#{Gitlab.config.git.bin_path} clone] + clone_opts + %W[-- #{repo} #{target_dir}])
|
||||
end
|
||||
|
||||
def checkout_version(version, target_dir)
|
||||
|
|
|
@ -75,12 +75,12 @@ module Gitlab
|
|||
str.gsub(/\r?\n/, '')
|
||||
end
|
||||
|
||||
def to_boolean(value)
|
||||
def to_boolean(value, default: nil)
|
||||
return value if [true, false].include?(value)
|
||||
return true if value =~ /^(true|t|yes|y|1|on)$/i
|
||||
return false if value =~ /^(false|f|no|n|0|off)$/i
|
||||
|
||||
nil
|
||||
default
|
||||
end
|
||||
|
||||
def boolean_to_yes_no(bool)
|
||||
|
|
|
@ -12,7 +12,7 @@ module SystemCheck
|
|||
def show_error
|
||||
try_fixing_it(
|
||||
"Please migrate all projects to hashed storage#{' on the primary' if Gitlab.ee? && Gitlab::Geo.secondary?}",
|
||||
"as legacy storage is deprecated in 13.0 and support will be removed in 13.4."
|
||||
"as legacy storage is deprecated in 13.0 and support will be removed in 14.0."
|
||||
)
|
||||
|
||||
for_more_information('doc/administration/repository_storage_types.md')
|
||||
|
|
|
@ -13,7 +13,7 @@ Usage: rake "gitlab:gitaly:install[/installation/dir,/storage/path]")
|
|||
|
||||
version = Gitlab::GitalyClient.expected_server_version
|
||||
|
||||
checkout_or_clone_version(version: version, repo: args.repo, target_dir: args.dir)
|
||||
checkout_or_clone_version(version: version, repo: args.repo, target_dir: args.dir, clone_opts: %w[--depth 1])
|
||||
|
||||
command = []
|
||||
_, status = Gitlab::Popen.popen(%w[which gmake])
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace :gitlab do
|
|||
gitlab_url += '/' unless gitlab_url.end_with?('/')
|
||||
target_dir = Gitlab.config.gitlab_shell.path
|
||||
|
||||
checkout_or_clone_version(version: default_version, repo: args.repo, target_dir: target_dir)
|
||||
checkout_or_clone_version(version: default_version, repo: args.repo, target_dir: target_dir, clone_opts: %w[--depth 1])
|
||||
|
||||
# Make sure we're on the right tag
|
||||
Dir.chdir(target_dir) do
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace :gitlab do
|
|||
|
||||
version = Gitlab::Workhorse.version
|
||||
|
||||
checkout_or_clone_version(version: version, repo: args.repo, target_dir: args.dir)
|
||||
checkout_or_clone_version(version: version, repo: args.repo, target_dir: args.dir, clone_opts: %w[--depth 1])
|
||||
|
||||
_, status = Gitlab::Popen.popen(%w[which gmake])
|
||||
command = status.zero? ? 'gmake' : 'make'
|
||||
|
|
|
@ -3797,6 +3797,9 @@ msgstr ""
|
|||
msgid "Changing group path can have unintended side effects."
|
||||
msgstr ""
|
||||
|
||||
msgid "Channel handle (e.g. town-square)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Charts"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9719,15 +9722,15 @@ msgstr ""
|
|||
msgid "Geo"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo Designs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo Nodes"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo Nodes|Cannot remove a primary node if there is a secondary node"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo Replication"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo Settings"
|
||||
msgstr ""
|
||||
|
||||
|
@ -10019,6 +10022,9 @@ msgstr ""
|
|||
msgid "Geo|Reverify all"
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
|
||||
msgstr ""
|
||||
|
||||
msgid "Geo|Status"
|
||||
msgstr ""
|
||||
|
||||
|
@ -13474,6 +13480,9 @@ msgstr ""
|
|||
msgid "Metrics|Refresh dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Metrics|Star dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Metrics|There was an error creating the dashboard."
|
||||
msgstr ""
|
||||
|
||||
|
@ -13510,6 +13519,9 @@ msgstr ""
|
|||
msgid "Metrics|Unit label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Metrics|Unstar dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Metrics|Used as a title for the chart"
|
||||
msgstr ""
|
||||
|
||||
|
@ -17705,6 +17717,9 @@ msgstr ""
|
|||
msgid "Replaces the clone URL root."
|
||||
msgstr ""
|
||||
|
||||
msgid "Replication"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reply by email"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ module GitalyTest
|
|||
'HOME' => File.expand_path('tmp/tests'),
|
||||
'GEM_PATH' => Gem.path.join(':'),
|
||||
'BUNDLE_APP_CONFIG' => File.join(File.dirname(gemfile), '.bundle/config'),
|
||||
'BUNDLE_FLAGS' => "--jobs=4 --retry=3",
|
||||
'BUNDLE_FLAGS' => "--jobs=4 --retry=3 --quiet",
|
||||
'BUNDLE_INSTALL_FLAGS' => nil,
|
||||
'BUNDLE_GEMFILE' => gemfile,
|
||||
'RUBYOPT' => nil,
|
||||
|
|
|
@ -6,12 +6,17 @@ export BUNDLE_INSTALL_FLAGS="--without=production --jobs=$(nproc) --path=vendor
|
|||
|
||||
if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
|
||||
bundle --version
|
||||
bundle install --clean $BUNDLE_INSTALL_FLAGS && bundle check
|
||||
run_timed_command "bundle install --clean ${BUNDLE_INSTALL_FLAGS}"
|
||||
run_timed_command "bundle check"
|
||||
# When we test multiple versions of PG in the same pipeline, we have a single `setup-test-env`
|
||||
# job but the `pg` gem needs to be rebuilt since it includes extensions (https://guides.rubygems.org/gems-with-extensions).
|
||||
# Uncomment the following line if multiple versions of PG are tested in the same pipeline.
|
||||
# run_timed_command "bundle pristine pg"
|
||||
fi
|
||||
|
||||
# Only install knapsack after bundle install! Otherwise oddly some native
|
||||
# gems could not be found under some circumstance. No idea why, hours wasted.
|
||||
retry gem install knapsack --no-document
|
||||
run_timed_command "gem install knapsack --no-document"
|
||||
|
||||
cp config/gitlab.yml.example config/gitlab.yml
|
||||
sed -i 's/bin_path: \/usr\/bin\/git/bin_path: \/usr\/local\/bin\/git/' config/gitlab.yml
|
||||
|
|
|
@ -18,11 +18,8 @@ function setup_db_user_only() {
|
|||
}
|
||||
|
||||
function setup_db() {
|
||||
setup_db_user_only
|
||||
|
||||
bundle exec rake db:drop db:create db:structure:load db:migrate
|
||||
|
||||
bundle exec rake gitlab:db:setup_ee
|
||||
run_timed_command "setup_db_user_only"
|
||||
run_timed_command "bundle exec rake db:drop db:create db:structure:load db:migrate gitlab:db:setup_ee"
|
||||
}
|
||||
|
||||
function install_api_client_dependencies_with_apk() {
|
||||
|
@ -38,6 +35,24 @@ function install_gitlab_gem() {
|
|||
gem install gitlab --no-document --version 4.13.0
|
||||
}
|
||||
|
||||
function run_timed_command() {
|
||||
local cmd="${1}"
|
||||
local start=$(date +%s)
|
||||
echosuccess "\$ ${cmd}"
|
||||
eval "${cmd}"
|
||||
local ret=$?
|
||||
local end=$(date +%s)
|
||||
local runtime=$((end-start))
|
||||
|
||||
if [[ $ret -eq 0 ]]; then
|
||||
echosuccess "==> '${cmd}' succeeded in ${runtime} seconds."
|
||||
return 0
|
||||
else
|
||||
echoerr "==> '${cmd}' failed (${ret}) in ${runtime} seconds."
|
||||
return $ret
|
||||
fi
|
||||
}
|
||||
|
||||
function echoerr() {
|
||||
local header="${2}"
|
||||
|
||||
|
@ -58,6 +73,16 @@ function echoinfo() {
|
|||
fi
|
||||
}
|
||||
|
||||
function echosuccess() {
|
||||
local header="${2}"
|
||||
|
||||
if [ -n "${header}" ]; then
|
||||
printf "\n\033[0;32m** %s **\n\033[0m" "${1}" >&2;
|
||||
else
|
||||
printf "\033[0;32m%s\n\033[0m" "${1}" >&2;
|
||||
fi
|
||||
}
|
||||
|
||||
function get_job_id() {
|
||||
local job_name="${1}"
|
||||
local query_string="${2:+&${2}}"
|
||||
|
|
|
@ -32,7 +32,7 @@ describe GraphqlController do
|
|||
|
||||
describe 'POST #execute' do
|
||||
context 'when user is logged in' do
|
||||
let(:user) { create(:user) }
|
||||
let(:user) { create(:user, last_activity_on: Date.yesterday) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
|
@ -56,6 +56,19 @@ describe GraphqlController do
|
|||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
expect(response).to render_template('errors/access_denied')
|
||||
end
|
||||
|
||||
it 'updates the users last_activity_on field' do
|
||||
expect { post :execute }.to change { user.reload.last_activity_on }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user uses an API token' do
|
||||
let(:user) { create(:user, last_activity_on: Date.yesterday) }
|
||||
let(:token) { create(:personal_access_token, user: user, scopes: [:api]) }
|
||||
|
||||
it 'updates the users last_activity_on field' do
|
||||
expect { post :execute, params: { access_token: token.token } }.to change { user.reload.last_activity_on }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not logged in' do
|
||||
|
|
|
@ -158,6 +158,13 @@ FactoryBot.define do
|
|||
token { 'test_token' }
|
||||
end
|
||||
|
||||
factory :slack_service do
|
||||
project
|
||||
active { true }
|
||||
webhook { 'https://slack.service.url' }
|
||||
type { 'SlackService' }
|
||||
end
|
||||
|
||||
# this is for testing storing values inside properties, which is deprecated and will be removed in
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/29404
|
||||
trait :without_properties_callback do
|
||||
|
|
|
@ -212,12 +212,12 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
|
|||
expect(current_settings.hide_third_party_offers).to be true
|
||||
end
|
||||
|
||||
it 'Change Slack Notifications Service template settings' do
|
||||
it 'Change Slack Notifications Service template settings', :js do
|
||||
first(:link, 'Service Templates').click
|
||||
click_link 'Slack notifications'
|
||||
fill_in 'Webhook', with: 'http://localhost'
|
||||
fill_in 'Username', with: 'test_user'
|
||||
fill_in 'service_push_channel', with: '#test_channel'
|
||||
fill_in 'service[push_channel]', with: '#test_channel'
|
||||
page.check('Notify only broken pipelines')
|
||||
page.select 'All branches', from: 'Branches to be notified'
|
||||
|
||||
|
@ -231,10 +231,10 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
|
|||
expect(page.all('input[type=checkbox]')).to all(be_checked)
|
||||
expect(find_field('Webhook').value).to eq 'http://localhost'
|
||||
expect(find_field('Username').value).to eq 'test_user'
|
||||
expect(find('#service_push_channel').value).to eq '#test_channel'
|
||||
expect(find('[name="service[push_channel]"]').value).to eq '#test_channel'
|
||||
end
|
||||
|
||||
it 'defaults Deployment events to false for chat notification template settings' do
|
||||
it 'defaults Deployment events to false for chat notification template settings', :js do
|
||||
first(:link, 'Service Templates').click
|
||||
click_link 'Slack notifications'
|
||||
|
||||
|
@ -500,13 +500,13 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
|
|||
def check_all_events
|
||||
page.check('Push')
|
||||
page.check('Issue')
|
||||
page.check('Confidential issue')
|
||||
page.check('Merge request')
|
||||
page.check('Confidential Issue')
|
||||
page.check('Merge Request')
|
||||
page.check('Note')
|
||||
page.check('Confidential note')
|
||||
page.check('Tag push')
|
||||
page.check('Confidential Note')
|
||||
page.check('Tag Push')
|
||||
page.check('Pipeline')
|
||||
page.check('Wiki page')
|
||||
page.check('Wiki Page')
|
||||
page.check('Deployment')
|
||||
end
|
||||
|
||||
|
|
|
@ -209,6 +209,33 @@ describe "User browses files" do
|
|||
end
|
||||
end
|
||||
|
||||
context "when browsing a `Ääh-test-utf-8` branch", :js do
|
||||
before do
|
||||
project.repository.create_branch('Ääh-test-utf-8', project.repository.root_ref)
|
||||
visit(project_tree_path(project, "Ääh-test-utf-8"))
|
||||
end
|
||||
|
||||
it "shows files from a repository" do
|
||||
expect(page).to have_content("VERSION")
|
||||
.and have_content(".gitignore")
|
||||
.and have_content("LICENSE")
|
||||
|
||||
click_link("files")
|
||||
|
||||
page.within('.repo-breadcrumb') do
|
||||
expect(page).to have_link('files')
|
||||
end
|
||||
|
||||
click_link("html")
|
||||
|
||||
page.within('.repo-breadcrumb') do
|
||||
expect(page).to have_link('html')
|
||||
end
|
||||
|
||||
expect(page).to have_link('500.html')
|
||||
end
|
||||
end
|
||||
|
||||
context "when browsing a `test-#` branch", :js do
|
||||
before do
|
||||
project.repository.create_branch('test-#', project.repository.root_ref)
|
||||
|
|
|
@ -18,7 +18,10 @@ describe('ActiveToggle', () => {
|
|||
};
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) wrapper.destroy();
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
}
|
||||
});
|
||||
|
||||
const findGlToggle = () => wrapper.find(GlToggle);
|
||||
|
|
|
@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils';
|
|||
import IntegrationForm from '~/integrations/edit/components/integration_form.vue';
|
||||
import ActiveToggle from '~/integrations/edit/components/active_toggle.vue';
|
||||
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
|
||||
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
|
||||
|
||||
describe('IntegrationForm', () => {
|
||||
let wrapper;
|
||||
|
@ -38,6 +39,7 @@ describe('IntegrationForm', () => {
|
|||
|
||||
const findActiveToggle = () => wrapper.find(ActiveToggle);
|
||||
const findJiraTriggerFields = () => wrapper.find(JiraTriggerFields);
|
||||
const findTriggerFields = () => wrapper.find(TriggerFields);
|
||||
|
||||
describe('template', () => {
|
||||
describe('showActive is true', () => {
|
||||
|
@ -77,5 +79,21 @@ describe('IntegrationForm', () => {
|
|||
expect(findJiraTriggerFields().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('triggerEvents is present', () => {
|
||||
it('renders TriggerFields', () => {
|
||||
const events = [{ title: 'push' }];
|
||||
const type = 'slack';
|
||||
|
||||
createComponent({
|
||||
triggerEvents: events,
|
||||
type,
|
||||
});
|
||||
|
||||
expect(findTriggerFields().exists()).toBe(true);
|
||||
expect(findTriggerFields().props('events')).toBe(events);
|
||||
expect(findTriggerFields().props('type')).toBe(type);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,7 +18,10 @@ describe('JiraTriggerFields', () => {
|
|||
};
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) wrapper.destroy();
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
}
|
||||
});
|
||||
|
||||
const findCommentSettings = () => wrapper.find('[data-testid="comment-settings"]');
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
|
||||
import { GlFormGroup, GlFormCheckbox, GlFormInput } from '@gitlab/ui';
|
||||
|
||||
describe('TriggerFields', () => {
|
||||
let wrapper;
|
||||
|
||||
const defaultProps = {
|
||||
type: 'slack',
|
||||
};
|
||||
|
||||
const createComponent = props => {
|
||||
wrapper = mount(TriggerFields, {
|
||||
propsData: { ...defaultProps, ...props },
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
}
|
||||
});
|
||||
|
||||
const findAllGlFormCheckboxes = () => wrapper.findAll(GlFormCheckbox);
|
||||
const findAllGlFormInputs = () => wrapper.findAll(GlFormInput);
|
||||
|
||||
describe('template', () => {
|
||||
it('renders a label with text "Trigger"', () => {
|
||||
createComponent();
|
||||
|
||||
const triggerLabel = wrapper.find('[data-testid="trigger-fields-group"]').find('label');
|
||||
expect(triggerLabel.exists()).toBe(true);
|
||||
expect(triggerLabel.text()).toBe('Trigger');
|
||||
});
|
||||
|
||||
describe('events without field property', () => {
|
||||
const events = [
|
||||
{
|
||||
title: 'push',
|
||||
name: 'push_event',
|
||||
description: 'Event on push',
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
title: 'merge_request',
|
||||
name: 'merge_requests_event',
|
||||
description: 'Event on merge_request',
|
||||
value: false,
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
events,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not render GlFormInput for each event', () => {
|
||||
expect(findAllGlFormInputs().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders GlFormInput with description for each event', () => {
|
||||
const groups = wrapper.find('#trigger-fields').findAll(GlFormGroup);
|
||||
|
||||
expect(groups).toHaveLength(2);
|
||||
groups.wrappers.forEach((group, index) => {
|
||||
expect(group.find('small').text()).toBe(events[index].description);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders GlFormCheckbox for each event', () => {
|
||||
const checkboxes = findAllGlFormCheckboxes();
|
||||
const expectedResults = [
|
||||
{ labelText: 'Push', inputName: 'service[push_event]' },
|
||||
{ labelText: 'Merge Request', inputName: 'service[merge_requests_event]' },
|
||||
];
|
||||
expect(checkboxes).toHaveLength(2);
|
||||
|
||||
checkboxes.wrappers.forEach((checkbox, index) => {
|
||||
expect(checkbox.find('label').text()).toBe(expectedResults[index].labelText);
|
||||
expect(checkbox.find('input').attributes('name')).toBe(expectedResults[index].inputName);
|
||||
expect(checkbox.vm.$attrs.checked).toBe(events[index].value);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('events with field property', () => {
|
||||
const events = [
|
||||
{
|
||||
field: {
|
||||
name: 'push_channel',
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
name: 'merge_request_channel',
|
||||
value: 'gitlab-development',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
events,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders GlFormCheckbox for each event', () => {
|
||||
expect(findAllGlFormCheckboxes()).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('renders GlFormInput for each event', () => {
|
||||
const fields = findAllGlFormInputs();
|
||||
const expectedResults = [
|
||||
{
|
||||
name: 'service[push_channel]',
|
||||
placeholder: 'Slack channels (e.g. general, development)',
|
||||
},
|
||||
{
|
||||
name: 'service[merge_request_channel]',
|
||||
placeholder: 'Slack channels (e.g. general, development)',
|
||||
},
|
||||
];
|
||||
|
||||
expect(fields).toHaveLength(2);
|
||||
|
||||
fields.wrappers.forEach((field, index) => {
|
||||
expect(field.attributes()).toMatchObject(expectedResults[index]);
|
||||
expect(field.vm.$attrs.value).toBe(events[index].field.value);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -100,6 +100,26 @@ exports[`Dashboard template matches the default snapshot 1`] = `
|
|||
<div
|
||||
class="d-sm-flex"
|
||||
>
|
||||
<div
|
||||
class="mb-2 mr-2 d-flex"
|
||||
>
|
||||
<div
|
||||
class="flex-grow-1"
|
||||
title="Star dashboard"
|
||||
>
|
||||
<gl-deprecated-button-stub
|
||||
class="w-100"
|
||||
size="md"
|
||||
variant="default"
|
||||
>
|
||||
<gl-icon-stub
|
||||
name="star-o"
|
||||
size="16"
|
||||
/>
|
||||
</gl-deprecated-button-stub>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { shallowMount, mount } from '@vue/test-utils';
|
||||
import Tracking from '~/tracking';
|
||||
import { ESC_KEY, ESC_KEY_IE11 } from '~/lib/utils/keys';
|
||||
import { GlModal, GlDropdownItem, GlDeprecatedButton } from '@gitlab/ui';
|
||||
import { GlModal, GlDropdownItem, GlDeprecatedButton, GlIcon } from '@gitlab/ui';
|
||||
import { objectToQuery } from '~/lib/utils/url_utility';
|
||||
import VueDraggable from 'vuedraggable';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
|
@ -353,6 +353,83 @@ describe('Dashboard', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('star dashboards', () => {
|
||||
const findToggleStar = () => wrapper.find({ ref: 'toggleStarBtn' });
|
||||
const findToggleStarIcon = () => findToggleStar().find(GlIcon);
|
||||
|
||||
beforeEach(() => {
|
||||
createShallowWrapper();
|
||||
});
|
||||
|
||||
it('toggle star button is shown', () => {
|
||||
expect(findToggleStar().exists()).toBe(true);
|
||||
expect(findToggleStar().props('disabled')).toBe(false);
|
||||
});
|
||||
|
||||
it('toggle star button is disabled when starring is taking place', () => {
|
||||
store.commit(`monitoringDashboard/${types.REQUEST_DASHBOARD_STARRING}`);
|
||||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(findToggleStar().exists()).toBe(true);
|
||||
expect(findToggleStar().props('disabled')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the dashboard list is loaded', () => {
|
||||
// Tooltip element should wrap directly
|
||||
const getToggleTooltip = () => findToggleStar().element.parentElement.getAttribute('title');
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper.vm.$store.commit(
|
||||
`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
|
||||
dashboardGitResponse,
|
||||
);
|
||||
jest.spyOn(store, 'dispatch');
|
||||
});
|
||||
|
||||
it('dispatches a toggle star action', () => {
|
||||
findToggleStar().vm.$emit('click');
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(store.dispatch).toHaveBeenCalledWith(
|
||||
'monitoringDashboard/toggleStarredValue',
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when dashboard is not starred', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.setProps({ currentDashboard: dashboardGitResponse[0].path });
|
||||
return wrapper.vm.$nextTick();
|
||||
});
|
||||
|
||||
it('toggle star button shows "Star dashboard"', () => {
|
||||
expect(getToggleTooltip()).toBe('Star dashboard');
|
||||
});
|
||||
|
||||
it('toggle star button shows an unstarred state', () => {
|
||||
expect(findToggleStarIcon().attributes('name')).toBe('star-o');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when dashboard is starred', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.setProps({ currentDashboard: dashboardGitResponse[1].path });
|
||||
return wrapper.vm.$nextTick();
|
||||
});
|
||||
|
||||
it('toggle star button shows "Star dashboard"', () => {
|
||||
expect(getToggleTooltip()).toBe('Unstar dashboard');
|
||||
});
|
||||
|
||||
it('toggle star button shows a starred state', () => {
|
||||
expect(findToggleStarIcon().attributes('name')).toBe('star');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('hides the environments dropdown list when there is no environments', () => {
|
||||
createMountedWrapper({ hasMetrics: true });
|
||||
|
||||
|
|
|
@ -15,9 +15,6 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
|
|||
|
||||
const buildWrapper = (propsData = {}) => {
|
||||
wrapper = shallowMount(EditArea, {
|
||||
provide: {
|
||||
glFeatures: { richContentEditor: true },
|
||||
},
|
||||
propsData: {
|
||||
title,
|
||||
content,
|
||||
|
|
|
@ -220,6 +220,24 @@ describe Gitlab::Auth::AuthFinders do
|
|||
it { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with oauth headers' do
|
||||
before do
|
||||
set_header('HTTP_AUTHORIZATION', "Bearer #{deploy_token.token}")
|
||||
end
|
||||
|
||||
it { is_expected.to eq deploy_token }
|
||||
|
||||
it_behaves_like 'an unauthenticated route'
|
||||
|
||||
context 'with invalid token' do
|
||||
before do
|
||||
set_header('HTTP_AUTHORIZATION', "Bearer invalid_token")
|
||||
end
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#find_user_from_access_token' do
|
||||
|
|
|
@ -163,6 +163,13 @@ describe Gitlab::Danger::Teammate do
|
|||
{ message: 'OOO: massage' } | false
|
||||
{ message: 'love it SOOO much' } | false
|
||||
{ emoji: 'red_circle' } | false
|
||||
{ emoji: 'palm_tree' } | false
|
||||
{ emoji: 'beach' } | false
|
||||
{ emoji: 'beach_umbrella' } | false
|
||||
{ emoji: 'beach_with_umbrella' } | false
|
||||
{ emoji: nil } | true
|
||||
{ emoji: '' } | true
|
||||
{ emoji: 'dancer' } | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
|
@ -175,9 +182,9 @@ describe Gitlab::Danger::Teammate do
|
|||
end
|
||||
|
||||
it 'returns true if request fails' do
|
||||
expect(Gitlab::Danger::RequestHelper).to receive(:http_get_json)
|
||||
.twice
|
||||
.and_raise(Gitlab::Danger::RequestHelper::HTTPError.new)
|
||||
expect(Gitlab::Danger::RequestHelper)
|
||||
.to receive(:http_get_json)
|
||||
.and_raise(Gitlab::Danger::RequestHelper::HTTPError.new)
|
||||
|
||||
expect(subject.available?).to be true
|
||||
end
|
||||
|
|
|
@ -130,7 +130,7 @@ describe Gitlab::Utils do
|
|||
expect(to_boolean(false)).to be(false)
|
||||
end
|
||||
|
||||
it 'converts a valid string to a boolean' do
|
||||
it 'converts a valid value to a boolean' do
|
||||
expect(to_boolean(true)).to be(true)
|
||||
expect(to_boolean('true')).to be(true)
|
||||
expect(to_boolean('YeS')).to be(true)
|
||||
|
@ -146,12 +146,35 @@ describe Gitlab::Utils do
|
|||
expect(to_boolean('oFF')).to be(false)
|
||||
end
|
||||
|
||||
it 'converts an invalid string to nil' do
|
||||
it 'converts an invalid value to nil' do
|
||||
expect(to_boolean('fals')).to be_nil
|
||||
expect(to_boolean('yeah')).to be_nil
|
||||
expect(to_boolean('')).to be_nil
|
||||
expect(to_boolean(nil)).to be_nil
|
||||
end
|
||||
|
||||
it 'accepts a default value, and does not return it when a valid value is given' do
|
||||
expect(to_boolean(true, default: false)).to be(true)
|
||||
expect(to_boolean('true', default: false)).to be(true)
|
||||
expect(to_boolean('YeS', default: false)).to be(true)
|
||||
expect(to_boolean('t', default: false)).to be(true)
|
||||
expect(to_boolean('1', default: 'any value')).to be(true)
|
||||
expect(to_boolean('ON', default: 42)).to be(true)
|
||||
|
||||
expect(to_boolean('FaLse', default: true)).to be(false)
|
||||
expect(to_boolean('F', default: true)).to be(false)
|
||||
expect(to_boolean('NO', default: true)).to be(false)
|
||||
expect(to_boolean('n', default: true)).to be(false)
|
||||
expect(to_boolean('0', default: 'any value')).to be(false)
|
||||
expect(to_boolean('oFF', default: 42)).to be(false)
|
||||
end
|
||||
|
||||
it 'accepts a default value, and returns it when an invalid value is given' do
|
||||
expect(to_boolean('fals', default: true)).to eq(true)
|
||||
expect(to_boolean('yeah', default: false)).to eq(false)
|
||||
expect(to_boolean('', default: 'any value')).to eq('any value')
|
||||
expect(to_boolean(nil, default: 42)).to eq(42)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.boolean_to_yes_no' do
|
||||
|
|
|
@ -14,5 +14,15 @@ describe MilestoneNote do
|
|||
it_behaves_like 'a system note', exclude_project: true do
|
||||
let(:action) { 'milestone' }
|
||||
end
|
||||
|
||||
context 'with a remove milestone event' do
|
||||
let(:milestone) { create(:milestone) }
|
||||
let(:event) { create(:resource_milestone_event, action: :remove, issue: noteable, milestone: milestone) }
|
||||
|
||||
it 'creates the expected note' do
|
||||
expect(subject.note_html).to include('removed milestone')
|
||||
expect(subject.note_html).not_to include('changed milestone to')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -64,22 +64,4 @@ RSpec.describe Namespace::RootStorageSize, type: :model do
|
|||
|
||||
it { is_expected.to eq(limit.megabytes) }
|
||||
end
|
||||
|
||||
describe '#show_alert?' do
|
||||
subject { model.show_alert? }
|
||||
|
||||
it { is_expected.to eq(true) }
|
||||
|
||||
context 'when limit is 0' do
|
||||
let(:limit) { 0 }
|
||||
|
||||
it { is_expected.to eq(false) }
|
||||
end
|
||||
|
||||
context 'when is below threshold' do
|
||||
let(:current_size) { 49.megabytes }
|
||||
|
||||
it { is_expected.to eq(false) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe ServiceEventEntity do
|
||||
let(:request) { double('request') }
|
||||
|
||||
subject { described_class.new(event, request: request, service: service).as_json }
|
||||
|
||||
before do
|
||||
allow(request).to receive(:service).and_return(service)
|
||||
end
|
||||
|
||||
describe '#as_json' do
|
||||
context 'service without fields' do
|
||||
let(:service) { create(:emails_on_push_service, push_events: true) }
|
||||
let(:event) { 'push' }
|
||||
|
||||
it 'exposes correct attributes' do
|
||||
expect(subject[:description]).to eq('Event will be triggered by a push to the repository')
|
||||
expect(subject[:name]).to eq('push_events')
|
||||
expect(subject[:title]).to eq('push')
|
||||
expect(subject[:value]).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'service with fields' do
|
||||
let(:service) { create(:slack_service, note_events: false, note_channel: 'note-channel') }
|
||||
let(:event) { 'note' }
|
||||
|
||||
it 'exposes correct attributes' do
|
||||
expect(subject[:description]).to eq('Event will be triggered when someone adds a comment')
|
||||
expect(subject[:name]).to eq('note_events')
|
||||
expect(subject[:title]).to eq('note')
|
||||
expect(subject[:value]).to eq(false)
|
||||
expect(subject[:field][:name]).to eq('note_channel')
|
||||
expect(subject[:field][:value]).to eq('note-channel')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -34,7 +34,7 @@ describe Ci::CreatePipelineService do
|
|||
|
||||
it 'creates a pipeline using the content passed in as param' do
|
||||
expect(subject).to be_persisted
|
||||
expect(subject.builds.map(&:name)).to eq %w[rspec custom]
|
||||
expect(subject.builds.pluck(:name)).to match_array %w[rspec custom]
|
||||
expect(subject.config_source).to eq 'bridge_source'
|
||||
end
|
||||
|
||||
|
@ -59,7 +59,7 @@ describe Ci::CreatePipelineService do
|
|||
|
||||
it 'created a pipeline using the content passed in as param and download the artifact' do
|
||||
expect(subject).to be_persisted
|
||||
expect(subject.builds.pluck(:name)).to eq %w[rspec time custom]
|
||||
expect(subject.builds.pluck(:name)).to match_array %w[rspec time custom]
|
||||
expect(subject.config_source).to eq 'bridge_source'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -92,6 +92,7 @@ describe MergeRequests::UpdateService, :mailer do
|
|||
labels: [],
|
||||
mentioned_users: [user2],
|
||||
assignees: [user3],
|
||||
milestone: nil,
|
||||
total_time_spent: 0,
|
||||
description: "FYI #{user2.to_reference}"
|
||||
}
|
||||
|
|
|
@ -3,92 +3,157 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Namespaces::CheckStorageSizeService, '#execute' do
|
||||
let_it_be(:root_group) { create(:group) }
|
||||
let(:nested_group) { create(:group, parent: root_group) }
|
||||
let(:service) { described_class.new(nested_group) }
|
||||
let(:namespace) { build_stubbed(:namespace) }
|
||||
let(:user) { build(:user, namespace: namespace) }
|
||||
let(:service) { described_class.new(namespace, user) }
|
||||
let(:current_size) { 150.megabytes }
|
||||
let(:limit) { 100 }
|
||||
let(:limit) { 100.megabytes }
|
||||
|
||||
subject { service.execute }
|
||||
subject(:response) { service.execute }
|
||||
|
||||
before do
|
||||
stub_application_setting(namespace_storage_size_limit: limit)
|
||||
allow(namespace).to receive(:root_ancestor).and_return(namespace)
|
||||
|
||||
create(:namespace_root_storage_statistics, namespace: root_group, storage_size: current_size)
|
||||
root_storage_size = instance_double("RootStorageSize",
|
||||
current_size: current_size,
|
||||
limit: limit,
|
||||
usage_ratio: limit == 0 ? 0 : current_size.to_f / limit.to_f,
|
||||
above_size_limit?: current_size > limit
|
||||
)
|
||||
|
||||
expect(Namespace::RootStorageSize).to receive(:new).and_return(root_storage_size)
|
||||
end
|
||||
|
||||
context 'feature flag' do
|
||||
it 'is successful when disabled' do
|
||||
stub_feature_flags(namespace_storage_limit: false)
|
||||
|
||||
expect(subject).to be_success
|
||||
expect(response).to be_success
|
||||
end
|
||||
|
||||
it 'errors when enabled' do
|
||||
stub_feature_flags(namespace_storage_limit: true)
|
||||
|
||||
expect(subject).to be_error
|
||||
expect(response).to be_error
|
||||
end
|
||||
|
||||
it 'is successful when feature flag is activated for another group' do
|
||||
stub_feature_flags(namespace_storage_limit: create(:group))
|
||||
it 'is successful when feature flag is activated for another namespace' do
|
||||
stub_feature_flags(namespace_storage_limit: build(:namespace))
|
||||
|
||||
expect(subject).to be_success
|
||||
expect(response).to be_success
|
||||
end
|
||||
|
||||
it 'errors when feature flag is activated for the current group' do
|
||||
stub_feature_flags(namespace_storage_limit: root_group)
|
||||
it 'errors when feature flag is activated for the current namespace' do
|
||||
stub_feature_flags(namespace_storage_limit: namespace )
|
||||
|
||||
expect(subject).to be_error
|
||||
expect(response).to be_error
|
||||
expect(response.message).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
context 'when limit is set to 0' do
|
||||
let(:limit) { 0 }
|
||||
|
||||
it { is_expected.to be_success }
|
||||
|
||||
it 'does not respond with a payload' do
|
||||
result = subject
|
||||
|
||||
expect(result.message).to be_nil
|
||||
expect(result.payload).to be_empty
|
||||
it 'is successful and has no payload' do
|
||||
expect(response).to be_success
|
||||
expect(response.payload).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current size is below threshold to show an alert' do
|
||||
context 'when current size is below threshold' do
|
||||
let(:current_size) { 10.megabytes }
|
||||
|
||||
it { is_expected.to be_success }
|
||||
end
|
||||
|
||||
context 'when current size exceeds limit' do
|
||||
it 'returns an error with a payload' do
|
||||
result = subject
|
||||
current_usage_message = result.payload[:current_usage_message]
|
||||
|
||||
expect(result).to be_error
|
||||
expect(result.message).to include("#{root_group.name} is now read-only.")
|
||||
expect(current_usage_message).to include("150%")
|
||||
expect(current_usage_message).to include(root_group.name)
|
||||
expect(current_usage_message).to include("150 MB of 100 MB")
|
||||
expect(result.payload[:usage_ratio]).to eq(1.5)
|
||||
it 'is successful and has no payload' do
|
||||
expect(response).to be_success
|
||||
expect(response.payload).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current size is below limit but should show an alert' do
|
||||
let(:current_size) { 50.megabytes }
|
||||
context 'when not admin of the namespace' do
|
||||
let(:other_namespace) { build_stubbed(:namespace) }
|
||||
|
||||
it 'returns success with a payload' do
|
||||
result = subject
|
||||
current_usage_message = result.payload[:current_usage_message]
|
||||
subject(:response) { described_class.new(other_namespace, user).execute }
|
||||
|
||||
expect(result).to be_success
|
||||
expect(result.message).to be_present
|
||||
expect(current_usage_message).to include("50%")
|
||||
expect(current_usage_message).to include(root_group.name)
|
||||
expect(current_usage_message).to include("50 MB of 100 MB")
|
||||
expect(result.payload[:usage_ratio]).to eq(0.5)
|
||||
before do
|
||||
allow(other_namespace).to receive(:root_ancestor).and_return(other_namespace)
|
||||
end
|
||||
|
||||
it 'errors and has no payload' do
|
||||
expect(response).to be_error
|
||||
expect(response.payload).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when providing the child namespace' do
|
||||
let(:namespace) { build_stubbed(:group) }
|
||||
let(:child_namespace) { build_stubbed(:group, parent: namespace) }
|
||||
|
||||
subject(:response) { described_class.new(child_namespace, user).execute }
|
||||
|
||||
before do
|
||||
allow(child_namespace).to receive(:root_ancestor).and_return(namespace)
|
||||
namespace.add_owner(user)
|
||||
end
|
||||
|
||||
it 'uses the root namespace' do
|
||||
expect(response).to be_error
|
||||
end
|
||||
end
|
||||
|
||||
describe 'payload alert_level' do
|
||||
subject { service.execute.payload[:alert_level] }
|
||||
|
||||
context 'when above info threshold' do
|
||||
let(:current_size) { 50.megabytes }
|
||||
|
||||
it { is_expected.to eq(:info) }
|
||||
end
|
||||
|
||||
context 'when above warning threshold' do
|
||||
let(:current_size) { 75.megabytes }
|
||||
|
||||
it { is_expected.to eq(:warning) }
|
||||
end
|
||||
|
||||
context 'when above alert threshold' do
|
||||
let(:current_size) { 95.megabytes }
|
||||
|
||||
it { is_expected.to eq(:alert) }
|
||||
end
|
||||
|
||||
context 'when above error threshold' do
|
||||
let(:current_size) { 100.megabytes }
|
||||
|
||||
it { is_expected.to eq(:error) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'payload explanation_message' do
|
||||
subject(:response) { service.execute.payload[:explanation_message] }
|
||||
|
||||
context 'when above limit' do
|
||||
let(:current_size) { 110.megabytes }
|
||||
|
||||
it 'returns message with read-only warning' do
|
||||
expect(response).to include("#{namespace.name} is now read-only")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when below limit' do
|
||||
let(:current_size) { 60.megabytes }
|
||||
|
||||
it { is_expected.to include('If you reach 100% storage capacity') }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'payload usage_message' do
|
||||
let(:current_size) { 60.megabytes }
|
||||
|
||||
subject(:response) { service.execute.payload[:usage_message] }
|
||||
|
||||
it 'returns current usage information' do
|
||||
expect(response).to include("60 MB of 100 MB")
|
||||
expect(response).to include("60%")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -166,6 +166,41 @@ describe PostReceiveService do
|
|||
expect(subject).to include(build_alert_message(message))
|
||||
end
|
||||
end
|
||||
|
||||
context 'storage size limit alerts' do
|
||||
let(:check_storage_size_response) { ServiceResponse.success }
|
||||
|
||||
before do
|
||||
expect_next_instance_of(Namespaces::CheckStorageSizeService, project.namespace, user) do |check_storage_size_service|
|
||||
expect(check_storage_size_service).to receive(:execute).and_return(check_storage_size_response)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is no payload' do
|
||||
it 'adds no alert' do
|
||||
expect(subject.size).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is payload' do
|
||||
let(:check_storage_size_response) do
|
||||
ServiceResponse.success(
|
||||
payload: {
|
||||
alert_level: :info,
|
||||
usage_message: "Usage",
|
||||
explanation_message: "Explanation"
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'adds an alert' do
|
||||
response = subject
|
||||
|
||||
expect(response.size).to eq(2)
|
||||
expect(response).to include(build_alert_message("##### INFO #####\nUsage\nExplanation"))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with PersonalSnippet' do
|
||||
|
|
|
@ -3,11 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ResourceEvents::ChangeMilestoneService do
|
||||
it_behaves_like 'a milestone events creator' do
|
||||
let(:resource) { create(:issue) }
|
||||
end
|
||||
|
||||
it_behaves_like 'a milestone events creator' do
|
||||
let(:resource) { create(:merge_request) }
|
||||
[:issue, :merge_request].each do |issuable|
|
||||
it_behaves_like 'a milestone events creator' do
|
||||
let(:resource) { create(issuable) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,10 +8,12 @@ ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true'
|
|||
ENV["RSPEC_ALLOW_INVALID_URLS"] = 'true'
|
||||
|
||||
require File.expand_path('../config/environment', __dir__)
|
||||
|
||||
require 'rspec/mocks'
|
||||
require 'rspec/rails'
|
||||
require 'shoulda/matchers'
|
||||
require 'rspec/retry'
|
||||
require 'rspec-parameterized'
|
||||
require 'shoulda/matchers'
|
||||
require 'test_prof/recipes/rspec/let_it_be'
|
||||
|
||||
rspec_profiling_is_configured =
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rspec/mocks'
|
||||
|
||||
module TestEnv
|
||||
extend ActiveSupport::Concern
|
||||
extend self
|
||||
|
@ -284,29 +282,33 @@ module TestEnv
|
|||
end
|
||||
|
||||
def setup_factory_repo
|
||||
setup_repo(factory_repo_path, factory_repo_path_bare, factory_repo_name,
|
||||
BRANCH_SHA)
|
||||
setup_repo(factory_repo_path, factory_repo_path_bare, factory_repo_name, BRANCH_SHA)
|
||||
end
|
||||
|
||||
# This repo has a submodule commit that is not present in the main test
|
||||
# repository.
|
||||
def setup_forked_repo
|
||||
setup_repo(forked_repo_path, forked_repo_path_bare, forked_repo_name,
|
||||
FORKED_BRANCH_SHA)
|
||||
setup_repo(forked_repo_path, forked_repo_path_bare, forked_repo_name, FORKED_BRANCH_SHA)
|
||||
end
|
||||
|
||||
def setup_repo(repo_path, repo_path_bare, repo_name, refs)
|
||||
clone_url = "https://gitlab.com/gitlab-org/#{repo_name}.git"
|
||||
|
||||
unless File.directory?(repo_path)
|
||||
system(*%W(#{Gitlab.config.git.bin_path} clone -q #{clone_url} #{repo_path}))
|
||||
puts "\n==> Setting up #{repo_name} repository in #{repo_path}..."
|
||||
start = Time.now
|
||||
system(*%W(#{Gitlab.config.git.bin_path} clone --quiet -- #{clone_url} #{repo_path}))
|
||||
puts " #{repo_path} set up in #{Time.now - start} seconds...\n"
|
||||
end
|
||||
|
||||
set_repo_refs(repo_path, refs)
|
||||
|
||||
unless File.directory?(repo_path_bare)
|
||||
puts "\n==> Setting up #{repo_name} bare repository in #{repo_path_bare}..."
|
||||
start = Time.now
|
||||
# We must copy bare repositories because we will push to them.
|
||||
system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare}))
|
||||
system(git_env, *%W(#{Gitlab.config.git.bin_path} clone --quiet --bare -- #{repo_path} #{repo_path_bare}))
|
||||
puts " #{repo_path_bare} set up in #{Time.now - start} seconds...\n"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ shared_context 'project service activation' do
|
|||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(integration_form_refactor: false)
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ shared_examples 'a milestone events creator' do
|
|||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:created_at_time) { Time.utc(2019, 12, 30) }
|
||||
let(:service) { described_class.new(resource, user, created_at: created_at_time) }
|
||||
let(:service) { described_class.new(resource, user, created_at: created_at_time, old_milestone: nil) }
|
||||
|
||||
context 'when milestone is present' do
|
||||
let_it_be(:milestone) { create(:milestone) }
|
||||
|
@ -25,10 +25,13 @@ shared_examples 'a milestone events creator' do
|
|||
resource.milestone = nil
|
||||
end
|
||||
|
||||
let(:old_milestone) { create(:milestone, project: resource.project) }
|
||||
let(:service) { described_class.new(resource, user, created_at: created_at_time, old_milestone: old_milestone) }
|
||||
|
||||
it 'creates the expected event records' do
|
||||
expect { service.execute }.to change { ResourceMilestoneEvent.count }.by(1)
|
||||
|
||||
expect_event_record(ResourceMilestoneEvent.last, action: 'remove', milestone: nil, state: 'opened')
|
||||
expect_event_record(ResourceMilestoneEvent.last, action: 'remove', milestone: old_milestone, state: 'opened')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ describe 'gitlab:gitaly namespace rake task' do
|
|||
|
||||
it 'calls checkout_or_clone_version with the right arguments' do
|
||||
expect(main_object)
|
||||
.to receive(:checkout_or_clone_version).with(version: version, repo: repo, target_dir: clone_path)
|
||||
.to receive(:checkout_or_clone_version).with(version: version, repo: repo, target_dir: clone_path, clone_opts: %w[--depth 1])
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
|
@ -28,7 +28,7 @@ describe Gitlab::TaskHelpers do
|
|||
|
||||
context "target_dir doesn't exist" do
|
||||
it 'clones the repo' do
|
||||
expect(subject).to receive(:clone_repo).with(repo, clone_path)
|
||||
expect(subject).to receive(:clone_repo).with(repo, clone_path, clone_opts: [])
|
||||
|
||||
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path)
|
||||
end
|
||||
|
@ -45,6 +45,12 @@ describe Gitlab::TaskHelpers do
|
|||
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path)
|
||||
end
|
||||
end
|
||||
|
||||
it 'accepts clone_opts' do
|
||||
expect(subject).to receive(:clone_repo).with(repo, clone_path, clone_opts: %w[--depth 1])
|
||||
|
||||
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path, clone_opts: %w[--depth 1])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#clone_repo' do
|
||||
|
@ -54,6 +60,13 @@ describe Gitlab::TaskHelpers do
|
|||
|
||||
subject.clone_repo(repo, clone_path)
|
||||
end
|
||||
|
||||
it 'accepts clone_opts' do
|
||||
expect(subject)
|
||||
.to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} clone --depth 1 -- #{repo} #{clone_path}])
|
||||
|
||||
subject.clone_repo(repo, clone_path, clone_opts: %w[--depth 1])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#checkout_version' do
|
||||
|
|
|
@ -36,7 +36,7 @@ describe 'gitlab:workhorse namespace rake task' do
|
|||
|
||||
it 'calls checkout_or_clone_version with the right arguments' do
|
||||
expect(main_object)
|
||||
.to receive(:checkout_or_clone_version).with(version: version, repo: repo, target_dir: clone_path)
|
||||
.to receive(:checkout_or_clone_version).with(version: version, repo: repo, target_dir: clone_path, clone_opts: %w[--depth 1])
|
||||
|
||||
run_rake_task('gitlab:workhorse:install', clone_path)
|
||||
end
|
||||
|
|
|
@ -7,6 +7,8 @@ describe 'projects/services/_form' do
|
|||
let(:user) { create(:admin) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(integration_form_refactor: false)
|
||||
|
||||
assign(:project, project)
|
||||
|
||||
allow(controller).to receive(:current_user).and_return(user)
|
||||
|
|
Loading…
Reference in New Issue