Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2d337eacd9
commit
0a70b104d0
|
|
@ -53,23 +53,6 @@ Layout/HashAlignment:
|
|||
- 'spec/lib/gitlab/metrics/subscribers/action_view_spec.rb'
|
||||
- 'spec/lib/gitlab/metrics/subscribers/active_record_spec.rb'
|
||||
- 'spec/lib/gitlab/metrics/subscribers/load_balancing_spec.rb'
|
||||
- 'spec/models/ci/build_spec.rb'
|
||||
- 'spec/models/ci/processable_spec.rb'
|
||||
- 'spec/models/clusters/platforms/kubernetes_spec.rb'
|
||||
- 'spec/models/container_registry/event_spec.rb'
|
||||
- 'spec/models/deployment_spec.rb'
|
||||
- 'spec/models/design_management/version_spec.rb'
|
||||
- 'spec/models/group_spec.rb'
|
||||
- 'spec/models/integrations/chat_message/pipeline_message_spec.rb'
|
||||
- 'spec/models/integrations/drone_ci_spec.rb'
|
||||
- 'spec/models/merge_request_spec.rb'
|
||||
- 'spec/models/namespace_spec.rb'
|
||||
- 'spec/models/operations/feature_flag_spec.rb'
|
||||
- 'spec/models/pages_domain_spec.rb'
|
||||
- 'spec/models/remote_mirror_spec.rb'
|
||||
- 'spec/models/repository_spec.rb'
|
||||
- 'spec/models/user_spec.rb'
|
||||
- 'spec/presenters/project_presenter_spec.rb'
|
||||
- 'spec/routing/project_routing_spec.rb'
|
||||
- 'spec/serializers/ci/lint/job_entity_spec.rb'
|
||||
- 'spec/serializers/container_repository_entity_spec.rb'
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@ import { SEVERITY_CLASSES, SEVERITY_ICONS } from '~/reports/codequality_report/c
|
|||
export default {
|
||||
components: { GlButton, GlIcon },
|
||||
props: {
|
||||
line: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
codeQuality: {
|
||||
type: Array,
|
||||
required: true,
|
||||
|
|
@ -50,7 +46,7 @@ export default {
|
|||
size="small"
|
||||
icon="close"
|
||||
class="gl-absolute gl-right-2 gl-top-2"
|
||||
@click="$emit('hideCodeQualityFindings', line)"
|
||||
@click="$emit('hideCodeQualityFindings')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<script>
|
||||
import DiffCodeQuality from './diff_code_quality.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DiffCodeQuality,
|
||||
},
|
||||
props: {
|
||||
line: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
parsedCodeQuality() {
|
||||
return (this.line.left ?? this.line.right)?.codequality;
|
||||
},
|
||||
codeQualityLineNumber() {
|
||||
return this.parsedCodeQuality[0].line;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hideCodeQualityFindings() {
|
||||
this.$emit('hideCodeQualityFindings', this.codeQualityLineNumber);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<diff-code-quality
|
||||
:code-quality="parsedCodeQuality"
|
||||
@hideCodeQualityFindings="hideCodeQualityFindings"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -9,7 +9,7 @@ import { getCommentedLines } from '~/notes/components/multiline_comment_utils';
|
|||
import { hide } from '~/tooltips';
|
||||
import { pickDirection } from '../utils/diff_line';
|
||||
import DiffCommentCell from './diff_comment_cell.vue';
|
||||
import DiffCodeQuality from './diff_code_quality.vue';
|
||||
import DiffLine from './diff_line.vue';
|
||||
import DiffExpansionCell from './diff_expansion_cell.vue';
|
||||
import DiffRow from './diff_row.vue';
|
||||
import { isHighlighted } from './diff_row_utils';
|
||||
|
|
@ -18,8 +18,8 @@ export default {
|
|||
components: {
|
||||
DiffExpansionCell,
|
||||
DiffRow,
|
||||
DiffLine,
|
||||
DiffCommentCell,
|
||||
DiffCodeQuality,
|
||||
DraftNote,
|
||||
},
|
||||
directives: {
|
||||
|
|
@ -96,10 +96,6 @@ export default {
|
|||
}
|
||||
this.idState.dragStart = line;
|
||||
},
|
||||
parseCodeQuality(line) {
|
||||
return (line.left ?? line.right)?.codequality;
|
||||
},
|
||||
|
||||
hideCodeQualityFindings(line) {
|
||||
const index = this.codeQualityExpandedLines.indexOf(line);
|
||||
if (index > -1) {
|
||||
|
|
@ -179,7 +175,7 @@ export default {
|
|||
);
|
||||
},
|
||||
getCodeQualityLine(line) {
|
||||
return this.parseCodeQuality(line)?.[0]?.line;
|
||||
return (line.left ?? line.right)?.codequality?.[0]?.line;
|
||||
},
|
||||
},
|
||||
userColorScheme: window.gon.user_color_scheme,
|
||||
|
|
@ -248,15 +244,13 @@ export default {
|
|||
@startdragging="onStartDragging"
|
||||
@stopdragging="onStopDragging"
|
||||
/>
|
||||
|
||||
<diff-code-quality
|
||||
<diff-line
|
||||
v-if="
|
||||
glFeatures.refactorCodeQualityInlineFindings &&
|
||||
codeQualityExpandedLines.includes(getCodeQualityLine(line))
|
||||
"
|
||||
:key="line.line_code"
|
||||
:line="getCodeQualityLine(line)"
|
||||
:code-quality="parseCodeQuality(line)"
|
||||
:line="line"
|
||||
@hideCodeQualityFindings="hideCodeQualityFindings"
|
||||
/>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,9 +1,43 @@
|
|||
<script>
|
||||
import { __ } from '~/locale';
|
||||
import createFlash from '~/flash';
|
||||
import branchRulesQuery from './graphql/queries/branch_rules.query.graphql';
|
||||
|
||||
export const i18n = {
|
||||
heading: __('Branch'),
|
||||
queryError: __('An error occurred while loading branch rules. Please try again.'),
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'BranchRules',
|
||||
i18n: { heading: __('Branch') },
|
||||
i18n,
|
||||
apollo: {
|
||||
branchRules: {
|
||||
query: branchRulesQuery,
|
||||
variables() {
|
||||
return {
|
||||
projectPath: this.projectPath,
|
||||
};
|
||||
},
|
||||
update(data) {
|
||||
return data.project?.branchRules?.nodes || [];
|
||||
},
|
||||
error() {
|
||||
createFlash({ message: this.$options.i18n.queryError });
|
||||
},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
branchRules: [],
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
query getBranchRules($projectPath: ID!) {
|
||||
project(fullPath: $projectPath) {
|
||||
id
|
||||
branchRules {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,28 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import BranchRulesApp from '~/projects/settings/repository/branch_rules/app.vue';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(),
|
||||
});
|
||||
|
||||
export default function mountBranchRules(el) {
|
||||
if (!el) return null;
|
||||
|
||||
const { projectPath } = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
apolloProvider,
|
||||
render(createElement) {
|
||||
return createElement(BranchRulesApp);
|
||||
return createElement(BranchRulesApp, {
|
||||
props: {
|
||||
projectPath,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,120 +23,4 @@ module StorageHelper
|
|||
|
||||
_("Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}") % counters
|
||||
end
|
||||
|
||||
def storage_enforcement_banner_info(context)
|
||||
root_ancestor = context.root_ancestor
|
||||
|
||||
return unless should_show_storage_enforcement_banner?(context, current_user, root_ancestor)
|
||||
|
||||
text_args = storage_enforcement_banner_text_args(root_ancestor, context)
|
||||
|
||||
text_paragraph_2 = if root_ancestor.user_namespace?
|
||||
html_escape_once(s_("UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. " \
|
||||
"View and manage your usage from %{strong_start}User settings > Usage quotas%{strong_end}. %{docs_link_start}Learn more%{link_end} " \
|
||||
"about how to reduce your storage.")).html_safe % text_args[:p2]
|
||||
else
|
||||
html_escape_once(s_("UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. " \
|
||||
"Group owners can view namespace storage usage and purchase more from %{strong_start}Group settings > Usage quotas%{strong_end}. %{docs_link_start}Learn more.%{link_end}" \
|
||||
)).html_safe % text_args[:p2]
|
||||
end
|
||||
|
||||
{
|
||||
text_paragraph_1: html_escape_once(s_("UsageQuota|Effective %{storage_enforcement_date}, namespace storage limits will apply " \
|
||||
"to the %{strong_start}%{namespace_name}%{strong_end} namespace. %{extra_message}" \
|
||||
"View the %{rollout_link_start}rollout schedule for this change%{link_end}.")).html_safe % text_args[:p1],
|
||||
text_paragraph_2: text_paragraph_2,
|
||||
text_paragraph_3: html_escape_once(s_("UsageQuota|See our %{faq_link_start}FAQ%{link_end} for more information.")).html_safe % text_args[:p3],
|
||||
variant: 'warning',
|
||||
namespace_id: root_ancestor.id,
|
||||
callouts_path: root_ancestor.user_namespace? ? callouts_path : group_callouts_path,
|
||||
callouts_feature_name: storage_enforcement_banner_user_callouts_feature_name(root_ancestor)
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def should_show_storage_enforcement_banner?(context, current_user, root_ancestor)
|
||||
return false unless user_allowed_storage_enforcement_banner?(context, current_user, root_ancestor)
|
||||
return false if root_ancestor.paid?
|
||||
return false unless future_enforcement_date?(root_ancestor)
|
||||
return false if user_dismissed_storage_enforcement_banner?(root_ancestor)
|
||||
return false if (root_ancestor.root_storage_statistics&.storage_size || 0) < ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE
|
||||
|
||||
::Feature.enabled?(:namespace_storage_limit_show_preenforcement_banner, root_ancestor)
|
||||
end
|
||||
|
||||
def user_allowed_storage_enforcement_banner?(context, current_user, root_ancestor)
|
||||
return can?(current_user, :maintainer_access, context) unless context.respond_to?(:user_namespace?) && context.user_namespace?
|
||||
|
||||
can?(current_user, :owner_access, context)
|
||||
end
|
||||
|
||||
def storage_enforcement_banner_text_args(root_ancestor, context)
|
||||
strong_tags = {
|
||||
strong_start: "<strong>".html_safe,
|
||||
strong_end: "</strong>".html_safe
|
||||
}
|
||||
|
||||
extra_message = if context.is_a?(Project)
|
||||
html_escape_once(s_("UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "))
|
||||
.html_safe % strong_tags.merge(context_name: context.name)
|
||||
elsif !context.root?
|
||||
html_escape_once(s_("UsageQuota|The %{strong_start}%{context_name}%{strong_end} group will be affected by this. "))
|
||||
.html_safe % strong_tags.merge(context_name: context.name)
|
||||
else
|
||||
''
|
||||
end
|
||||
|
||||
{
|
||||
p1: {
|
||||
storage_enforcement_date: root_ancestor.storage_enforcement_date,
|
||||
namespace_name: root_ancestor.name,
|
||||
extra_message: extra_message,
|
||||
rollout_link_start: '<a href="%{url}" >'.html_safe % { url: help_page_path('user/usage_quotas', anchor: 'namespace-storage-limit-enforcement-schedule') },
|
||||
link_end: "</a>".html_safe
|
||||
}.merge(strong_tags),
|
||||
p2: {
|
||||
used_storage: storage_counter(root_ancestor.root_storage_statistics&.storage_size || 0),
|
||||
docs_link_start: '<a href="%{url}" >'.html_safe % { url: help_page_path('user/usage_quotas', anchor: 'manage-your-storage-usage') },
|
||||
link_end: "</a>".html_safe
|
||||
}.merge(strong_tags),
|
||||
p3: {
|
||||
faq_link_start: '<a href="%{url}" >'.html_safe % { url: "#{Gitlab::Saas.about_pricing_url}faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier" },
|
||||
link_end: "</a>".html_safe
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def storage_enforcement_banner_user_callouts_feature_name(namespace)
|
||||
"storage_enforcement_banner_#{storage_enforcement_banner_threshold(namespace)}_enforcement_threshold"
|
||||
end
|
||||
|
||||
def storage_enforcement_banner_threshold(namespace)
|
||||
days_to_enforcement_date = (namespace.storage_enforcement_date - Date.today)
|
||||
|
||||
return :first if days_to_enforcement_date > 30
|
||||
return :second if days_to_enforcement_date > 15 && days_to_enforcement_date <= 30
|
||||
return :third if days_to_enforcement_date > 7 && days_to_enforcement_date <= 15
|
||||
return :fourth if days_to_enforcement_date >= 0 && days_to_enforcement_date <= 7
|
||||
end
|
||||
|
||||
def user_dismissed_storage_enforcement_banner?(namespace)
|
||||
return false unless current_user
|
||||
|
||||
if namespace.user_namespace?
|
||||
current_user.dismissed_callout?(feature_name: storage_enforcement_banner_user_callouts_feature_name(namespace))
|
||||
else
|
||||
current_user.dismissed_callout_for_group?(
|
||||
feature_name: storage_enforcement_banner_user_callouts_feature_name(namespace),
|
||||
group: namespace
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def future_enforcement_date?(namespace)
|
||||
return true if ::Feature.enabled?(:namespace_storage_limit_bypass_date_check, namespace)
|
||||
|
||||
namespace.storage_enforcement_date.present? && namespace.storage_enforcement_date >= Date.today
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ module Users
|
|||
verification_reminder: 40, # EE-only
|
||||
ci_deprecation_warning_for_types_keyword: 41,
|
||||
security_training_feature_promotion: 42, # EE-only
|
||||
storage_enforcement_banner_first_enforcement_threshold: 43,
|
||||
storage_enforcement_banner_second_enforcement_threshold: 44,
|
||||
storage_enforcement_banner_third_enforcement_threshold: 45,
|
||||
storage_enforcement_banner_fourth_enforcement_threshold: 46,
|
||||
storage_enforcement_banner_first_enforcement_threshold: 43, # EE-only
|
||||
storage_enforcement_banner_second_enforcement_threshold: 44, # EE-only
|
||||
storage_enforcement_banner_third_enforcement_threshold: 45, # EE-only
|
||||
storage_enforcement_banner_fourth_enforcement_threshold: 46, # EE-only
|
||||
# 47 and 48 were removed with https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95446
|
||||
# 49 was removed with https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91533
|
||||
# because the banner was no longer relevant.
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ module Users
|
|||
enum feature_name: {
|
||||
invite_members_banner: 1,
|
||||
approaching_seat_count_threshold: 2, # EE-only
|
||||
storage_enforcement_banner_first_enforcement_threshold: 3,
|
||||
storage_enforcement_banner_second_enforcement_threshold: 4,
|
||||
storage_enforcement_banner_third_enforcement_threshold: 5,
|
||||
storage_enforcement_banner_fourth_enforcement_threshold: 6,
|
||||
storage_enforcement_banner_first_enforcement_threshold: 3, # EE-only
|
||||
storage_enforcement_banner_second_enforcement_threshold: 4, # EE-only
|
||||
storage_enforcement_banner_third_enforcement_threshold: 5, # EE-only
|
||||
storage_enforcement_banner_fourth_enforcement_threshold: 6, # EE-only
|
||||
preview_user_over_limit_free_plan_alert: 7, # EE-only
|
||||
user_reached_limit_free_plan_alert: 8, # EE-only
|
||||
free_group_limited_alert: 9, # EE-only
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ module Users
|
|||
enum feature_name: {
|
||||
invite_members_banner: 1,
|
||||
approaching_seat_count_threshold: 2, # EE-only
|
||||
storage_enforcement_banner_first_enforcement_threshold: 3,
|
||||
storage_enforcement_banner_second_enforcement_threshold: 4,
|
||||
storage_enforcement_banner_third_enforcement_threshold: 5,
|
||||
storage_enforcement_banner_fourth_enforcement_threshold: 6,
|
||||
storage_enforcement_banner_first_enforcement_threshold: 3, # EE-only
|
||||
storage_enforcement_banner_second_enforcement_threshold: 4, # EE-only
|
||||
storage_enforcement_banner_third_enforcement_threshold: 5, # EE-only
|
||||
storage_enforcement_banner_fourth_enforcement_threshold: 6, # EE-only
|
||||
preview_user_over_limit_free_plan_alert: 7, # EE-only
|
||||
user_reached_limit_free_plan_alert: 8, # EE-only
|
||||
web_hook_disabled: 9
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
- @left_sidebar = true
|
||||
|
||||
- content_for :flash_message do
|
||||
= render "layouts/header/storage_enforcement_banner", context: @group
|
||||
= dispensable_render_if_exists "groups/storage_enforcement_alert", context: @group
|
||||
= dispensable_render_if_exists "shared/namespace_storage_limit_alert", context: @group
|
||||
|
||||
- content_for :page_specific_javascripts do
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
- return unless current_user
|
||||
- context = local_assigns.fetch(:context)
|
||||
- banner_info = storage_enforcement_banner_info(context)
|
||||
- return unless banner_info.present?
|
||||
|
||||
= render Pajamas::AlertComponent.new(variant: :warning,
|
||||
alert_options: { class: 'js-storage-enforcement-banner',
|
||||
data: { feature_id: banner_info[:callouts_feature_name],
|
||||
dismiss_endpoint: banner_info[:callouts_path],
|
||||
group_id: banner_info[:namespace_id],
|
||||
defer_links: "true" }}) do |c|
|
||||
= c.body do
|
||||
%p= banner_info[:text_paragraph_1]
|
||||
%p= banner_info[:text_paragraph_2]
|
||||
%p= banner_info[:text_paragraph_3]
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
- enable_search_settings locals: { container_class: 'gl-my-5' }
|
||||
|
||||
- content_for :flash_message do
|
||||
= render "layouts/header/storage_enforcement_banner", context: current_user.namespace
|
||||
= dispensable_render_if_exists "profiles/storage_enforcement_alert", context: current_user.namespace
|
||||
= dispensable_render_if_exists "shared/namespace_storage_limit_alert", context: current_user.namespace
|
||||
|
||||
= render template: "layouts/application"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
- @content_class = [@content_class, project_classes(@project)].compact.join(" ")
|
||||
|
||||
- content_for :flash_message do
|
||||
= render "layouts/header/storage_enforcement_banner", context: @project
|
||||
= dispensable_render_if_exists "projects/storage_enforcement_alert", context: @project
|
||||
= dispensable_render_if_exists "shared/namespace_storage_limit_alert", context: @project
|
||||
|
||||
- content_for :project_javascripts do
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@
|
|||
= _('Define rules for who can push, merge, and the required approvals for each branch.')
|
||||
|
||||
.settings-content.gl-pr-0
|
||||
#js-branch-rules
|
||||
#js-branch-rules{ data: { project_path: @project.full_path } }
|
||||
|
|
|
|||
|
|
@ -736,7 +736,7 @@ You can change these limits in the [GitLab Rails console](operations/rails_conso
|
|||
- To update the maximum YAML size, update `max_yaml_size_bytes` with the new value in megabytes:
|
||||
|
||||
```ruby
|
||||
ApplicationSetting.update!(max_yaml_size_bytes: 2.megabytes)
|
||||
ApplicationSetting.update(max_yaml_size_bytes: 2.megabytes)
|
||||
```
|
||||
|
||||
The `max_yaml_size_bytes` value is not directly tied to the size of the YAML file,
|
||||
|
|
@ -745,7 +745,7 @@ You can change these limits in the [GitLab Rails console](operations/rails_conso
|
|||
- To update the maximum YAML depth, update `max_yaml_depth` with the new value in megabytes:
|
||||
|
||||
```ruby
|
||||
ApplicationSetting.update!(max_yaml_depth: 125)
|
||||
ApplicationSetting.update(max_yaml_depth: 125)
|
||||
```
|
||||
|
||||
### Limit dotenv variables
|
||||
|
|
|
|||
|
|
@ -4197,6 +4197,9 @@ msgstr ""
|
|||
msgid "An error occurred while loading all the files."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while loading branch rules. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while loading chart data"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -42179,6 +42182,9 @@ msgstr ""
|
|||
msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker Images. %{linkStart}More information%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|Group settings > Usage quotas"
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|Includes artifacts, repositories, wiki, uploads, and other items."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -42275,10 +42281,10 @@ msgstr ""
|
|||
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}Group settings > Usage quotas%{strong_end}. %{docs_link_start}Learn more.%{link_end}"
|
||||
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}User settings > Usage quotas%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
|
||||
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|The table below shows current period usage"
|
||||
|
|
@ -42344,6 +42350,9 @@ msgstr ""
|
|||
msgid "UsageQuota|Usage quotas help link"
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|User settings > Usage quotas"
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|When you purchase additional storage, we automatically unlock projects that were locked when you reached the %{actualRepositorySizeLimit} limit."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,11 @@ module QA
|
|||
group.add_member(developer_user, Resource::Members::AccessLevel::DEVELOPER)
|
||||
end
|
||||
|
||||
it 'allows enforcing 2FA via UI and logging in with 2FA', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347931' do
|
||||
it(
|
||||
'allows enforcing 2FA via UI and logging in with 2FA',
|
||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347931',
|
||||
quarantine: { type: :flaky, issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/369516' }
|
||||
) do
|
||||
enforce_two_factor_authentication_on_group(group)
|
||||
|
||||
enable_two_factor_authentication_for_user(developer_user)
|
||||
|
|
|
|||
|
|
@ -517,76 +517,4 @@ RSpec.describe 'Group' do
|
|||
fill_in 'confirm_name_input', with: confirm_with
|
||||
click_button 'Confirm'
|
||||
end
|
||||
|
||||
describe 'storage_enforcement_banner', :js do
|
||||
let_it_be_with_refind(:group) { create(:group, :with_root_storage_statistics) }
|
||||
let_it_be_with_refind(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE)
|
||||
group.add_owner(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'with storage_enforcement_date set' do
|
||||
let_it_be(:storage_enforcement_date) { Date.today + 30 }
|
||||
|
||||
before do
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
it 'displays the banner in the group page' do
|
||||
visit group_path(group)
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
end
|
||||
|
||||
it 'does not display the banner in a paid group page' do
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:paid?).and_return(true)
|
||||
end
|
||||
visit group_path(group)
|
||||
expect_page_not_to_have_storage_enforcement_banner
|
||||
end
|
||||
|
||||
it 'does not display the banner if user has previously closed unless threshold has changed' do
|
||||
visit group_path(group)
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
find('.js-storage-enforcement-banner [data-testid="close-icon"]').click
|
||||
wait_for_requests
|
||||
page.refresh
|
||||
expect_page_not_to_have_storage_enforcement_banner
|
||||
|
||||
storage_enforcement_date = Date.today + 13
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
page.refresh
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with storage_enforcement_date not set' do
|
||||
before do
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:storage_enforcement_date).and_return(nil)
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not display the banner in the group page' do
|
||||
stub_feature_flags(namespace_storage_limit_bypass_date_check: false)
|
||||
visit group_path(group)
|
||||
expect_page_not_to_have_storage_enforcement_banner
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
expect(page).to have_text "Effective #{storage_enforcement_date}, namespace storage limits will apply"
|
||||
end
|
||||
|
||||
def expect_page_not_to_have_storage_enforcement_banner
|
||||
expect(page).not_to have_text "namespace storage limits will apply"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -87,69 +87,4 @@ RSpec.describe 'User visits their profile' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'storage_enforcement_banner', :js do
|
||||
let_it_be(:root_storage_statistics) do
|
||||
create(
|
||||
:namespace_root_storage_statistics,
|
||||
namespace: user.namespace,
|
||||
storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
stub_feature_flags(namespace_storage_limit_bypass_date_check: false)
|
||||
end
|
||||
|
||||
context 'with storage_enforcement_date set' do
|
||||
let_it_be(:storage_enforcement_date) { Date.today + 30 }
|
||||
|
||||
before do
|
||||
allow_next_found_instance_of(Namespaces::UserNamespace) do |user_namespace|
|
||||
allow(user_namespace).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
it 'displays the banner in the profile page' do
|
||||
visit(profile_path)
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
end
|
||||
|
||||
it 'does not display the banner if user has previously closed unless threshold has changed' do
|
||||
visit(profile_path)
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
find('.js-storage-enforcement-banner [data-testid="close-icon"]').click
|
||||
page.refresh
|
||||
expect_page_not_to_have_storage_enforcement_banner
|
||||
|
||||
storage_enforcement_date = Date.today + 13
|
||||
allow_next_found_instance_of(Namespaces::UserNamespace) do |user_namespace|
|
||||
allow(user_namespace).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
page.refresh
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with storage_enforcement_date not set' do
|
||||
before do
|
||||
allow_next_found_instance_of(Namespaces::UserNamespace) do |user_namespace|
|
||||
allow(user_namespace).to receive(:storage_enforcement_date).and_return(nil)
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not display the banner in the group page' do
|
||||
visit(profile_path)
|
||||
expect_page_not_to_have_storage_enforcement_banner
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
expect(page).to have_text "Effective #{storage_enforcement_date}, namespace storage limits will apply"
|
||||
end
|
||||
|
||||
def expect_page_not_to_have_storage_enforcement_banner
|
||||
expect(page).not_to have_text "namespace storage limits will apply"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ RSpec.describe 'User creates release', :js do
|
|||
fill_out_form_and_submit
|
||||
end
|
||||
|
||||
it 'creates a new release when "Create release" is clicked and redirects to the release\'s dedicated page', :aggregate_failures do
|
||||
it 'creates a new release when "Create release" is clicked and redirects to the release\'s dedicated page', :aggregate_failures, :sidekiq_inline do
|
||||
release = project.releases.last
|
||||
|
||||
expect(release.tag).to eq(tag_name)
|
||||
|
|
@ -66,6 +66,11 @@ RSpec.describe 'User creates release', :js do
|
|||
expect(link.url).to eq(link_2[:url])
|
||||
expect(link.name).to eq(link_2[:title])
|
||||
|
||||
expect(release).not_to be_historical_release
|
||||
expect(release).not_to be_upcoming_release
|
||||
|
||||
expect(release.evidences.length).to eq(1)
|
||||
|
||||
expect(page).to have_current_path(project_release_path(project, release))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -440,110 +440,6 @@ RSpec.describe 'Project' do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'storage_enforcement_banner', :js do
|
||||
let_it_be_with_refind(:group) { create(:group, :with_root_storage_statistics) }
|
||||
let_it_be_with_refind(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, group: group) }
|
||||
|
||||
before do
|
||||
group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE)
|
||||
group.add_maintainer(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'with storage_enforcement_date set' do
|
||||
let_it_be(:storage_enforcement_date) { Date.today + 30 }
|
||||
|
||||
before do
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
it 'displays the banner in the project page' do
|
||||
visit project_path(project)
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
end
|
||||
|
||||
context 'when in a subgroup project page' do
|
||||
let_it_be(:subgroup) { create(:group, parent: group) }
|
||||
let_it_be(:project) { create(:project, namespace: subgroup) }
|
||||
|
||||
it 'displays the banner' do
|
||||
visit project_path(project)
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when in a user namespace project page' do
|
||||
let_it_be_with_refind(:project) { create(:project, namespace: user.namespace) }
|
||||
|
||||
before do
|
||||
create(
|
||||
:namespace_root_storage_statistics,
|
||||
namespace: user.namespace,
|
||||
storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE
|
||||
)
|
||||
|
||||
allow_next_found_instance_of(Namespaces::UserNamespace) do |user_namespace|
|
||||
allow(user_namespace).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
it 'displays the banner' do
|
||||
visit project_path(project)
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not display the banner in a paid group project page' do
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:paid?).and_return(true)
|
||||
end
|
||||
visit project_path(project)
|
||||
expect_page_not_to_have_storage_enforcement_banner
|
||||
end
|
||||
|
||||
it 'does not display the banner if user has previously closed unless threshold has changed' do
|
||||
visit project_path(project)
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
find('.js-storage-enforcement-banner [data-testid="close-icon"]').click
|
||||
wait_for_requests
|
||||
page.refresh
|
||||
expect_page_not_to_have_storage_enforcement_banner
|
||||
|
||||
storage_enforcement_date = Date.today + 13
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
page.refresh
|
||||
expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with storage_enforcement_date not set' do
|
||||
before do
|
||||
allow_next_found_instance_of(Group) do |group|
|
||||
allow(group).to receive(:storage_enforcement_date).and_return(nil)
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not display the banner in the group page' do
|
||||
stub_feature_flags(namespace_storage_limit_bypass_date_check: false)
|
||||
visit project_path(project)
|
||||
expect_page_not_to_have_storage_enforcement_banner
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def expect_page_to_have_storage_enforcement_banner(storage_enforcement_date)
|
||||
expect(page).to have_text "Effective #{storage_enforcement_date}, namespace storage limits will apply"
|
||||
end
|
||||
|
||||
def expect_page_not_to_have_storage_enforcement_banner
|
||||
expect(page).not_to have_text "namespace storage limits will apply"
|
||||
end
|
||||
|
||||
def remove_with_confirm(button_text, confirm_with, confirm_button_text = 'Confirm')
|
||||
click_button button_text
|
||||
fill_in 'confirm_name_input', with: confirm_with
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ describe('DiffCodeQuality', () => {
|
|||
return mountFunction(DiffCodeQuality, {
|
||||
propsData: {
|
||||
expandedLines: [],
|
||||
line: 1,
|
||||
codeQuality,
|
||||
},
|
||||
});
|
||||
|
|
@ -28,9 +27,7 @@ describe('DiffCodeQuality', () => {
|
|||
expect(wrapper.findByTestId('diff-codequality').exists()).toBe(true);
|
||||
|
||||
await wrapper.findByTestId('diff-codequality-close').trigger('click');
|
||||
|
||||
expect(wrapper.emitted('hideCodeQualityFindings').length).toBe(1);
|
||||
expect(wrapper.emitted().hideCodeQualityFindings[0][0]).toBe(wrapper.props('line'));
|
||||
});
|
||||
|
||||
it('renders correct amount of list items for codequality array and their description', async () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import DiffLine from '~/diffs/components/diff_line.vue';
|
||||
import DiffCodeQuality from '~/diffs/components/diff_code_quality.vue';
|
||||
|
||||
const EXAMPLE_LINE_NUMBER = 3;
|
||||
const EXAMPLE_DESCRIPTION = 'example description';
|
||||
const EXAMPLE_SEVERITY = 'example severity';
|
||||
|
||||
const left = {
|
||||
line: {
|
||||
left: {
|
||||
codequality: [
|
||||
{
|
||||
line: EXAMPLE_LINE_NUMBER,
|
||||
description: EXAMPLE_DESCRIPTION,
|
||||
severity: EXAMPLE_SEVERITY,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const right = {
|
||||
line: {
|
||||
right: {
|
||||
codequality: [
|
||||
{
|
||||
line: EXAMPLE_LINE_NUMBER,
|
||||
description: EXAMPLE_DESCRIPTION,
|
||||
severity: EXAMPLE_SEVERITY,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mockData = [right, left];
|
||||
|
||||
describe('DiffLine', () => {
|
||||
const createWrapper = (propsData) => {
|
||||
return shallowMount(DiffLine, { propsData });
|
||||
};
|
||||
|
||||
it('should emit event when hideCodeQualityFindings is called', () => {
|
||||
const wrapper = createWrapper(right);
|
||||
|
||||
wrapper.findComponent(DiffCodeQuality).vm.$emit('hideCodeQualityFindings');
|
||||
expect(wrapper.emitted()).toEqual({
|
||||
hideCodeQualityFindings: [[EXAMPLE_LINE_NUMBER]],
|
||||
});
|
||||
});
|
||||
|
||||
mockData.forEach((element) => {
|
||||
it('should set correct props for DiffCodeQuality', () => {
|
||||
const wrapper = createWrapper(element);
|
||||
expect(wrapper.findComponent(DiffCodeQuality).props('codeQuality')).toEqual([
|
||||
{
|
||||
line: EXAMPLE_LINE_NUMBER,
|
||||
description: EXAMPLE_DESCRIPTION,
|
||||
severity: EXAMPLE_SEVERITY,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils';
|
|||
import Vue, { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import DiffView from '~/diffs/components/diff_view.vue';
|
||||
import DiffCodeQuality from '~/diffs/components/diff_code_quality.vue';
|
||||
import DiffLine from '~/diffs/components/diff_line.vue';
|
||||
import { diffCodeQuality } from '../mock_data/diff_code_quality';
|
||||
|
||||
describe('DiffView', () => {
|
||||
|
|
@ -51,28 +51,27 @@ describe('DiffView', () => {
|
|||
return shallowMount(DiffView, { propsData, store, stubs, provide });
|
||||
};
|
||||
|
||||
it('does not render a codeQuality diff view when there is no finding', () => {
|
||||
it('does not render a diff-line component when there is no finding', () => {
|
||||
const wrapper = createWrapper();
|
||||
expect(wrapper.findComponent(DiffCodeQuality).exists()).toBe(false);
|
||||
expect(wrapper.findComponent(DiffLine).exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does render a codeQuality diff view with the correct props when there is a finding & refactorCodeQualityInlineFindings flag is true ', async () => {
|
||||
it('does render a diff-line component with the correct props when there is a finding & refactorCodeQualityInlineFindings flag is true ', async () => {
|
||||
const wrapper = createWrapper(diffCodeQuality, {
|
||||
glFeatures: { refactorCodeQualityInlineFindings: true },
|
||||
});
|
||||
wrapper.findComponent(DiffRow).vm.$emit('toggleCodeQualityFindings', 2);
|
||||
await nextTick();
|
||||
expect(wrapper.findComponent(DiffCodeQuality).exists()).toBe(true);
|
||||
expect(wrapper.findComponent(DiffCodeQuality).props().codeQuality.length).not.toBe(0);
|
||||
expect(wrapper.findComponent(DiffLine).props('line')).toBe(diffCodeQuality.diffLines[2]);
|
||||
});
|
||||
|
||||
it('does not render a codeQuality diff view when there is a finding & refactorCodeQualityInlineFindings flag is false ', async () => {
|
||||
it('does not render a diff-line component when there is a finding & refactorCodeQualityInlineFindings flag is false ', async () => {
|
||||
const wrapper = createWrapper(diffCodeQuality, {
|
||||
glFeatures: { refactorCodeQualityInlineFindings: false },
|
||||
});
|
||||
wrapper.findComponent(DiffRow).vm.$emit('toggleCodeQualityFindings', 2);
|
||||
await nextTick();
|
||||
expect(wrapper.findComponent(DiffCodeQuality).exists()).toBe(false);
|
||||
expect(wrapper.findComponent(DiffLine).exists()).toBe(false);
|
||||
});
|
||||
|
||||
it.each`
|
||||
|
|
|
|||
|
|
@ -1,18 +1,46 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import BranchRules from '~/projects/settings/repository/branch_rules/app.vue';
|
||||
import BranchRules, { i18n } from '~/projects/settings/repository/branch_rules/app.vue';
|
||||
import branchRulesQuery from '~/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql';
|
||||
import createFlash from '~/flash';
|
||||
import { branchRulesMockResponse, propsDataMock } from './mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
describe('Branch rules app', () => {
|
||||
let wrapper;
|
||||
let fakeApollo;
|
||||
|
||||
const createComponent = () => {
|
||||
wrapper = mountExtended(BranchRules);
|
||||
const branchRulesQuerySuccessHandler = jest.fn().mockResolvedValue(branchRulesMockResponse);
|
||||
|
||||
const createComponent = async (branchRulesQueryHandler = branchRulesQuerySuccessHandler) => {
|
||||
fakeApollo = createMockApollo([[branchRulesQuery, branchRulesQueryHandler]]);
|
||||
|
||||
wrapper = mountExtended(BranchRules, {
|
||||
apolloProvider: fakeApollo,
|
||||
propsData: {
|
||||
...propsDataMock,
|
||||
},
|
||||
});
|
||||
|
||||
await waitForPromises();
|
||||
};
|
||||
|
||||
const findTitle = () => wrapper.find('strong');
|
||||
|
||||
beforeEach(() => createComponent());
|
||||
|
||||
it('displays an error if branch rules query fails', async () => {
|
||||
await createComponent(jest.fn().mockRejectedValue());
|
||||
expect(createFlash).toHaveBeenCalledWith({ message: i18n.queryError });
|
||||
});
|
||||
|
||||
it('renders a title', () => {
|
||||
expect(findTitle().text()).toBe('Branch');
|
||||
expect(findTitle().text()).toBe(i18n.heading);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
export const branchRulesMockResponse = {
|
||||
data: {
|
||||
project: {
|
||||
__typename: 'Project',
|
||||
branchRules: {
|
||||
__typename: 'BranchRuleConnection',
|
||||
nodes: [
|
||||
{
|
||||
name: 'master',
|
||||
__typename: 'BranchRule',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const propsDataMock = {
|
||||
projectPath: 'some/project/path',
|
||||
};
|
||||
|
|
@ -50,149 +50,4 @@ RSpec.describe StorageHelper do
|
|||
expect(helper.storage_counters_details(namespace_stats)).to eq(message)
|
||||
end
|
||||
end
|
||||
|
||||
describe "storage_enforcement_banner" do
|
||||
let_it_be_with_refind(:current_user) { create(:user) }
|
||||
let_it_be(:free_group) { create(:group, :with_root_storage_statistics) }
|
||||
let_it_be(:paid_group) { create(:group, :with_root_storage_statistics) }
|
||||
|
||||
before do
|
||||
allow(helper).to receive(:can?).with(current_user, :maintainer_access, free_group).and_return(true)
|
||||
allow(helper).to receive(:can?).with(current_user, :maintainer_access, paid_group).and_return(true)
|
||||
allow(helper).to receive(:current_user) { current_user }
|
||||
allow(paid_group).to receive(:paid?).and_return(true)
|
||||
|
||||
free_group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE)
|
||||
paid_group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE)
|
||||
|
||||
stub_feature_flags(namespace_storage_limit_bypass_date_check: false)
|
||||
end
|
||||
|
||||
describe "#storage_enforcement_banner_info" do
|
||||
it 'returns nil when namespace is not free' do
|
||||
expect(helper.storage_enforcement_banner_info(paid_group)).to be(nil)
|
||||
end
|
||||
|
||||
it 'returns nil when storage_enforcement_date is not set' do
|
||||
allow(free_group).to receive(:storage_enforcement_date).and_return(nil)
|
||||
|
||||
expect(helper.storage_enforcement_banner_info(free_group)).to be(nil)
|
||||
end
|
||||
|
||||
describe 'when storage_enforcement_date is set' do
|
||||
let_it_be(:storage_enforcement_date) { Date.today + 30 }
|
||||
|
||||
before do
|
||||
allow(free_group).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
|
||||
it 'returns nil when current_user do not have access usage quotas page' do
|
||||
allow(helper).to receive(:can?).with(current_user, :maintainer_access, free_group).and_return(false)
|
||||
|
||||
expect(helper.storage_enforcement_banner_info(free_group)).to be(nil)
|
||||
end
|
||||
|
||||
it 'returns nil when namespace_storage_limit_show_preenforcement_banner FF is disabled' do
|
||||
stub_feature_flags(namespace_storage_limit_show_preenforcement_banner: false)
|
||||
|
||||
expect(helper.storage_enforcement_banner_info(free_group)).to be(nil)
|
||||
end
|
||||
|
||||
context 'when current_user can access the usage quotas page' do
|
||||
it 'returns a hash' do
|
||||
used_storage = helper.storage_counter(free_group.root_storage_statistics&.storage_size || 0)
|
||||
|
||||
expect(helper.storage_enforcement_banner_info(free_group)).to eql({
|
||||
text_paragraph_1: "Effective #{storage_enforcement_date}, namespace storage limits will apply to the <strong>#{free_group.name}</strong> namespace. View the <a href=\"/help/user/usage_quotas#namespace-storage-limit-enforcement-schedule\" >rollout schedule for this change</a>.",
|
||||
text_paragraph_2: "The namespace is currently using <strong>#{used_storage}</strong> of namespace storage. Group owners can view namespace storage usage and purchase more from <strong>Group settings > Usage quotas</strong>. <a href=\"/help/user/usage_quotas#manage-your-storage-usage\" >Learn more.</a>",
|
||||
text_paragraph_3: "See our <a href=\"https://about.gitlab.com/pricing/faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier\" >FAQ</a> for more information.",
|
||||
variant: 'warning',
|
||||
namespace_id: free_group.id,
|
||||
callouts_feature_name: 'storage_enforcement_banner_second_enforcement_threshold',
|
||||
callouts_path: '/-/users/group_callouts'
|
||||
})
|
||||
end
|
||||
|
||||
context 'when namespace is under MIN_STORAGE_ENFORCEMENT_USAGE limit' do
|
||||
before do
|
||||
free_group.root_storage_statistics.update!(storage_size: ::Namespace::MIN_STORAGE_ENFORCEMENT_USAGE - 1)
|
||||
end
|
||||
|
||||
it 'returns nil' do
|
||||
expect(helper.storage_enforcement_banner_info(free_group)).to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the given group is a sub-group' do
|
||||
let_it_be(:sub_group) { build(:group) }
|
||||
|
||||
before do
|
||||
allow(helper).to receive(:can?).with(current_user, :maintainer_access, sub_group).and_return(true)
|
||||
allow(sub_group).to receive(:root_ancestor).and_return(free_group)
|
||||
end
|
||||
|
||||
it 'returns the banner hash' do
|
||||
expect(helper.storage_enforcement_banner_info(sub_group).keys).to match_array(%i(text_paragraph_1 text_paragraph_2 text_paragraph_3 variant namespace_id callouts_feature_name callouts_path))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the :storage_banner_bypass_date_check is enabled', :freeze_time do
|
||||
before do
|
||||
stub_feature_flags(namespace_storage_limit_bypass_date_check: true)
|
||||
end
|
||||
|
||||
it 'returns the enforcement info' do
|
||||
expect(helper.storage_enforcement_banner_info(free_group)[:text_paragraph_1]).to include("Effective #{Date.current}, namespace storage limits will apply")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when storage_enforcement_date is set and dismissed callout exists' do
|
||||
before do
|
||||
create(:group_callout,
|
||||
user: current_user,
|
||||
group_id: free_group.id,
|
||||
feature_name: 'storage_enforcement_banner_second_enforcement_threshold')
|
||||
storage_enforcement_date = Date.today + 30
|
||||
allow(free_group).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
end
|
||||
|
||||
it { expect(helper.storage_enforcement_banner_info(free_group)).to be(nil) }
|
||||
end
|
||||
|
||||
context 'callouts_feature_name' do
|
||||
let(:days_from_now) { 45 }
|
||||
|
||||
subject do
|
||||
storage_enforcement_date = Date.today + days_from_now
|
||||
allow(free_group).to receive(:storage_enforcement_date).and_return(storage_enforcement_date)
|
||||
|
||||
helper.storage_enforcement_banner_info(free_group)[:callouts_feature_name]
|
||||
end
|
||||
|
||||
it 'returns first callouts_feature_name' do
|
||||
is_expected.to eq('storage_enforcement_banner_first_enforcement_threshold')
|
||||
end
|
||||
|
||||
context 'returns second callouts_feature_name' do
|
||||
let(:days_from_now) { 20 }
|
||||
|
||||
it { is_expected.to eq('storage_enforcement_banner_second_enforcement_threshold') }
|
||||
end
|
||||
|
||||
context 'returns third callouts_feature_name' do
|
||||
let(:days_from_now) { 13 }
|
||||
|
||||
it { is_expected.to eq('storage_enforcement_banner_third_enforcement_threshold') }
|
||||
end
|
||||
|
||||
context 'returns fourth callouts_feature_name' do
|
||||
let(:days_from_now) { 3 }
|
||||
|
||||
it { is_expected.to eq('storage_enforcement_banner_fourth_enforcement_threshold') }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2662,17 +2662,17 @@ RSpec.describe Ci::Build do
|
|||
|
||||
describe '#ref_slug' do
|
||||
{
|
||||
'master' => 'master',
|
||||
'1-foo' => '1-foo',
|
||||
'fix/1-foo' => 'fix-1-foo',
|
||||
'fix-1-foo' => 'fix-1-foo',
|
||||
'a' * 63 => 'a' * 63,
|
||||
'a' * 64 => 'a' * 63,
|
||||
'FOO' => 'foo',
|
||||
'-' + 'a' * 61 + '-' => 'a' * 61,
|
||||
'-' + 'a' * 62 + '-' => 'a' * 62,
|
||||
'-' + 'a' * 63 + '-' => 'a' * 62,
|
||||
'a' * 62 + ' ' => 'a' * 62
|
||||
'master' => 'master',
|
||||
'1-foo' => '1-foo',
|
||||
'fix/1-foo' => 'fix-1-foo',
|
||||
'fix-1-foo' => 'fix-1-foo',
|
||||
'a' * 63 => 'a' * 63,
|
||||
'a' * 64 => 'a' * 63,
|
||||
'FOO' => 'foo',
|
||||
'-' + 'a' * 61 + '-' => 'a' * 61,
|
||||
'-' + 'a' * 62 + '-' => 'a' * 62,
|
||||
'-' + 'a' * 63 + '-' => 'a' * 62,
|
||||
'a' * 62 + ' ' => 'a' * 62
|
||||
}.each do |ref, slug|
|
||||
it "transforms #{ref} to #{slug}" do
|
||||
build.ref = ref
|
||||
|
|
|
|||
|
|
@ -30,10 +30,8 @@ RSpec.describe Ci::Processable do
|
|||
let_it_be(:downstream_project) { create(:project, :repository) }
|
||||
|
||||
let_it_be_with_refind(:processable) do
|
||||
create(
|
||||
:ci_bridge, :success, pipeline: pipeline, downstream: downstream_project,
|
||||
description: 'a trigger job', stage_id: stage.id
|
||||
)
|
||||
create(:ci_bridge, :success,
|
||||
pipeline: pipeline, downstream: downstream_project, description: 'a trigger job', stage_id: stage.id)
|
||||
end
|
||||
|
||||
let(:clone_accessors) { ::Ci::Bridge.clone_accessors }
|
||||
|
|
@ -208,10 +206,11 @@ RSpec.describe Ci::Processable do
|
|||
let(:environment_name) { 'review/$CI_COMMIT_REF_SLUG-$GITLAB_USER_ID' }
|
||||
|
||||
let!(:processable) do
|
||||
create(:ci_build, :with_deployment, environment: environment_name,
|
||||
options: { environment: { name: environment_name } },
|
||||
pipeline: pipeline, stage_id: stage.id, project: project,
|
||||
user: other_developer)
|
||||
create(:ci_build, :with_deployment,
|
||||
environment: environment_name,
|
||||
options: { environment: { name: environment_name } },
|
||||
pipeline: pipeline, stage_id: stage.id, project: project,
|
||||
user: other_developer)
|
||||
end
|
||||
|
||||
it 're-uses the previous persisted environment' do
|
||||
|
|
|
|||
|
|
@ -605,15 +605,15 @@ RSpec.describe Clusters::Platforms::Kubernetes do
|
|||
{ 'app.gitlab.com/app' => project.full_path_slug, 'app.gitlab.com/env' => 'env-000000' }
|
||||
])
|
||||
expect(rollout_status.instances).to eq([{ pod_name: "kube-pod",
|
||||
stable: true,
|
||||
status: "pending",
|
||||
tooltip: "kube-pod (Pending)",
|
||||
track: "stable" },
|
||||
stable: true,
|
||||
status: "pending",
|
||||
tooltip: "kube-pod (Pending)",
|
||||
track: "stable" },
|
||||
{ pod_name: "Not provided",
|
||||
stable: true,
|
||||
status: "pending",
|
||||
tooltip: "Not provided (Pending)",
|
||||
track: "stable" }])
|
||||
stable: true,
|
||||
status: "pending",
|
||||
tooltip: "Not provided (Pending)",
|
||||
track: "stable" }])
|
||||
end
|
||||
|
||||
context 'with canary ingress' do
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ RSpec.describe ContainerRegistry::Event do
|
|||
let(:target) do
|
||||
{
|
||||
'mediaType' => ContainerRegistry::Client::DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE,
|
||||
'repository' => repository_path,
|
||||
'repository' => repository_path,
|
||||
'tag' => 'latest'
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ RSpec.describe Deployment do
|
|||
it 'executes Deployments::HooksWorker asynchronously' do
|
||||
freeze_time do
|
||||
expect(Deployments::HooksWorker)
|
||||
.to receive(:perform_async).with(deployment_id: deployment.id, status: 'running',
|
||||
status_changed_at: Time.current)
|
||||
.to receive(:perform_async)
|
||||
.with(deployment_id: deployment.id, status: 'running', status_changed_at: Time.current)
|
||||
|
||||
deployment.run!
|
||||
end
|
||||
|
|
@ -200,8 +200,8 @@ RSpec.describe Deployment do
|
|||
it 'executes Deployments::HooksWorker asynchronously' do
|
||||
freeze_time do
|
||||
expect(Deployments::HooksWorker)
|
||||
.to receive(:perform_async).with(deployment_id: deployment.id, status: 'success',
|
||||
status_changed_at: Time.current)
|
||||
.to receive(:perform_async)
|
||||
.with(deployment_id: deployment.id, status: 'success', status_changed_at: Time.current)
|
||||
|
||||
deployment.succeed!
|
||||
end
|
||||
|
|
@ -230,8 +230,8 @@ RSpec.describe Deployment do
|
|||
it 'executes Deployments::HooksWorker asynchronously' do
|
||||
freeze_time do
|
||||
expect(Deployments::HooksWorker)
|
||||
.to receive(:perform_async).with(deployment_id: deployment.id, status: 'failed',
|
||||
status_changed_at: Time.current)
|
||||
.to receive(:perform_async)
|
||||
.with(deployment_id: deployment.id, status: 'failed', status_changed_at: Time.current)
|
||||
|
||||
deployment.drop!
|
||||
end
|
||||
|
|
@ -260,8 +260,8 @@ RSpec.describe Deployment do
|
|||
it 'executes Deployments::HooksWorker asynchronously' do
|
||||
freeze_time do
|
||||
expect(Deployments::HooksWorker)
|
||||
.to receive(:perform_async).with(deployment_id: deployment.id, status: 'canceled',
|
||||
status_changed_at: Time.current)
|
||||
.to receive(:perform_async)
|
||||
.with(deployment_id: deployment.id, status: 'canceled', status_changed_at: Time.current)
|
||||
|
||||
deployment.cancel!
|
||||
end
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ RSpec.describe DesignManagement::Version do
|
|||
it 'puts them in the right buckets' do
|
||||
expect(version.designs_by_event).to match(
|
||||
a_hash_including(
|
||||
'creation' => have_attributes(size: 3),
|
||||
'creation' => have_attributes(size: 3),
|
||||
'modification' => have_attributes(size: 4),
|
||||
'deletion' => have_attributes(size: 5)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2139,8 +2139,7 @@ RSpec.describe Group do
|
|||
let(:another_shared_with_group) { create(:group, parent: group) }
|
||||
|
||||
before do
|
||||
create(:group_group_link, shared_group: nested_group,
|
||||
shared_with_group: another_shared_with_group)
|
||||
create(:group_group_link, shared_group: nested_group, shared_with_group: another_shared_with_group)
|
||||
end
|
||||
|
||||
it 'returns all shared with group ids' do
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ RSpec.describe Integrations::ChatMessage::PipelineMessage do
|
|||
allow(test_project).to receive(:avatar_url).with(only_path: false).and_return(args[:project][:avatar_url])
|
||||
allow(Project).to receive(:find) { test_project }
|
||||
|
||||
test_pipeline = double("A test pipeline", has_yaml_errors?: has_yaml_errors,
|
||||
yaml_errors: "yaml error description here")
|
||||
test_pipeline = double("A test pipeline",
|
||||
has_yaml_errors?: has_yaml_errors, yaml_errors: "yaml error description here")
|
||||
allow(Ci::Pipeline).to receive(:find) { test_pipeline }
|
||||
|
||||
allow(Gitlab::UrlBuilder).to receive(:build).with(test_commit).and_return("http://example.com/commit")
|
||||
|
|
|
|||
|
|
@ -175,9 +175,9 @@ RSpec.describe Integrations::DroneCi, :use_clean_rails_memory_store_caching do
|
|||
end
|
||||
|
||||
{
|
||||
"killed" => :canceled,
|
||||
"killed" => :canceled,
|
||||
"failure" => :failed,
|
||||
"error" => :failed,
|
||||
"error" => :failed,
|
||||
"success" => "success"
|
||||
}.each do |drone_status, our_status|
|
||||
it "sets commit status to #{our_status.inspect} when returned status is #{drone_status.inspect}" do
|
||||
|
|
|
|||
|
|
@ -3729,9 +3729,9 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
|
||||
let(:expected_diff_refs) do
|
||||
Gitlab::Diff::DiffRefs.new(
|
||||
base_sha: subject.merge_request_diff.base_commit_sha,
|
||||
base_sha: subject.merge_request_diff.base_commit_sha,
|
||||
start_sha: subject.merge_request_diff.start_commit_sha,
|
||||
head_sha: subject.merge_request_diff.head_commit_sha
|
||||
head_sha: subject.merge_request_diff.head_commit_sha
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -744,30 +744,30 @@ RSpec.describe Namespace do
|
|||
create(:project,
|
||||
namespace: namespace,
|
||||
statistics: build(:project_statistics,
|
||||
namespace: namespace,
|
||||
repository_size: 101,
|
||||
wiki_size: 505,
|
||||
lfs_objects_size: 202,
|
||||
build_artifacts_size: 303,
|
||||
namespace: namespace,
|
||||
repository_size: 101,
|
||||
wiki_size: 505,
|
||||
lfs_objects_size: 202,
|
||||
build_artifacts_size: 303,
|
||||
pipeline_artifacts_size: 707,
|
||||
packages_size: 404,
|
||||
snippets_size: 605,
|
||||
uploads_size: 808))
|
||||
packages_size: 404,
|
||||
snippets_size: 605,
|
||||
uploads_size: 808))
|
||||
end
|
||||
|
||||
let(:project2) do
|
||||
create(:project,
|
||||
namespace: namespace,
|
||||
statistics: build(:project_statistics,
|
||||
namespace: namespace,
|
||||
repository_size: 10,
|
||||
wiki_size: 50,
|
||||
lfs_objects_size: 20,
|
||||
build_artifacts_size: 30,
|
||||
namespace: namespace,
|
||||
repository_size: 10,
|
||||
wiki_size: 50,
|
||||
lfs_objects_size: 20,
|
||||
build_artifacts_size: 30,
|
||||
pipeline_artifacts_size: 70,
|
||||
packages_size: 40,
|
||||
snippets_size: 60,
|
||||
uploads_size: 80))
|
||||
packages_size: 40,
|
||||
snippets_size: 60,
|
||||
uploads_size: 80))
|
||||
end
|
||||
|
||||
it "sums all project storage counters in the namespace" do
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ RSpec.describe Operations::FeatureFlag do
|
|||
it 'is valid if associated with Operations::FeatureFlags::Strategy models' do
|
||||
project = create(:project)
|
||||
feature_flag = described_class.create!({ name: 'test', project: project, version: 2,
|
||||
strategies_attributes: [{ name: 'default', parameters: {} }] })
|
||||
strategies_attributes: [{ name: 'default', parameters: {} }] })
|
||||
|
||||
expect(feature_flag).to be_valid
|
||||
end
|
||||
|
|
@ -114,13 +114,11 @@ RSpec.describe Operations::FeatureFlag do
|
|||
let_it_be(:project) { create(:project) }
|
||||
|
||||
let!(:feature_flag) do
|
||||
create(:operations_feature_flag, project: project,
|
||||
name: 'feature1', active: true, version: 2)
|
||||
create(:operations_feature_flag, project: project, name: 'feature1', active: true, version: 2)
|
||||
end
|
||||
|
||||
let!(:strategy) do
|
||||
create(:operations_strategy, feature_flag: feature_flag,
|
||||
name: 'default', parameters: {})
|
||||
create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
||||
end
|
||||
|
||||
it 'matches wild cards in the scope' do
|
||||
|
|
@ -141,10 +139,8 @@ RSpec.describe Operations::FeatureFlag do
|
|||
|
||||
it 'returns feature flags ordered by id' do
|
||||
create(:operations_scope, strategy: strategy, environment_scope: 'production')
|
||||
feature_flag_b = create(:operations_feature_flag, project: project,
|
||||
name: 'feature2', active: true, version: 2)
|
||||
strategy_b = create(:operations_strategy, feature_flag: feature_flag_b,
|
||||
name: 'default', parameters: {})
|
||||
feature_flag_b = create(:operations_feature_flag, project: project, name: 'feature2', active: true, version: 2)
|
||||
strategy_b = create(:operations_strategy, feature_flag: feature_flag_b, name: 'default', parameters: {})
|
||||
create(:operations_scope, strategy: strategy_b, environment_scope: '*')
|
||||
|
||||
flags = described_class.for_unleash_client(project, 'production')
|
||||
|
|
|
|||
|
|
@ -32,17 +32,17 @@ RSpec.describe PagesDomain do
|
|||
|
||||
describe "hostname" do
|
||||
{
|
||||
'my.domain.com' => true,
|
||||
'123.456.789' => true,
|
||||
'0x12345.com' => true,
|
||||
'0123123' => true,
|
||||
'a-reserved.com' => true,
|
||||
'my.domain.com' => true,
|
||||
'123.456.789' => true,
|
||||
'0x12345.com' => true,
|
||||
'0123123' => true,
|
||||
'a-reserved.com' => true,
|
||||
'a.b-reserved.com' => true,
|
||||
'reserved.com' => true,
|
||||
'_foo.com' => false,
|
||||
'a.reserved.com' => false,
|
||||
'reserved.com' => true,
|
||||
'_foo.com' => false,
|
||||
'a.reserved.com' => false,
|
||||
'a.b.reserved.com' => false,
|
||||
nil => false
|
||||
nil => false
|
||||
}.each do |value, validity|
|
||||
context "domain #{value.inspect} validity" do
|
||||
before do
|
||||
|
|
@ -66,8 +66,7 @@ RSpec.describe PagesDomain do
|
|||
end
|
||||
|
||||
let(:pages_domain) do
|
||||
build(:pages_domain, certificate: certificate, key: key,
|
||||
auto_ssl_enabled: auto_ssl_enabled).tap do |pd|
|
||||
build(:pages_domain, certificate: certificate, key: key, auto_ssl_enabled: auto_ssl_enabled).tap do |pd|
|
||||
allow(pd).to receive(:project).and_return(project)
|
||||
pd.valid?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -359,10 +359,10 @@ RSpec.describe RemoteMirror, :mailer do
|
|||
|
||||
it 'resets all the columns when URL changes' do
|
||||
remote_mirror.update!(last_error: Time.current,
|
||||
last_update_at: Time.current,
|
||||
last_successful_update_at: Time.current,
|
||||
update_status: 'started',
|
||||
error_notification_sent: true)
|
||||
last_update_at: Time.current,
|
||||
last_successful_update_at: Time.current,
|
||||
update_status: 'started',
|
||||
error_notification_sent: true)
|
||||
|
||||
expect { remote_mirror.update_attribute(:url, 'http://new.example.com') }
|
||||
.to change { remote_mirror.last_error }.to(nil)
|
||||
|
|
|
|||
|
|
@ -3306,7 +3306,7 @@ RSpec.describe Repository do
|
|||
before do
|
||||
storages = {
|
||||
'default' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories'),
|
||||
'picked' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories')
|
||||
'picked' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/repositories')
|
||||
}
|
||||
|
||||
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
|
||||
|
|
|
|||
|
|
@ -2071,11 +2071,12 @@ RSpec.describe User do
|
|||
context 'user has existing U2F registration' do
|
||||
it 'returns false' do
|
||||
device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5))
|
||||
create(:u2f_registration, name: 'my u2f device',
|
||||
user: user,
|
||||
certificate: Base64.strict_encode64(device.cert_raw),
|
||||
key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
|
||||
public_key: Base64.strict_encode64(device.origin_public_key_raw))
|
||||
create(:u2f_registration,
|
||||
name: 'my u2f device',
|
||||
user: user,
|
||||
certificate: Base64.strict_encode64(device.cert_raw),
|
||||
key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
|
||||
public_key: Base64.strict_encode64(device.origin_public_key_raw))
|
||||
|
||||
expect(user.two_factor_u2f_enabled?).to eq(false)
|
||||
end
|
||||
|
|
@ -2094,11 +2095,12 @@ RSpec.describe User do
|
|||
context 'user has existing U2F registration' do
|
||||
it 'returns true' do
|
||||
device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5))
|
||||
create(:u2f_registration, name: 'my u2f device',
|
||||
user: user,
|
||||
certificate: Base64.strict_encode64(device.cert_raw),
|
||||
key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
|
||||
public_key: Base64.strict_encode64(device.origin_public_key_raw))
|
||||
create(:u2f_registration,
|
||||
name: 'my u2f device',
|
||||
user: user,
|
||||
certificate: Base64.strict_encode64(device.cert_raw),
|
||||
key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
|
||||
public_key: Base64.strict_encode64(device.origin_public_key_raw))
|
||||
|
||||
expect(user.two_factor_u2f_enabled?).to eq(true)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ RSpec.describe ProjectPresenter do
|
|||
expect(release).to be_truthy
|
||||
expect(presenter.releases_anchor_data).to have_attributes(
|
||||
is_link: true,
|
||||
label: a_string_including("#{project.releases.count}"),
|
||||
label: a_string_including("#{project.releases.count}"),
|
||||
link: presenter.project_releases_path(project)
|
||||
)
|
||||
end
|
||||
|
|
@ -216,7 +216,7 @@ RSpec.describe ProjectPresenter do
|
|||
it 'returns storage data' do
|
||||
expect(presenter.storage_anchor_data).to have_attributes(
|
||||
is_link: true,
|
||||
label: a_string_including('0 Bytes'),
|
||||
label: a_string_including('0 Bytes'),
|
||||
link: nil
|
||||
)
|
||||
end
|
||||
|
|
@ -270,7 +270,7 @@ RSpec.describe ProjectPresenter do
|
|||
it 'returns storage data without usage quotas link for non-admin users' do
|
||||
expect(presenter.storage_anchor_data).to have_attributes(
|
||||
is_link: true,
|
||||
label: a_string_including('0 Bytes'),
|
||||
label: a_string_including('0 Bytes'),
|
||||
link: nil
|
||||
)
|
||||
end
|
||||
|
|
@ -280,7 +280,7 @@ RSpec.describe ProjectPresenter do
|
|||
|
||||
expect(presenter.storage_anchor_data).to have_attributes(
|
||||
is_link: true,
|
||||
label: a_string_including('0 Bytes'),
|
||||
label: a_string_including('0 Bytes'),
|
||||
link: presenter.project_usage_quotas_path(project)
|
||||
)
|
||||
end
|
||||
|
|
@ -293,7 +293,7 @@ RSpec.describe ProjectPresenter do
|
|||
expect(release).to be_truthy
|
||||
expect(presenter.releases_anchor_data).to have_attributes(
|
||||
is_link: true,
|
||||
label: a_string_including("#{project.releases.count}"),
|
||||
label: a_string_including("#{project.releases.count}"),
|
||||
link: presenter.project_releases_path(project)
|
||||
)
|
||||
end
|
||||
|
|
@ -566,7 +566,7 @@ RSpec.describe ProjectPresenter do
|
|||
it 'returns upload_anchor_data' do
|
||||
expect(presenter.upload_anchor_data).to have_attributes(
|
||||
is_link: false,
|
||||
label: a_string_including('Upload file'),
|
||||
label: a_string_including('Upload file'),
|
||||
data: {
|
||||
"can_push_code" => "true",
|
||||
"original_branch" => "master",
|
||||
|
|
|
|||
Loading…
Reference in New Issue