Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
ff2a881e20
commit
9968d39440
|
|
@ -302,7 +302,7 @@ export default {
|
|||
|
||||
<div :class="newSubgroup && 'row gl-mb-3'">
|
||||
<gl-form-group v-if="newSubgroup" class="col-sm-6 gl-pr-0" :label="inputLabels.subgroupPath">
|
||||
<div class="input-group gl-flex-nowrap">
|
||||
<div class="input-group gl-flex-wrap-nowrap">
|
||||
<gl-button-group class="gl-w-full">
|
||||
<gl-button class="js-group-namespace-button gl-text-truncate gl-flex-grow-0!" label>
|
||||
{{ basePath }}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex-center gl-flex-nowrap text-nowrap js-ide-status-mr">
|
||||
<div class="d-flex-center gl-flex-wrap-nowrap text-nowrap js-ide-status-mr">
|
||||
<gl-icon name="merge-request" />
|
||||
<span class="ml-1 d-none d-sm-block">{{ s__('WebIDE|Merge request') }}</span>
|
||||
<gl-link class="ml-1" :href="url">{{ text }}</gl-link>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<dropdown-button class="gl-w-full!">
|
||||
<span class="row gl-flex-nowrap">
|
||||
<span class="row gl-flex-wrap-nowrap">
|
||||
<span class="col-auto flex-fill text-truncate">
|
||||
<gl-icon :size="16" :aria-label="__('Current Branch')" name="branch" /> {{ branchLabel }}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ export default {
|
|||
</div>
|
||||
<div class="gl-w-full gl-display-flex">
|
||||
<ul
|
||||
class="merge-request-tabs nav-tabs nav nav-links gl-display-flex gl-flex-nowrap gl-m-0 gl-p-0 gl-border-b-0"
|
||||
class="merge-request-tabs nav-tabs nav nav-links gl-display-flex gl-flex-wrap-nowrap gl-m-0 gl-p-0 gl-border-b-0"
|
||||
>
|
||||
<li
|
||||
v-for="(tab, index) in tabs"
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export default {
|
|||
<status-icon :icon-name="data.icon.name" :size="12" class="gl-m-auto" />
|
||||
</div>
|
||||
<div class="gl-w-full">
|
||||
<div class="gl-display-flex gl-flex-nowrap">
|
||||
<div class="gl-display-flex gl-flex-wrap-nowrap">
|
||||
<div class="gl-flex-wrap gl-display-flex gl-w-full">
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<p v-safe-html="generateText(data.text)" class="gl-m-0"></p>
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
<script>
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
dashboardUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
metricEmbedComponent: null,
|
||||
namespace: 'alertMetrics',
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.dashboardUrl) {
|
||||
Promise.all([
|
||||
import('~/monitoring/components/embeds/metric_embed.vue'),
|
||||
import('~/monitoring/stores'),
|
||||
])
|
||||
.then(([{ default: MetricEmbed }, { monitoringDashboard }]) => {
|
||||
this.$store = new Vuex.Store({
|
||||
modules: {
|
||||
[this.namespace]: monitoringDashboard,
|
||||
},
|
||||
});
|
||||
this.metricEmbedComponent = MetricEmbed;
|
||||
})
|
||||
.catch((e) => Sentry.captureException(e));
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-py-3">
|
||||
<div v-if="dashboardUrl" ref="metricsChart">
|
||||
<component
|
||||
:is="metricEmbedComponent"
|
||||
v-if="metricEmbedComponent"
|
||||
:dashboard-url="dashboardUrl"
|
||||
:namespace="namespace"
|
||||
/>
|
||||
</div>
|
||||
<div v-else ref="emptyState">
|
||||
{{ s__("AlertManagement|Metrics weren't available in the alerts payload.") }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -295,7 +295,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="form-row gl-mb-5 work-item-assignees gl-relative gl-flex-nowrap">
|
||||
<div class="form-row gl-mb-5 work-item-assignees gl-relative gl-flex-wrap-nowrap">
|
||||
<span
|
||||
:id="assigneesTitleId"
|
||||
class="gl-font-weight-bold gl-mt-2 col-lg-2 col-3 gl-pt-2 min-w-fit-content gl-overflow-wrap-break"
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="form-row gl-mb-5 work-item-labels gl-relative gl-flex-nowrap">
|
||||
<div class="form-row gl-mb-5 work-item-labels gl-relative gl-flex-wrap-nowrap">
|
||||
<span
|
||||
:id="labelsTitleId"
|
||||
class="gl-font-weight-bold gl-mt-2 col-lg-2 col-3 gl-pt-2 min-w-fit-content gl-overflow-wrap-break"
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<gl-form-group
|
||||
class="work-item-dropdown gl-flex-nowrap"
|
||||
class="work-item-dropdown gl-flex-wrap-nowrap"
|
||||
:label="$options.i18n.MILESTONE"
|
||||
label-for="milestone-value"
|
||||
label-class="gl-pb-0! gl-mt-3 gl-overflow-wrap-break"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
= text_field_tag :name, @name, placeholder: "My awesome project", class: "js-project-name form-control gl-form-input input-lg", autofocus: true, required: true, aria: { required: true }, data: { qa_selector: 'project_name_field' }
|
||||
.form-group.col-12.col-sm-6.gl-pr-0
|
||||
= label_tag :namespace_id, _('Project URL'), class: 'label-bold'
|
||||
.input-group.gl-flex-nowrap
|
||||
.input-group.gl-flex-wrap-nowrap
|
||||
- if current_user.can_select_namespace?
|
||||
- namespace_id = namespace_id_from(params)
|
||||
.js-vue-new-project-url-select{ data: { namespace_full_path: GroupFinder.new(current_user).execute(id: namespace_id)&.full_path || current_user.namespace.full_path,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
.form-group.project-path.col-sm-6.gl-pr-0
|
||||
= f.label :namespace_id, class: 'label-bold' do
|
||||
%span= _('Project URL')
|
||||
.input-group.gl-flex-nowrap
|
||||
.input-group.gl-flex-wrap-nowrap
|
||||
- if current_user.can_select_namespace?
|
||||
- namespace_id = namespace_id_from(params)
|
||||
.js-vue-new-project-url-select{ data: { namespace_full_path: GroupFinder.new(current_user).execute(id: namespace_id)&.full_path || @current_user_group&.full_path,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
- f ||= local_assigns[:f]
|
||||
|
||||
.project-templates-buttons
|
||||
= gl_tabs_nav({ class: 'nav-links scrolling-tabs gl-display-flex gl-flex-grow-1 gl-flex-nowrap gl-border-0' }) do
|
||||
= gl_tabs_nav({ class: 'nav-links scrolling-tabs gl-display-flex gl-flex-grow-1 gl-flex-wrap-nowrap gl-border-0' }) do
|
||||
= gl_tab_link_to '#built-in', tab_class: 'built-in-tab', class: 'active', data: { toggle: 'tab' } do
|
||||
= _('Built-in')
|
||||
= gl_tab_counter_badge Gitlab::ProjectTemplate.all.count + Gitlab::SampleDataTemplate.all.count
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
= render "projects/merge_requests/mr_box"
|
||||
.merge-request-tabs-holder{ class: "#{'js-tabs-affix' unless ENV['RAILS_ENV'] == 'test'} #{'gl-static' if moved_mr_sidebar_enabled?}" }
|
||||
.merge-request-tabs-container.gl-display-flex.gl-justify-content-space-between{ class: "#{'is-merge-request' if Feature.enabled?(:moved_mr_sidebar, @project) && !fluid_layout}" }
|
||||
%ul.merge-request-tabs.nav-tabs.nav.nav-links.gl-display-flex.gl-flex-nowrap.gl-m-0.gl-p-0{ class: "#{'gl-w-full gl-lg-w-auto!' if Feature.enabled?(:moved_mr_sidebar, @project)}" }
|
||||
%ul.merge-request-tabs.nav-tabs.nav.nav-links.gl-display-flex.gl-flex-wrap-nowrap.gl-m-0.gl-p-0{ class: "#{'gl-w-full gl-lg-w-auto!' if Feature.enabled?(:moved_mr_sidebar, @project)}" }
|
||||
= render "projects/merge_requests/tabs/tab", class: "notes-tab", qa_selector: "notes_tab" do
|
||||
= tab_link_for @merge_request, :show, force_link: @commit.present? do
|
||||
= _("Overview")
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
|
||||
.fade-left= sprite_icon('chevron-lg-left', size: 12)
|
||||
.fade-right= sprite_icon('chevron-lg-right', size: 12)
|
||||
%ul.merge-request-tabs.nav.nav-tabs.nav-links.no-top.no-bottom.gl-display-flex.gl-flex-nowrap.gl-m-0.gl-p-0.js-tabs-affix
|
||||
%ul.merge-request-tabs.nav.nav-tabs.nav-links.no-top.no-bottom.gl-display-flex.gl-flex-wrap-nowrap.gl-m-0.gl-p-0.js-tabs-affix
|
||||
%li.commits-tab.new-tab
|
||||
= link_to url_for(safe_params), data: {target: 'div#commits', action: 'new', toggle: 'tabvue'} do
|
||||
= _("Commits")
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
- include_private = local_assigns.fetch(:include_private, false)
|
||||
- params[:scope] ||= []
|
||||
|
||||
= gl_tabs_nav({ class: 'js-snippets-nav-tabs gl-border-b-0 gl-overflow-x-auto gl-flex-grow-1 gl-flex-nowrap' }) do
|
||||
= gl_tabs_nav({ class: 'js-snippets-nav-tabs gl-border-b-0 gl-overflow-x-auto gl-flex-grow-1 gl-flex-wrap-nowrap' }) do
|
||||
= gl_tab_link_to subject_snippets_path(subject), { item_active: params[:scope].empty? } do
|
||||
= _('All')
|
||||
= gl_tab_counter_badge(include_private ? counts[:total] : counts[:are_public_or_internal])
|
||||
|
|
|
|||
|
|
@ -8,11 +8,9 @@ class AddIndexToVulnerabilityFindingsOnUuid < Gitlab::Database::Migration[2.1]
|
|||
# TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/397740
|
||||
|
||||
def up
|
||||
index_sql = <<-SQL
|
||||
prepare_async_index_from_sql <<-SQL
|
||||
CREATE UNIQUE INDEX CONCURRENTLY #{INDEX_NAME} ON vulnerability_occurrences (uuid) include (vulnerability_id);
|
||||
SQL
|
||||
|
||||
prepare_async_index_from_sql(:vulnerability_occurrences, INDEX_NAME, index_sql)
|
||||
end
|
||||
|
||||
def down
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
status: proposed
|
||||
status: ongoing
|
||||
creation-date: "2022-11-25"
|
||||
authors: [ "@theoretick" ]
|
||||
coach: "@DylanGriffith"
|
||||
|
|
@ -123,6 +123,23 @@ Given our existing familiarity with the tool and its extensibility, it should
|
|||
remain our engine of choice. Changes to the detection engine are out of scope
|
||||
unless benchmarking unveils performance concerns.
|
||||
|
||||
Notable alternatives include high-performance regex engines such as [hyperscan](https://github.com/intel/hyperscan) or it's portable fork [vectorscan](https://github.com/VectorCamp/vectorscan).
|
||||
|
||||
### High-level architecture
|
||||
|
||||
The implementation of the secret scanning service is highly dependent on the outcomes of our benchmarking
|
||||
and capacity planning against both GitLab.com and our
|
||||
[Reference Architectures](../../../administration/reference_architectures/index.md).
|
||||
As the scanning capability must be an on-by-default component of both our SaaS and self-managed
|
||||
instances [the PoC](#iterations), the deployment characteristics must be considered to determine whether
|
||||
this is a standalone component or executed as a subprocess of the existing Sidekiq worker fleet
|
||||
(similar to the implementation of our Elasticsearch indexing service).
|
||||
|
||||
Similarly, the scan target volume will require a robust and scalable enqueueing system to limit resource consumption.
|
||||
|
||||
See [this thread](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105142#note_1194863310)
|
||||
for past discussion around scaling approaches.
|
||||
|
||||
### Push event detection flow
|
||||
|
||||
```mermaid
|
||||
|
|
@ -151,17 +168,20 @@ sequenceDiagram
|
|||
|
||||
## Iterations
|
||||
|
||||
1. Requirements definition for detection coverage and actions
|
||||
1. PoC of secret scanning service
|
||||
1. gRPC commit retrieval from Gitaly
|
||||
1. blob scanning
|
||||
1. benchmarking of issuables, comments, job logs and blobs to gain confidence that the total costs will be viable
|
||||
1. Implementation of secret scanning service MVC (targeting individual commits)
|
||||
1. Security and readiness review
|
||||
1. Deployment and monitoring
|
||||
1. Implementation of secret scanning service MVC (targeting arbitrary text blobs)
|
||||
1. Deployment and monitoring
|
||||
1. High priority domain object rollout (priority `TBD`)
|
||||
1. Issuable comments
|
||||
1. Issuable bodies
|
||||
1. Job logs
|
||||
- [x] Define [requirements for detection coverage and actions](https://gitlab.com/gitlab-org/gitlab/-/issues/376716)
|
||||
- [x] Implement [Clientside detection of GitLab tokens within comments/issues](https://gitlab.com/gitlab-org/gitlab/-/issues/368434)
|
||||
- [ ] PoC of secret scanning service
|
||||
- [ ] Benchmarking of issuables, comments, job logs and blobs to gain confidence that the total costs will be viable
|
||||
- [ ] Capacity planning for addition of service component to Reference Architectures headroom
|
||||
- [ ] Service capabilities
|
||||
- [ ] gRPC commit retrieval from Gitaly
|
||||
- [ ] blob scanning
|
||||
- [ ] Implementation of secret scanning service MVC (targeting individual commits)
|
||||
- [ ] Security and readiness review
|
||||
- [ ] Deployment and monitoring
|
||||
- [ ] Implementation of secret scanning service MVC (targeting arbitrary text blobs)
|
||||
- [ ] Deployment and monitoring
|
||||
- [ ] High priority domain object rollout (priority `TBD`)
|
||||
- [ ] Issuable comments
|
||||
- [ ] Issuable bodies
|
||||
- [ ] Job logs
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ tab of the pipeline's details page.
|
|||
|
||||
### Project quality view
|
||||
|
||||
The project quality view displays an overview of the code quality findings.
|
||||
The project quality view displays an overview of the code quality findings. The view can be found under **Analytics > CI/CD**, and requires [`project_quality_summary_page`](../../user/feature_flags.md) feature flag to be enabled for this particular project.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ We recommend that you use fuzz testing in addition to the other security scanner
|
|||
and your own test processes. If you're using [GitLab CI/CD](../../../ci/index.md),
|
||||
you can run your coverage-guided fuzz testing as part your CI/CD workflow.
|
||||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an overview, see [Coverage Fuzzing](https://www.youtube.com/watch?v=bbIenVVcjW0).
|
||||
|
||||
## Coverage-guided fuzz testing process
|
||||
|
||||
The fuzz testing process:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ visible from the source code.
|
|||
Dynamic Application Security Testing (DAST) examines applications for
|
||||
vulnerabilities like these in deployed environments.
|
||||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an overview, see [Dynamic Application Security Testing (DAST)](https://www.youtube.com/watch?v=nbeDUoLZJTo).
|
||||
|
||||
NOTE:
|
||||
To learn how four of the top six attacks were application-based and how
|
||||
to protect your organization, download our
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
Use the dependency list to review your project's dependencies and key
|
||||
details about those dependencies, including their known vulnerabilities. It is a collection of dependencies in your project, including existing and new findings.
|
||||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an overview, see [Project Dependency](https://www.youtube.com/watch?v=ckqkn9Tnbw4).
|
||||
|
||||
To see the dependency list, go to your project and select **Security and Compliance > Dependency list**.
|
||||
|
||||
This information is sometimes referred to as a Software Bill of Materials, SBOM, or BOM.
|
||||
|
|
|
|||
|
|
@ -350,5 +350,17 @@ a minimum of the Guest role in the specified Dependency Proxy group:
|
|||
```plaintext
|
||||
ERROR: gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest: not found
|
||||
|
||||
failed to solve with frontend dockerfile.v0: failed to create LLB definition: gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest: not found
|
||||
failed to solve with frontend dockerfile.v0: failed to create LLB definition:
|
||||
gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest: not found
|
||||
```
|
||||
|
||||
```plaintext
|
||||
ERROR: Job failed: failed to pull image
|
||||
"gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest" with specified policies [always]:
|
||||
Error response from daemon: error parsing HTTP 404 response body:
|
||||
unexpected end of JSON input: "" (manager.go:237:1s)
|
||||
```
|
||||
|
||||
NOTE:
|
||||
The work to correctly display `Access denied` errors in such cases is being tracked in the following issue:
|
||||
[Dependency proxy error reporting confusing - "404/not found" should be "access denied" when not group member](https://gitlab.com/gitlab-org/gitlab/-/issues/354826).
|
||||
|
|
|
|||
|
|
@ -3,14 +3,17 @@ stage: Manage
|
|||
group: Integrations
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
<!--- start_remove The following content will be removed on remove_date: '2024-05-22' -->
|
||||
|
||||
# Slack notifications **(FREE)**
|
||||
# Slack notifications (deprecated) **(FREE)**
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/372411) on GitLab.com
|
||||
in GitLab 15.9 and is [planned for removal](https://gitlab.com/groups/gitlab-org/-/epics/8673).
|
||||
For GitLab.com, use the [GitLab for Slack app](gitlab_slack_application.md) instead.
|
||||
For self-managed GitLab instances, you can continue to use this feature.
|
||||
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/372411) in GitLab 15.9
|
||||
and is planned for removal in 17.0. Use the [GitLab for Slack app](gitlab_slack_application.md) instead.
|
||||
This change is a breaking change.
|
||||
|
||||
For the planned support of the GitLab for Slack app for self-managed instances,
|
||||
see [epic 1211](https://gitlab.com/groups/gitlab-org/-/epics/1211).
|
||||
|
||||
The Slack notifications integration enables your GitLab project to send events
|
||||
(such as issue creation) to your existing Slack team as notifications. Setting up
|
||||
|
|
@ -150,3 +153,5 @@ p.each do |project|
|
|||
project.slack_integration.update!(:active, false)
|
||||
end
|
||||
```
|
||||
|
||||
<!--- end_remove -->
|
||||
|
|
|
|||
|
|
@ -77,11 +77,13 @@ module Gitlab
|
|||
async_index
|
||||
end
|
||||
|
||||
def prepare_async_index_from_sql(table_name, index_name, definition)
|
||||
def prepare_async_index_from_sql(definition)
|
||||
Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
|
||||
|
||||
return unless async_index_creation_available?
|
||||
|
||||
table_name, index_name = extract_table_and_index_names_from_concurrent_index!(definition)
|
||||
|
||||
if index_name_exists?(table_name, index_name)
|
||||
Gitlab::AppLogger.warn(
|
||||
message: 'Index not prepared because it already exists',
|
||||
|
|
@ -137,7 +139,30 @@ module Gitlab
|
|||
end
|
||||
|
||||
def async_index_creation_available?
|
||||
connection.table_exists?(:postgres_async_indexes)
|
||||
table_exists?(:postgres_async_indexes)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
delegate :table_exists?, to: :connection, private: true
|
||||
|
||||
def extract_table_and_index_names_from_concurrent_index!(definition)
|
||||
statement = index_statement_from!(definition)
|
||||
|
||||
raise 'Index statement not found!' unless statement
|
||||
raise 'Index must be created concurrently!' unless statement.concurrent
|
||||
raise 'Table does not exist!' unless table_exists?(statement.relation.relname)
|
||||
|
||||
[statement.relation.relname, statement.idxname]
|
||||
end
|
||||
|
||||
# This raises `PgQuery::ParseError` if the given statement
|
||||
# is syntactically incorrect, therefore, validates that the
|
||||
# index definition is correct.
|
||||
def index_statement_from!(definition)
|
||||
parsed_query = PgQuery.parse(definition)
|
||||
|
||||
parsed_query.tree.stmts[0].stmt.index_stmt
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3822,9 +3822,6 @@ msgstr ""
|
|||
msgid "AlertManagement|Metrics"
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|Metrics weren't available in the alerts payload."
|
||||
msgstr ""
|
||||
|
||||
msgid "AlertManagement|More information"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -25468,6 +25465,9 @@ msgstr ""
|
|||
msgid "Learn more."
|
||||
msgstr ""
|
||||
|
||||
msgid "Learn more: %{url}"
|
||||
msgstr ""
|
||||
|
||||
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -28369,19 +28369,10 @@ msgstr ""
|
|||
msgid "NamespaceStorageSize|push to your repository, create pipelines, create issues or add comments. To reduce storage capacity, delete unused repositories, artifacts, wikis, issues, and pipelines."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|%{name_with_link} namespace has approximately %{percent} (%{size}) namespace storage space remaining."
|
||||
msgid "NamespaceStorage|%{name_with_link} is now read-only. Projects under this namespace are locked and actions are restricted."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|%{name_with_link} namespace has exceeded its namespace storage limit."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|%{name}(%{url}) namespace has approximately %{percent} (%{size}) namespace storage space remaining."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|%{name}(%{url}) namespace has exceeded its namespace storage limit."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|Action required: Approximately %{percentage_of_available_storage}%% of namespace storage remains for %{namespace_name}"
|
||||
msgid "NamespaceStorage|%{name} is now read-only. Projects under this namespace are locked and actions are restricted."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|Action required: Storage has been exceeded for %{namespace_name}"
|
||||
|
|
@ -28390,10 +28381,37 @@ msgstr ""
|
|||
msgid "NamespaceStorage|Buy more storage"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|We recommend that you buy additional storage to ensure your service is not interrupted."
|
||||
msgid "NamespaceStorage|If %{name_with_link} exceeds the storage quota, all projects in the namespace will be locked and actions will be restricted."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|We recommend that you buy additional storage to resume normal service."
|
||||
msgid "NamespaceStorage|If %{name} exceeds the storage quota, all projects in the namespace will be locked and actions will be restricted."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|Learn about which actions are restricted: %{url}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|Learn about which actions become restricted: %{url}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|Manage your storage usage or purchase additional storage."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|See storage usage statistics: %{url}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|Which actions are restricted?"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|Which actions become restricted?"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
|
||||
|
|
|
|||
|
|
@ -348,7 +348,8 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
|
|||
expect(page).to have_content('Invalid two-factor code')
|
||||
end
|
||||
|
||||
it 'allows login with invalid code, then valid code' do
|
||||
it 'allows login with invalid code, then valid code',
|
||||
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402322' do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_authenticated_counter)
|
||||
.and increment(:user_two_factor_authenticated_counter)
|
||||
|
|
@ -362,7 +363,8 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
|
|||
expect(page).to have_current_path root_path, ignore_query: true
|
||||
end
|
||||
|
||||
it 'triggers ActiveSession.cleanup for the user', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402322' do
|
||||
it 'triggers ActiveSession.cleanup for the user',
|
||||
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/402322' do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_authenticated_counter)
|
||||
.and increment(:user_two_factor_authenticated_counter)
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import MetricEmbed from '~/monitoring/components/embeds/metric_embed.vue';
|
||||
import AlertMetrics from '~/vue_shared/alert_details/components/alert_metrics.vue';
|
||||
|
||||
jest.mock('~/monitoring/stores', () => ({
|
||||
monitoringDashboard: {},
|
||||
}));
|
||||
|
||||
jest.mock('~/monitoring/components/embeds/metric_embed.vue', () => ({
|
||||
render(h) {
|
||||
return h('div');
|
||||
},
|
||||
}));
|
||||
|
||||
describe('Alert Metrics', () => {
|
||||
let wrapper;
|
||||
const mock = new MockAdapter(axios);
|
||||
|
||||
function mountComponent({ props } = {}) {
|
||||
wrapper = shallowMount(AlertMetrics, {
|
||||
propsData: {
|
||||
...props,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const findChart = () => wrapper.findComponent(MetricEmbed);
|
||||
const findEmptyState = () => wrapper.findComponent({ ref: 'emptyState' });
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
describe('Empty state', () => {
|
||||
it('should display a message when metrics dashboard url is not provided', () => {
|
||||
mountComponent();
|
||||
expect(findChart().exists()).toBe(false);
|
||||
expect(findEmptyState().text()).toBe("Metrics weren't available in the alerts payload.");
|
||||
});
|
||||
});
|
||||
|
||||
describe('Chart', () => {
|
||||
it('should be rendered when dashboard url is provided', async () => {
|
||||
mountComponent({ props: { dashboardUrl: 'metrics.url' } });
|
||||
|
||||
await waitForPromises();
|
||||
await nextTick();
|
||||
|
||||
expect(findEmptyState().exists()).toBe(false);
|
||||
expect(findChart().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -144,10 +144,10 @@ RSpec.describe Gitlab::Database::AsyncIndexes::MigrationHelpers, feature_categor
|
|||
end
|
||||
|
||||
describe '#prepare_async_index_from_sql' do
|
||||
let(:index_definition) { "CREATE INDEX #{index_name} ON #{table_name} USING btree(id)" }
|
||||
let(:index_definition) { "CREATE INDEX CONCURRENTLY #{index_name} ON #{table_name} USING btree(id)" }
|
||||
|
||||
subject(:prepare_async_index_from_sql) do
|
||||
migration.prepare_async_index_from_sql(table_name, index_name, index_definition)
|
||||
migration.prepare_async_index_from_sql(index_definition)
|
||||
end
|
||||
|
||||
before do
|
||||
|
|
@ -162,6 +162,33 @@ RSpec.describe Gitlab::Database::AsyncIndexes::MigrationHelpers, feature_categor
|
|||
expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to have_received(:require_ddl_mode!)
|
||||
end
|
||||
|
||||
context 'when the given index is invalid' do
|
||||
let(:index_definition) { "SELECT FROM users" }
|
||||
|
||||
it 'raises a RuntimeError' do
|
||||
expect { prepare_async_index_from_sql }.to raise_error(RuntimeError, 'Index statement not found!')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the given index is valid' do
|
||||
context 'when the index algorithm is not concurrent' do
|
||||
let(:index_definition) { "CREATE INDEX #{index_name} ON #{table_name} USING btree(id)" }
|
||||
|
||||
it 'raises a RuntimeError' do
|
||||
expect { prepare_async_index_from_sql }.to raise_error(RuntimeError, 'Index must be created concurrently!')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the index algorithm is concurrent' do
|
||||
context 'when the statement tries to create an index for non-existing table' do
|
||||
let(:index_definition) { "CREATE INDEX CONCURRENTLY #{index_name} ON foo_table USING btree(id)" }
|
||||
|
||||
it 'raises a RuntimeError' do
|
||||
expect { prepare_async_index_from_sql }.to raise_error(RuntimeError, 'Table does not exist!')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the statement tries to create an index for an existing table' do
|
||||
context 'when the async index creation is not available' do
|
||||
before do
|
||||
connection.drop_table(:postgres_async_indexes)
|
||||
|
|
@ -198,6 +225,9 @@ RSpec.describe Gitlab::Database::AsyncIndexes::MigrationHelpers, feature_categor
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#prepare_async_index_removal' do
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -151,9 +151,27 @@ RSpec.describe Notify do
|
|||
it 'has the correct subject and body' do
|
||||
aggregate_failures do
|
||||
is_expected.to have_referable_subject(issue, reply: true)
|
||||
is_expected.to have_body_text(previous_assignee.name)
|
||||
is_expected.to have_body_text(assignee.name)
|
||||
is_expected.to have_body_text(project_issue_path(project, issue))
|
||||
is_expected.to have_body_text("Assignee changed from <strong>#{previous_assignee.name}</strong> to <strong>#{assignee.name}</strong>")
|
||||
is_expected.to have_body_text(%(<a href="#{project_issue_url(project, issue)}">view it on GitLab</a>))
|
||||
is_expected.to have_body_text("You're receiving this email because of your account")
|
||||
end
|
||||
end
|
||||
|
||||
context 'without new assignee' do
|
||||
before do
|
||||
issue.update!(assignees: [])
|
||||
end
|
||||
|
||||
it 'uses "Unassigned" placeholder' do
|
||||
is_expected.to have_body_text("Assignee changed from <strong>#{previous_assignee.name}</strong> to <strong>Unassigned</strong>")
|
||||
end
|
||||
end
|
||||
|
||||
context 'without previous assignees' do
|
||||
subject { described_class.reassigned_issue_email(recipient.id, issue.id, [], current_user.id) }
|
||||
|
||||
it 'uses short text' do
|
||||
is_expected.to have_body_text("Assignee changed to <strong>#{assignee.name}</strong>")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ RSpec.describe CreateTestFailureIssues, feature_category: :tooling do
|
|||
|
||||
### Test file path
|
||||
|
||||
[`#{failed_test['file']}`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/#{failed_test['file']})
|
||||
[`#{failed_test['file']}`](https://gitlab.com/example/gitlab/-/blob/master/#{failed_test['file']})
|
||||
|
||||
<!-- Don't add anything after the report list since it's updated automatically -->
|
||||
### Reports (1)
|
||||
|
|
@ -131,8 +131,11 @@ RSpec.describe CreateTestFailureIssues, feature_category: :tooling do
|
|||
end
|
||||
|
||||
it 'calls CreateIssue#execute(payload)' do
|
||||
stub_const("#{described_class}::FILE_BASE_URL", 'https://gitlab.com/example/gitlab/-/blob/master/')
|
||||
|
||||
expect(CreateIssue).to receive(:new).with(project: project, api_token: api_token)
|
||||
.and_return(create_issue_stub)
|
||||
|
||||
expect(create_issue_stub).to receive(:execute).with(expected_create_payload).and_return(issue_stub)
|
||||
|
||||
creator.upsert(failed_test)
|
||||
|
|
@ -152,7 +155,7 @@ RSpec.describe CreateTestFailureIssues, feature_category: :tooling do
|
|||
|
||||
### Test file path
|
||||
|
||||
[`#{failed_test['file']}`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/#{failed_test['file']})
|
||||
[`#{failed_test['file']}`](https://gitlab.com/example/gitlab/-/blob/master/#{failed_test['file']})
|
||||
|
||||
<!-- Don't add anything after the report list since it's updated automatically -->
|
||||
### Reports (1)
|
||||
|
|
@ -165,7 +168,9 @@ RSpec.describe CreateTestFailureIssues, feature_category: :tooling do
|
|||
double('Issue', iid: 42, title: issue_title, description: issue_description, web_url: 'issue_web_url')
|
||||
end
|
||||
|
||||
let(:update_issue_stub) { double('UpdateIssue') }
|
||||
let(:update_issue_stub) do
|
||||
double('UpdateIssue', description: latest_format_issue_description)
|
||||
end
|
||||
|
||||
let(:expected_update_payload) do
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1107,19 +1107,37 @@ RSpec.describe Issues::UpdateService, :mailer, feature_category: :team_planning
|
|||
end
|
||||
|
||||
context 'updating asssignee_id' do
|
||||
it 'changes assignee' do
|
||||
expect_next_instance_of(NotificationService::Async) do |service|
|
||||
expect(service).to receive(:reassigned_issue).with(issue, user, [user3])
|
||||
end
|
||||
|
||||
update_issue(assignee_ids: [user2.id])
|
||||
|
||||
expect(issue.reload.assignees).to eq([user2])
|
||||
end
|
||||
|
||||
it 'does not update assignee when assignee_id is invalid' do
|
||||
expect(NotificationService).not_to receive(:new)
|
||||
|
||||
update_issue(assignee_ids: [-1])
|
||||
|
||||
expect(issue.reload.assignees).to eq([user3])
|
||||
end
|
||||
|
||||
it 'unassigns assignee when user id is 0' do
|
||||
expect_next_instance_of(NotificationService::Async) do |service|
|
||||
expect(service).to receive(:reassigned_issue).with(issue, user, [user3])
|
||||
end
|
||||
|
||||
update_issue(assignee_ids: [0])
|
||||
|
||||
expect(issue.reload.assignees).to be_empty
|
||||
end
|
||||
|
||||
it 'does not update assignee_id when user cannot read issue' do
|
||||
expect(NotificationService).not_to receive(:new)
|
||||
|
||||
update_issue(assignee_ids: [create(:user).id])
|
||||
|
||||
expect(issue.reload.assignees).to eq([user3])
|
||||
|
|
@ -1130,6 +1148,8 @@ RSpec.describe Issues::UpdateService, :mailer, feature_category: :team_planning
|
|||
|
||||
levels.each do |level|
|
||||
it "does not update with unauthorized assignee when project is #{Gitlab::VisibilityLevel.level_name(level)}" do
|
||||
expect(NotificationService).not_to receive(:new)
|
||||
|
||||
assignee = create(:user)
|
||||
project.update!(visibility_level: level)
|
||||
feature_visibility_attr = :"#{issue.model_name.plural}_access_level"
|
||||
|
|
|
|||
Loading…
Reference in New Issue