Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/pipelines/components/graph_shared/api.js5
-rw-r--r--app/graphql/mutations/namespace/package_settings/update.rb10
-rw-r--r--app/graphql/types/namespace/package_settings_type.rb2
-rw-r--r--app/models/namespace/package_setting.rb4
-rw-r--r--app/models/packages.rb2
-rw-r--r--app/models/repository.rb8
-rw-r--r--app/services/namespaces/package_settings/update_service.rb5
-rw-r--r--app/services/packages/generic/create_package_file_service.rb8
-rw-r--r--app/views/shared/snippets/_snippet.html.haml4
-rw-r--r--changelogs/unreleased/293755-generic-dupe-settings.yml5
-rw-r--r--changelogs/unreleased/327414-agent-proxy-request-count.yml5
-rw-r--r--db/migrate/20210429192653_add_generic_package_duplicate_settings_to_namespace_package_settings.rb11
-rw-r--r--db/migrate/20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex.rb15
-rw-r--r--db/schema_migrations/202104291926531
-rw-r--r--db/schema_migrations/202104291931061
-rw-r--r--db/structure.sql3
-rw-r--r--doc/api/graphql/reference/index.md4
-rw-r--r--doc/ci/yaml/README.md16
-rw-r--r--doc/development/internal_api.md3
-rw-r--r--doc/development/usage_ping/dictionary.md12
-rw-r--r--doc/topics/git/numerous_undo_possibilities_in_git/index.md255
-rw-r--r--lib/api/generic_packages.rb2
-rw-r--r--lib/api/internal/kubernetes.rb16
-rw-r--r--lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb24
-rw-r--r--qa/qa/page/dashboard/snippet/index.rb22
-rw-r--r--qa/qa/resource/snippet.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb82
-rw-r--r--spec/factories/namespace_package_settings.rb3
-rw-r--r--spec/frontend/pipelines/graph_shared/links_layer_spec.js14
-rw-r--r--spec/graphql/mutations/namespace/package_settings/update_spec.rb12
-rw-r--r--spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb56
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb1
-rw-r--r--spec/models/namespace/package_setting_spec.rb21
-rw-r--r--spec/models/repository_spec.rb61
-rw-r--r--spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb12
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb12
-rw-r--r--spec/services/namespaces/package_settings/update_service_spec.rb11
-rw-r--r--spec/services/packages/generic/create_package_file_service_spec.rb42
-rw-r--r--spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb4
39 files changed, 543 insertions, 233 deletions
diff --git a/app/assets/javascripts/pipelines/components/graph_shared/api.js b/app/assets/javascripts/pipelines/components/graph_shared/api.js
index 49cd04d11e9..0fe7d9ffda3 100644
--- a/app/assets/javascripts/pipelines/components/graph_shared/api.js
+++ b/app/assets/javascripts/pipelines/components/graph_shared/api.js
@@ -2,6 +2,11 @@ import axios from '~/lib/utils/axios_utils';
import { reportToSentry } from '../../utils';
export const reportPerformance = (path, stats) => {
+ // FIXME: https://gitlab.com/gitlab-org/gitlab/-/issues/330245
+ if (!path) {
+ return;
+ }
+
axios.post(path, stats).catch((err) => {
reportToSentry('links_inner_perf', `error: ${err}`);
});
diff --git a/app/graphql/mutations/namespace/package_settings/update.rb b/app/graphql/mutations/namespace/package_settings/update.rb
index ca21c3418fc..75c80cfbd3e 100644
--- a/app/graphql/mutations/namespace/package_settings/update.rb
+++ b/app/graphql/mutations/namespace/package_settings/update.rb
@@ -25,6 +25,16 @@ module Mutations
required: false,
description: copy_field_description(Types::Namespace::PackageSettingsType, :maven_duplicate_exception_regex)
+ argument :generic_duplicates_allowed,
+ GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: copy_field_description(Types::Namespace::PackageSettingsType, :generic_duplicates_allowed)
+
+ argument :generic_duplicate_exception_regex,
+ Types::UntrustedRegexp,
+ required: false,
+ description: copy_field_description(Types::Namespace::PackageSettingsType, :generic_duplicate_exception_regex)
+
field :package_settings,
Types::Namespace::PackageSettingsType,
null: true,
diff --git a/app/graphql/types/namespace/package_settings_type.rb b/app/graphql/types/namespace/package_settings_type.rb
index 0720a1cfb4b..af091515979 100644
--- a/app/graphql/types/namespace/package_settings_type.rb
+++ b/app/graphql/types/namespace/package_settings_type.rb
@@ -10,5 +10,7 @@ module Types
field :maven_duplicates_allowed, GraphQL::BOOLEAN_TYPE, null: false, description: 'Indicates whether duplicate Maven packages are allowed for this namespace.'
field :maven_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.'
+ field :generic_duplicates_allowed, GraphQL::BOOLEAN_TYPE, null: false, description: 'Indicates whether duplicate generic packages are allowed for this namespace.'
+ field :generic_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.'
end
end
diff --git a/app/models/namespace/package_setting.rb b/app/models/namespace/package_setting.rb
index ce0b736e9a5..881b2f3acb3 100644
--- a/app/models/namespace/package_setting.rb
+++ b/app/models/namespace/package_setting.rb
@@ -6,13 +6,15 @@ class Namespace::PackageSetting < ApplicationRecord
PackageSettingNotImplemented = Class.new(StandardError)
- PACKAGES_WITH_SETTINGS = %w[maven].freeze
+ PACKAGES_WITH_SETTINGS = %w[maven generic].freeze
belongs_to :namespace, inverse_of: :package_setting_relation
validates :namespace, presence: true
validates :maven_duplicates_allowed, inclusion: { in: [true, false] }
validates :maven_duplicate_exception_regex, untrusted_regexp: true, length: { maximum: 255 }
+ validates :generic_duplicates_allowed, inclusion: { in: [true, false] }
+ validates :generic_duplicate_exception_regex, untrusted_regexp: true, length: { maximum: 255 }
class << self
def duplicates_allowed?(package)
diff --git a/app/models/packages.rb b/app/models/packages.rb
index e14c9290093..19490d23ce4 100644
--- a/app/models/packages.rb
+++ b/app/models/packages.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
module Packages
+ DuplicatePackageError = Class.new(StandardError)
+
def self.table_name_prefix
'packages_'
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 9d2e514f377..9411cbc35fc 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -995,7 +995,13 @@ class Repository
def search_files_by_wildcard_path(path, ref = 'HEAD')
# We need to use RE2 to match Gitaly's regexp engine
- regexp_string = RE2::Regexp.escape(path).gsub('\*', '.*?')
+ regexp_string = RE2::Regexp.escape(path)
+
+ anything = '.*?'
+ anything_but_not_slash = '([^\/])*?'
+ regexp_string.gsub!('\*\*', anything)
+ regexp_string.gsub!('\*', anything_but_not_slash)
+
raw_repository.search_files_by_regexp("^#{regexp_string}$", ref)
end
diff --git a/app/services/namespaces/package_settings/update_service.rb b/app/services/namespaces/package_settings/update_service.rb
index 0964963647a..cbadbe5c907 100644
--- a/app/services/namespaces/package_settings/update_service.rb
+++ b/app/services/namespaces/package_settings/update_service.rb
@@ -5,7 +5,10 @@ module Namespaces
class UpdateService < BaseContainerService
include Gitlab::Utils::StrongMemoize
- ALLOWED_ATTRIBUTES = %i[maven_duplicates_allowed maven_duplicate_exception_regex].freeze
+ ALLOWED_ATTRIBUTES = %i[maven_duplicates_allowed
+ maven_duplicate_exception_regex
+ generic_duplicates_allowed
+ generic_duplicate_exception_regex].freeze
def execute
return ServiceResponse.error(message: 'Access Denied', http_status: 403) unless allowed?
diff --git a/app/services/packages/generic/create_package_file_service.rb b/app/services/packages/generic/create_package_file_service.rb
index 1451a022a39..42a191fb415 100644
--- a/app/services/packages/generic/create_package_file_service.rb
+++ b/app/services/packages/generic/create_package_file_service.rb
@@ -23,6 +23,10 @@ module Packages
.new(project, current_user, package_params)
.execute
+ unless Namespace::PackageSetting.duplicates_allowed?(package)
+ raise ::Packages::DuplicatePackageError if target_file_is_duplicate?(package)
+ end
+
package.update_column(:status, params[:status]) if params[:status] && params[:status] != package.status
package.build_infos.safe_find_or_create_by!(pipeline: params[:build].pipeline) if params[:build].present?
@@ -40,6 +44,10 @@ module Packages
::Packages::CreatePackageFileService.new(package, file_params).execute
end
+
+ def target_file_is_duplicate?(package)
+ package.package_files.with_file_name(params[:file_name]).exists?
+ end
end
end
end
diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index 52cf0248f21..4e373dda013 100644
--- a/app/views/shared/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -8,7 +8,7 @@
= link_to gitlab_snippet_path(snippet) do
= snippet.title
- %ul.controls
+ %ul.controls{ data: { qa_selector: 'snippet_file_count_content', qa_snippet_files: snippet.statistics&.file_count } }
%li
= snippet_file_count(snippet)
%li
@@ -16,7 +16,7 @@
= sprite_icon('comments', css_class: 'gl-vertical-align-text-bottom')
= notes_count
%li
- %span.sr-only
+ %span.sr-only{ data: { qa_selector: 'snippet_visibility_content', qa_snippet_visibility: visibility_level_label(snippet.visibility_level) } }
= visibility_level_label(snippet.visibility_level)
= visibility_level_icon(snippet.visibility_level)
diff --git a/changelogs/unreleased/293755-generic-dupe-settings.yml b/changelogs/unreleased/293755-generic-dupe-settings.yml
new file mode 100644
index 00000000000..fd2e5a8d1d8
--- /dev/null
+++ b/changelogs/unreleased/293755-generic-dupe-settings.yml
@@ -0,0 +1,5 @@
+---
+title: Add setting to allow or disallow duplicates for generic packages
+merge_request: 60664
+author:
+type: added
diff --git a/changelogs/unreleased/327414-agent-proxy-request-count.yml b/changelogs/unreleased/327414-agent-proxy-request-count.yml
new file mode 100644
index 00000000000..1f3bf7027b6
--- /dev/null
+++ b/changelogs/unreleased/327414-agent-proxy-request-count.yml
@@ -0,0 +1,5 @@
+---
+title: Add kubernetes_agent_proxy_request to usage ping
+merge_request: 60978
+author:
+type: changed
diff --git a/db/migrate/20210429192653_add_generic_package_duplicate_settings_to_namespace_package_settings.rb b/db/migrate/20210429192653_add_generic_package_duplicate_settings_to_namespace_package_settings.rb
new file mode 100644
index 00000000000..8c328eb52fc
--- /dev/null
+++ b/db/migrate/20210429192653_add_generic_package_duplicate_settings_to_namespace_package_settings.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddGenericPackageDuplicateSettingsToNamespacePackageSettings < ActiveRecord::Migration[6.0]
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit is added in 20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex
+ def change
+ add_column :namespace_package_settings, :generic_duplicates_allowed, :boolean, null: false, default: true
+ add_column :namespace_package_settings, :generic_duplicate_exception_regex, :text, null: false, default: ''
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex.rb b/db/migrate/20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex.rb
new file mode 100644
index 00000000000..5d02ad3e2f5
--- /dev/null
+++ b/db/migrate/20210429193106_add_text_limit_to_namespace_package_settings_generic_duplicate_exception_regex.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddTextLimitToNamespacePackageSettingsGenericDuplicateExceptionRegex < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :namespace_package_settings, :generic_duplicate_exception_regex, 255
+ end
+
+ def down
+ remove_text_limit :namespace_package_settings, :generic_duplicate_exception_regex
+ end
+end
diff --git a/db/schema_migrations/20210429192653 b/db/schema_migrations/20210429192653
new file mode 100644
index 00000000000..5e380380d72
--- /dev/null
+++ b/db/schema_migrations/20210429192653
@@ -0,0 +1 @@
+c2b5ad6786e1c71ccff391b03fcd0635dfd42d69484443291a692cef9f3ffda5 \ No newline at end of file
diff --git a/db/schema_migrations/20210429193106 b/db/schema_migrations/20210429193106
new file mode 100644
index 00000000000..49f1838a585
--- /dev/null
+++ b/db/schema_migrations/20210429193106
@@ -0,0 +1 @@
+e0898e4e439cde4e3b84808e7505490fe956cf17922f5c779b3384997d36cafd \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 5bf73b4955a..ce42f7362ca 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -14798,6 +14798,9 @@ CREATE TABLE namespace_package_settings (
namespace_id bigint NOT NULL,
maven_duplicates_allowed boolean DEFAULT true NOT NULL,
maven_duplicate_exception_regex text DEFAULT ''::text NOT NULL,
+ generic_duplicates_allowed boolean DEFAULT true NOT NULL,
+ generic_duplicate_exception_regex text DEFAULT ''::text NOT NULL,
+ CONSTRAINT check_31340211b1 CHECK ((char_length(generic_duplicate_exception_regex) <= 255)),
CONSTRAINT check_d63274b2b6 CHECK ((char_length(maven_duplicate_exception_regex) <= 255))
);
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index be5de5c86ac..28f91c7139e 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -3911,6 +3911,8 @@ Input type: `UpdateNamespacePackageSettingsInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationupdatenamespacepackagesettingsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationupdatenamespacepackagesettingsgenericduplicateexceptionregex"></a>`genericDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
+| <a id="mutationupdatenamespacepackagesettingsgenericduplicatesallowed"></a>`genericDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate generic packages are allowed for this namespace. |
| <a id="mutationupdatenamespacepackagesettingsmavenduplicateexceptionregex"></a>`mavenDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
| <a id="mutationupdatenamespacepackagesettingsmavenduplicatesallowed"></a>`mavenDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate Maven packages are allowed for this namespace. |
| <a id="mutationupdatenamespacepackagesettingsnamespacepath"></a>`namespacePath` | [`ID!`](#id) | The namespace path where the namespace package setting is located. |
@@ -10488,6 +10490,8 @@ Namespace-level Package Registry settings.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="packagesettingsgenericduplicateexceptionregex"></a>`genericDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
+| <a id="packagesettingsgenericduplicatesallowed"></a>`genericDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate generic packages are allowed for this namespace. |
| <a id="packagesettingsmavenduplicateexceptionregex"></a>`mavenDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. |
| <a id="packagesettingsmavenduplicatesallowed"></a>`mavenDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate Maven packages are allowed for this namespace. |
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index f815bfbc5a9..23cdce8187b 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -487,7 +487,7 @@ Use local includes instead of symbolic links.
> - It's not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to enable it. **(CORE ONLY)**
-You can use wildcard paths (`*`) with `include:local`.
+You can use wildcard paths (`*` and `**`) with `include:local`.
Example:
@@ -495,7 +495,19 @@ Example:
include: 'configs/*.yml'
```
-When the pipeline runs, it adds all `.yml` files in the `configs` folder into the pipeline configuration.
+When the pipeline runs, GitLab:
+
+- Adds all `.yml` files in the `configs` directory into the pipeline configuration.
+- Does not add `.yml` files in subfolders of the `configs` directory. To allow this,
+ add the following configuration:
+
+ ```yaml
+ # This matches all `.yml` files in `configs` and any subfolder in it.
+ include: 'configs/**.yml'
+
+ # This matches all `.yml` files only in subfolders of `configs`.
+ include: 'configs/**/*.yml'
+ ```
The wildcard file paths feature is under development and not ready for production use. It is
deployed behind a feature flag that is **disabled by default**.
diff --git a/doc/development/internal_api.md b/doc/development/internal_api.md
index 7cf740d16a0..57dd1c0a65b 100644
--- a/doc/development/internal_api.md
+++ b/doc/development/internal_api.md
@@ -453,7 +453,8 @@ metric counters.
| Attribute | Type | Required | Description |
|:----------|:-------|:---------|:------------|
-| `gitops_sync_count` | integer| yes | The number to increase the `gitops_sync_count` counter by |
+| `gitops_sync_count` | integer| no | The number to increase the `gitops_sync_count` counter by |
+| `k8s_api_proxy_request_count` | integer| no | The number to increase the `k8s_api_proxy_request_count` counter by |
```plaintext
POST /internal/kubernetes/usage_metrics
diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md
index 8c60a768b46..80816bf583a 100644
--- a/doc/development/usage_ping/dictionary.md
+++ b/doc/development/usage_ping/dictionary.md
@@ -2902,6 +2902,18 @@ Status: `data_available`
Tiers: `premium`, `ultimate`
+### `counts.kubernetes_agent_k8s_api_proxy_request`
+
+Count of Kubernetes API proxy requests
+
+[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210505015532_kubernetes_agent_k8s_api_proxy_request.yml)
+
+Group: `group::configure`
+
+Status: `implemented`
+
+Tiers: `premium`, `ultimate`
+
### `counts.kubernetes_agents`
Count of Kubernetes agents
diff --git a/doc/topics/git/numerous_undo_possibilities_in_git/index.md b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
index eb1c0a597f3..2426fa2f7cb 100644
--- a/doc/topics/git/numerous_undo_possibilities_in_git/index.md
+++ b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
@@ -5,139 +5,134 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: howto
---
-# Numerous undo possibilities in Git **(FREE)**
+# Undo possibilities in Git **(FREE)**
-This tutorial shows you different ways of undoing your work in Git.
-We assume you have a basic working knowledge of Git. Check the GitLab
-[Git documentation](../index.md) for reference.
+[Nothing in Git is deleted](https://git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery),
+so when you work in Git, you can undo your work.
-We only provide some general information about the commands to get you started.
-For more advanced examples, refer to the [Git book](https://git-scm.com/book/en/v2).
+All version control systems have options for undoing work. However,
+because of the de-centralized nature of Git, these options are multiplied.
+The actions you take are based on the
+[stage of development](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository)
+you are in.
-A few different techniques exist to undo your changes, based on the stage
-of the change in your current development. Remember that
-[nothing in Git is really deleted](https://git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery).
-Until Git cleans detached commits - commits that cannot be accessed by branch or tag -
-you can view them with `git reflog` command, and access them with direct commit ID.
-Read more about [redoing the undo](#redoing-the-undo) in the section below.
+For more information about working with Git and GitLab:
-> For more information about working with Git and GitLab:
->
-> - <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>&nbsp;Learn why [North Western Mutual chose GitLab](https://youtu.be/kPNMyxKRRoM) for their Enterprise source code management.
-> - Learn how to [get started with Git](https://about.gitlab.com/resources/whitepaper-moving-to-git/).
+- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>&nbsp;Learn why [North Western Mutual chose GitLab](https://youtu.be/kPNMyxKRRoM) for their enterprise source code management.
+- Learn how to [get started with Git](https://about.gitlab.com/resources/whitepaper-moving-to-git/).
+- For more advanced examples, refer to the [Git book](https://git-scm.com/book/en/v2).
-## Introduction
+## When you can undo changes
-This guide is organized depending on the [stage of development](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository):
+In the standard Git workflow:
-- Where do you want to undo your changes from?
-- Were they shared with other developers?
+1. You create or edit a file. It starts in the unstaged state. If it's new, it is not yet tracked by Git.
+1. You add the file to your local repository (`git add`), which puts the file into the staged state.
+1. You commit the file to your local repository (`git commit`).
+1. You can then share the file with other developers, by committing to a remote repository (`git push`).
-Because Git tracks changes, a created or edited file is in the unstaged state
-(if created it is untracked by Git). After you add it to a repository (`git add`) you put
-a file into the **staged** state, which is then committed (`git commit`) to your
-local repository. After that, file can be shared with other developers (`git push`).
-This tutorial covers:
+You can undo changes at any point in this workflow:
-- [Undo local changes](#undo-local-changes) which were not pushed to a remote repository:
+- [When you're working locally](#undo-local-changes) and haven't yet pushed to a remote repository.
+- When you have already pushed to a remote repository and you want to:
+ - [Keep the history intact](#undo-remote-changes-without-changing-history) (preferred).
+ - [Change the history](#undo-remote-changes-with-modifying-history) (requires
+ coordination with team and force pushes).
- - Before you commit, in both unstaged and staged state.
- - After you committed.
+## Undo local changes
-- Undo changes after they are pushed to a remote repository:
+Until you push your changes to a remote repository, changes
+you make in Git are only in your local development environment.
- - [Without history modification](#undo-remote-changes-without-changing-history) (preferred way).
- - [With history modification](#undo-remote-changes-with-modifying-history) (requires
- coordination with team and force pushes).
- - [Use cases when modifying history is generally acceptable](#where-modifying-history-is-generally-acceptable).
- - [How to modify history](#how-modifying-history-is-done).
- - [How to remove sensitive information from repository](#deleting-sensitive-information-from-commits).
+### Undo unstaged local changes before you commit
-### Branching strategy
+When you make a change, but have not yet staged it, you can undo your work.
-[Git](https://git-scm.com/) is a de-centralized version control system. Beside regular
-versioning of the whole repository, it has possibilities to exchange changes
-with other repositories.
+1. Confirm that the file is unstaged (that you did not use `git add <file>`) by running `git status`:
-To avoid chaos with
-[multiple sources of truth](https://git-scm.com/about/distributed), various
-development workflows have to be followed. It depends on your internal
-workflow how certain changes or commits can be undone or changed.
+ ```shell
+ $ git status
+ On branch main
+ Your branch is up-to-date with 'origin/main'.
+ Changes not staged for commit:
+ (use "git add <file>..." to update what will be committed)
+ (use "git checkout -- <file>..." to discard changes in working directory)
-[GitLab Flow](https://about.gitlab.com/topics/version-control/what-is-gitlab-flow/) provides a good
-balance between developers clashing with each other while
-developing the same feature and cooperating seamlessly. However, it does not enable
-joined development of the same feature by multiple developers by default.
+ modified: <file>
+ no changes added to commit (use "git add" and/or "git commit -a")
+ ```
-When multiple developers develop the same feature on the same branch, clashing
-with every synchronization is unavoidable. However, a proper or chosen Git Workflow
-prevents lost or out-of-sync data when the feature is complete.
+1. Choose an option and undo your changes:
-You can also
-read through this blog post on [Git Tips & Tricks](https://about.gitlab.com/blog/2016/12/08/git-tips-and-tricks/)
-to learn how to do things in Git.
+ - To overwrite local changes:
-## Undo local changes
+ ```shell
+ git checkout -- <file>
+ ```
-Until you push your changes to any remote repository, they only affect you.
-That broadens your options on how to handle undoing them. Still, local changes
-can be on various stages and each stage has a different approach on how to tackle them.
+ - To save local changes so you can [re-use them later](#quickly-save-local-changes):
-### Unstaged local changes (before you commit)
+ ```shell
+ git stash
+ ```
-When a change is made, but not added to the staged tree, Git
-proposes a solution to discard changes to the file.
+ - To discard local changes to all files, permanently:
-Suppose you edited a file to change the content using your favorite editor:
+ ```shell
+ git reset --hard
+ ```
-```shell
-vim <file>
-```
+### Undo staged local changes before you commit
-Because you did not `git add <file>` to staging, it should be under unstaged files (or
-untracked if file was created). You can confirm that with:
+If you added a file to staging, you can undo it.
-```shell
-$ git status
-On branch master
-Your branch is up-to-date with 'origin/master'.
-Changes not staged for commit:
- (use "git add <file>..." to update what will be committed)
- (use "git checkout -- <file>..." to discard changes in working directory)
-
- modified: <file>
-no changes added to commit (use "git add" and/or "git commit -a")
-```
+1. Confirm that the file is staged (that you used `git add <file>`) by running `git status`:
-At this point there are 3 options to undo the local changes you have:
+ ```shell
+ $ git status
+ On branch main
+ Your branch is up-to-date with 'origin/main'.
+ Changes to be committed:
+ (use "git restore --staged <file>..." to unstage)
-- Discard all local changes, but save them for possible re-use [later](#quickly-save-local-changes):
+ new file: <file>
+ ```
- ```shell
- git stash
- ```
+1. Choose an option and undo your changes:
-- Discarding local changes (permanently) to a file:
+ - To unstage the file but keep your changes:
- ```shell
- git checkout -- <file>
- ```
+ ```shell
+ git restore --staged <file>
+ ```
-- Discard all local changes to all files permanently:
+ - To unstage everything but keep your changes:
- ```shell
- git reset --hard
- ```
+ ```shell
+ git reset
+ ```
+
+ - To unstage the file to current commit (HEAD):
+
+ ```shell
+ git reset HEAD <file>
+ ```
+
+ - To discard all local changes, but save them for [later](#quickly-save-local-changes):
+
+ ```shell
+ git stash
+ ```
+
+ - To discard everything permanently:
-Before executing `git reset --hard`, keep in mind that there is also a way to
-just temporary store the changes without committing them using `git stash`.
-This command resets the changes to all files, but it also saves them in case
-you would like to apply them at some later time. You can read more about it in
-[section below](#quickly-save-local-changes).
+ ```shell
+ git reset --hard
+ ```
### Quickly save local changes
-You are working on a feature when a boss drops by with an urgent task. Because your
+You are working on a feature when someone drops by with an urgent task. Because your
feature is not complete, but you need to swap to another branch, you can use
`git stash` to:
@@ -159,60 +154,7 @@ additional options like:
- `git stash pop`, which redoes previously stashed changes and removes them from stashed list
- `git stash apply`, which redoes previously stashed changes, but keeps them on stashed list
-### Staged local changes (before you commit)
-
-If you add some files to staging, but you want to remove them from the
-current commit while retaining those changes, move them outside
-of the staging tree. You can also discard all changes with
-`git reset --hard` or think about `git stash` [as described earlier.](#quickly-save-local-changes)
-
-Lets start the example by editing a file with your favorite editor to change the
-content and add it to staging:
-
-```shell
-vim <file>
-git add <file>
-```
-
-The file is now added to staging as confirmed by `git status` command:
-
-```shell
-$ git status
-On branch master
-Your branch is up-to-date with 'origin/master'.
-Changes to be committed:
- (use "git reset HEAD <file>..." to unstage)
-
- new file: <file>
-```
-
-Now you have 4 options to undo your changes:
-
-- Unstage the file to current commit (HEAD):
-
- ```shell
- git reset HEAD <file>
- ```
-
-- Unstage everything - retain changes:
-
- ```shell
- git reset
- ```
-
-- Discard all local changes, but save them for [later](#quickly-save-local-changes):
-
- ```shell
- git stash
- ```
-
-- Discard everything permanently:
-
- ```shell
- git reset --hard
- ```
-
-## Committed local changes
+## Undo committed local changes
After you commit, your changes are recorded by the version control system.
Because you haven't pushed to your remote repository yet, your changes are
@@ -289,6 +231,9 @@ these options to remove all or part of it from our repository:
### With history modification
+You can rewrite history in Git, but you should avoid it, because it can cause problems
+when multiple developers are contributing to the same codebase.
+
There is one command for history modification and that is `git rebase`. Command
provides interactive mode (`-i` flag) which enables you to:
@@ -335,7 +280,7 @@ In case you want to modify something introduced in commit `B`.
You can find some more examples in the section explaining
[how to modify history](#how-modifying-history-is-done).
-### Redoing the Undo
+### Redoing the undo
Sometimes you realize that the changes you undid were useful and you want them
back. Well because of first paragraph you are in luck. Command `git reflog`
@@ -501,14 +446,6 @@ feature set as `git filter-branch` does, but focus on specific use cases.
Refer [Reduce repository size](../../../user/project/repository/reducing_the_repo_size_using_git.md) page to know more about purging files from repository history & GitLab storage.
-## Conclusion
-
-Various options exist for undoing your work with any version control system, but
-because of the de-centralized nature of Git, these options are multiplied (or limited)
-depending on the stage of your process. Git also enables rewriting history, but that
-should be avoided as it might cause problems when multiple developers are
-contributing to the same codebase.
-
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index cce55fa92d9..d0680ad7bc5 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -74,6 +74,8 @@ module API
Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: project.id })
forbidden!
+ rescue ::Packages::DuplicatePackageError
+ bad_request!('Duplicate package is not allowed')
end
desc 'Download package file' do
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index af2c53dd778..ca8e041b319 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -107,18 +107,18 @@ module API
detail 'Updates usage metrics for agent'
end
params do
- requires :gitops_sync_count, type: Integer, desc: 'The count to increment the gitops_sync metric by'
+ optional :gitops_sync_count, type: Integer, desc: 'The count to increment the gitops_sync metric by'
+ optional :k8s_api_proxy_request_count, type: Integer, desc: 'The count to increment the k8s_api_proxy_request_count metric by'
end
post '/' do
- gitops_sync_count = params[:gitops_sync_count]
+ events = params.slice(:gitops_sync_count, :k8s_api_proxy_request_count)
+ events.transform_keys! { |event| event.to_s.chomp('_count') }
- if gitops_sync_count < 0
- bad_request!('gitops_sync_count must be greater than or equal to zero')
- else
- Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_gitops_sync(gitops_sync_count)
+ Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(events)
- no_content!
- end
+ no_content!
+ rescue ArgumentError => e
+ bad_request!(e.message)
end
end
end
diff --git a/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb b/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
index eae42bdc4a1..8b9ca0fc220 100644
--- a/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
+++ b/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
@@ -4,17 +4,27 @@ module Gitlab
module UsageDataCounters
class KubernetesAgentCounter < BaseCounter
PREFIX = 'kubernetes_agent'
- KNOWN_EVENTS = %w[gitops_sync].freeze
+ KNOWN_EVENTS = %w[gitops_sync k8s_api_proxy_request].freeze
class << self
- def increment_gitops_sync(incr)
- raise ArgumentError, 'must be greater than or equal to zero' if incr < 0
+ def increment_event_counts(events)
+ validate!(events)
- # rather then hitting redis for this no-op, we return early
- # note: redis returns the increment, so we mimic this here
- return 0 if incr == 0
+ events.each do |event, incr|
+ # rather then hitting redis for this no-op, we return early
+ next if incr == 0
- increment_by(redis_key(:gitops_sync), incr)
+ increment_by(redis_key(event), incr)
+ end
+ end
+
+ private
+
+ def validate!(events)
+ events.each do |event, incr|
+ raise ArgumentError, "unknown event #{event}" unless event.in?(KNOWN_EVENTS)
+ raise ArgumentError, "#{event} count must be greater than or equal to zero" if incr < 0
+ end
end
end
end
diff --git a/qa/qa/page/dashboard/snippet/index.rb b/qa/qa/page/dashboard/snippet/index.rb
index 8c4abfdf606..63589c376f6 100644
--- a/qa/qa/page/dashboard/snippet/index.rb
+++ b/qa/qa/page/dashboard/snippet/index.rb
@@ -10,10 +10,32 @@ module QA
element :global_new_snippet_link
end
+ view 'app/views/shared/snippets/_snippet.html.haml' do
+ element :snippet_link
+ element :snippet_visibility_content
+ element :snippet_file_count_content
+ end
+
def go_to_new_snippet_page
click_element :new_menu_toggle
click_element :global_new_snippet_link
end
+
+ def has_snippet_title?(snippet_title)
+ has_element?(:snippet_link, snippet_title: snippet_title)
+ end
+
+ def has_visibility_level?(snippet_title, visibility)
+ within_element(:snippet_link, snippet_title: snippet_title) do
+ has_element?(:snippet_visibility_content, snippet_visibility: visibility)
+ end
+ end
+
+ def has_number_of_files?(snippet_title, number)
+ within_element(:snippet_link, snippet_title: snippet_title) do
+ has_element?(:snippet_file_count_content, snippet_files: number)
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/snippet.rb b/qa/qa/resource/snippet.rb
index 6423dc7a41c..a94ae02b8fd 100644
--- a/qa/qa/resource/snippet.rb
+++ b/qa/qa/resource/snippet.rb
@@ -3,7 +3,7 @@
module QA
module Resource
class Snippet < Base
- attr_accessor :title, :description, :file_content, :visibility, :file_name
+ attr_accessor :title, :description, :file_content, :visibility, :file_name, :files
attribute :id
attribute :http_url_to_repo
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb
new file mode 100644
index 00000000000..9c7dc868a2e
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Snippet index page' do
+ let(:personal_snippet_with_single_file) do
+ Resource::Snippet.fabricate_via_api! do |snippet|
+ snippet.title = "Personal snippet with one file-#{SecureRandom.hex(8)}"
+ snippet.visibility = 'Public'
+ end
+ end
+
+ let(:personal_snippet_with_multiple_files) do
+ Resource::Snippet.fabricate_via_api! do |snippet|
+ snippet.title = "Personal snippet with multiple files-#{SecureRandom.hex(8)}"
+ snippet.visibility = 'Private'
+ snippet.file_name = 'First file name'
+ snippet.file_content = 'first file content'
+
+ snippet.add_files do |files|
+ files.append(name: 'Second file name', content: 'second file content')
+ files.append(name: 'Third file name', content: 'third file content')
+ end
+ end
+ end
+
+ let(:project_snippet_with_single_file) do
+ Resource::ProjectSnippet.fabricate_via_api! do |snippet|
+ snippet.title = "Project snippet with one file-#{SecureRandom.hex(8)}"
+ snippet.visibility = 'Private'
+ end
+ end
+
+ let(:project_snippet_with_multiple_files) do
+ Resource::ProjectSnippet.fabricate_via_api! do |snippet|
+ snippet.title = "Project snippet with multiple files-#{SecureRandom.hex(8)}"
+ snippet.visibility = 'Public'
+ snippet.file_name = 'First file name'
+ snippet.file_content = 'first file content'
+
+ snippet.add_files do |files|
+ files.append(name: 'Second file name', content: 'second file content')
+ files.append(name: 'Third file name', content: 'third file content')
+ end
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ after do
+ personal_snippet_with_single_file.remove_via_api!
+ personal_snippet_with_multiple_files.remove_via_api!
+ project_snippet_with_single_file.remove_via_api!
+ project_snippet_with_multiple_files.remove_via_api!
+ end
+
+ shared_examples 'displaying details on index page' do |snippet_type|
+ it "shows correct details of #{snippet_type} including file number" do
+ send(snippet_type)
+ Page::Main::Menu.perform do |menu|
+ menu.go_to_more_dropdown_option(:snippets_link)
+ end
+
+ Page::Dashboard::Snippet::Index.perform do |snippet|
+ aggregate_failures 'file content verification' do
+ expect(snippet).to have_snippet_title(send(snippet_type).title)
+ expect(snippet).to have_visibility_level(send(snippet_type).title, send(snippet_type).visibility)
+ expect(snippet).to have_number_of_files(send(snippet_type).title, send(snippet_type).files.count)
+ end
+ end
+ end
+ end
+
+ it_behaves_like 'displaying details on index page', :personal_snippet_with_single_file
+ it_behaves_like 'displaying details on index page', :personal_snippet_with_multiple_files
+ it_behaves_like 'displaying details on index page', :project_snippet_with_single_file
+ it_behaves_like 'displaying details on index page', :project_snippet_with_multiple_files
+ end
+ end
+end
diff --git a/spec/factories/namespace_package_settings.rb b/spec/factories/namespace_package_settings.rb
index 875933ce84f..042808f042f 100644
--- a/spec/factories/namespace_package_settings.rb
+++ b/spec/factories/namespace_package_settings.rb
@@ -7,6 +7,9 @@ FactoryBot.define do
maven_duplicates_allowed { true }
maven_duplicate_exception_regex { 'SNAPSHOT' }
+ generic_duplicates_allowed { true }
+ generic_duplicate_exception_regex { 'foo' }
+
trait :group do
namespace { association(:group) }
end
diff --git a/spec/frontend/pipelines/graph_shared/links_layer_spec.js b/spec/frontend/pipelines/graph_shared/links_layer_spec.js
index 511aba0acaf..932a19f2f00 100644
--- a/spec/frontend/pipelines/graph_shared/links_layer_spec.js
+++ b/spec/frontend/pipelines/graph_shared/links_layer_spec.js
@@ -96,23 +96,19 @@ describe('links layer component', () => {
});
describe('performance metrics', () => {
+ const metricsPath = '/root/project/-/ci/prometheus_metrics/histograms.json';
let markAndMeasure;
let reportToSentry;
let reportPerformance;
let mock;
beforeEach(() => {
- mock = new MockAdapter(axios);
jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => cb());
markAndMeasure = jest.spyOn(perfUtils, 'performanceMarkAndMeasure');
reportToSentry = jest.spyOn(sentryUtils, 'reportToSentry');
reportPerformance = jest.spyOn(Api, 'reportPerformance');
});
- afterEach(() => {
- mock.restore();
- });
-
describe('with no metrics config object', () => {
beforeEach(() => {
createComponent();
@@ -164,7 +160,6 @@ describe('links layer component', () => {
});
describe('with metrics path and collect set to true', () => {
- const metricsPath = '/root/project/-/ci/prometheus_metrics/histograms.json';
const duration = 875;
const numLinks = 7;
const totalGroups = 8;
@@ -204,6 +199,9 @@ describe('links layer component', () => {
describe('with duration and no error', () => {
beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onPost(metricsPath).reply(200, {});
+
jest.spyOn(window.performance, 'getEntriesByName').mockImplementation(() => {
return [{ duration }];
});
@@ -218,6 +216,10 @@ describe('links layer component', () => {
});
});
+ afterEach(() => {
+ mock.restore();
+ });
+
it('it calls reportPerformance with expected arguments', () => {
expect(markAndMeasure).toHaveBeenCalled();
expect(reportPerformance).toHaveBeenCalled();
diff --git a/spec/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/graphql/mutations/namespace/package_settings/update_spec.rb
index bd0d38cb49f..978c81fadfa 100644
--- a/spec/graphql/mutations/namespace/package_settings/update_spec.rb
+++ b/spec/graphql/mutations/namespace/package_settings/update_spec.rb
@@ -25,7 +25,9 @@ RSpec.describe Mutations::Namespace::PackageSettings::Update do
end
RSpec.shared_examples 'updating the namespace package setting' do
- it_behaves_like 'updating the namespace package setting attributes', from: { maven_duplicates_allowed: true, maven_duplicate_exception_regex: 'SNAPSHOT' }, to: { maven_duplicates_allowed: false, maven_duplicate_exception_regex: 'RELEASE' }
+ it_behaves_like 'updating the namespace package setting attributes',
+ from: { maven_duplicates_allowed: true, maven_duplicate_exception_regex: 'SNAPSHOT', generic_duplicates_allowed: true, generic_duplicate_exception_regex: 'foo' },
+ to: { maven_duplicates_allowed: false, maven_duplicate_exception_regex: 'RELEASE', generic_duplicates_allowed: false, generic_duplicate_exception_regex: 'bar' }
it_behaves_like 'returning a success'
@@ -56,7 +58,13 @@ RSpec.describe Mutations::Namespace::PackageSettings::Update do
context 'with existing namespace package setting' do
let_it_be(:package_settings) { create(:namespace_package_setting, namespace: namespace) }
- let_it_be(:params) { { namespace_path: namespace.full_path, maven_duplicates_allowed: false, maven_duplicate_exception_regex: 'RELEASE' } }
+ let_it_be(:params) do
+ { namespace_path: namespace.full_path,
+ maven_duplicates_allowed: false,
+ maven_duplicate_exception_regex: 'RELEASE',
+ generic_duplicates_allowed: false,
+ generic_duplicate_exception_regex: 'bar' }
+ end
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the namespace package setting'
diff --git a/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
index 8f9a3e0cd9e..e7edb8b9cf1 100644
--- a/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
@@ -3,21 +3,57 @@
require 'spec_helper'
RSpec.describe Gitlab::UsageDataCounters::KubernetesAgentCounter do
- it_behaves_like 'a redis usage counter', 'Kubernetes Agent', :gitops_sync
+ described_class::KNOWN_EVENTS.each do |event|
+ it_behaves_like 'a redis usage counter', 'Kubernetes Agent', event
+ it_behaves_like 'a redis usage counter with totals', :kubernetes_agent, event => 1
+ end
+
+ describe '.increment_event_counts' do
+ let(:events) do
+ {
+ 'gitops_sync' => 1,
+ 'k8s_api_proxy_request' => 2
+ }
+ end
- it_behaves_like 'a redis usage counter with totals', :kubernetes_agent, gitops_sync: 1
+ subject { described_class.increment_event_counts(events) }
- describe '.increment_gitops_sync' do
- it 'increments the gtops_sync counter by the new increment amount' do
- described_class.increment_gitops_sync(7)
- described_class.increment_gitops_sync(2)
- described_class.increment_gitops_sync(0)
+ it 'increments the specified counters by the new increment amount' do
+ described_class.increment_event_counts(events)
+ described_class.increment_event_counts(events)
+ described_class.increment_event_counts(events)
- expect(described_class.totals).to eq(kubernetes_agent_gitops_sync: 9)
+ expect(described_class.totals).to eq(kubernetes_agent_gitops_sync: 3, kubernetes_agent_k8s_api_proxy_request: 6)
end
- it 'raises for negative numbers' do
- expect { described_class.increment_gitops_sync(-1) }.to raise_error(ArgumentError)
+ context 'event is unknown' do
+ let(:events) do
+ {
+ 'gitops_sync' => 1,
+ 'other_event' => 2
+ }
+ end
+
+ it 'raises an ArgumentError' do
+ expect(described_class).not_to receive(:increment_by)
+
+ expect { subject }.to raise_error(ArgumentError, 'unknown event other_event')
+ end
+ end
+
+ context 'increment is negative' do
+ let(:events) do
+ {
+ 'gitops_sync' => -1,
+ 'k8s_api_proxy_request' => 2
+ }
+ end
+
+ it 'raises an ArgumentError' do
+ expect(described_class).not_to receive(:increment_by)
+
+ expect { subject }.to raise_error(ArgumentError, 'gitops_sync count must be greater than or equal to zero')
+ end
end
end
end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 9be0ca71bcb..306537b69d1 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -774,6 +774,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.usage_counters }
it { is_expected.to include(:kubernetes_agent_gitops_sync) }
+ it { is_expected.to include(:kubernetes_agent_k8s_api_proxy_request) }
it { is_expected.to include(:static_site_editor_views) }
it { is_expected.to include(:package_events_i_package_pull_package) }
it { is_expected.to include(:package_events_i_package_delete_package_by_user) }
diff --git a/spec/models/namespace/package_setting_spec.rb b/spec/models/namespace/package_setting_spec.rb
index a6dcb316796..4308c8c06bc 100644
--- a/spec/models/namespace/package_setting_spec.rb
+++ b/spec/models/namespace/package_setting_spec.rb
@@ -14,9 +14,12 @@ RSpec.describe Namespace::PackageSetting do
it { is_expected.to allow_value(true).for(:maven_duplicates_allowed) }
it { is_expected.to allow_value(false).for(:maven_duplicates_allowed) }
it { is_expected.not_to allow_value(nil).for(:maven_duplicates_allowed) }
+ it { is_expected.to allow_value(true).for(:generic_duplicates_allowed) }
+ it { is_expected.to allow_value(false).for(:generic_duplicates_allowed) }
+ it { is_expected.not_to allow_value(nil).for(:generic_duplicates_allowed) }
end
- describe '#maven_duplicate_exception_regex' do
+ describe 'regex values' do
let_it_be(:package_settings) { create(:namespace_package_setting) }
subject { package_settings }
@@ -24,12 +27,14 @@ RSpec.describe Namespace::PackageSetting do
valid_regexps = %w[SNAPSHOT .* v.+ v10.1.* (?:v.+|SNAPSHOT|TEMP)]
invalid_regexps = ['[', '(?:v.+|SNAPSHOT|TEMP']
- valid_regexps.each do |valid_regexp|
- it { is_expected.to allow_value(valid_regexp).for(:maven_duplicate_exception_regex) }
- end
+ [:maven_duplicate_exception_regex, :generic_duplicate_exception_regex].each do |attribute|
+ valid_regexps.each do |valid_regexp|
+ it { is_expected.to allow_value(valid_regexp).for(attribute) }
+ end
- invalid_regexps.each do |invalid_regexp|
- it { is_expected.not_to allow_value(invalid_regexp).for(:maven_duplicate_exception_regex) }
+ invalid_regexps.each do |invalid_regexp|
+ it { is_expected.not_to allow_value(invalid_regexp).for(attribute) }
+ end
end
end
end
@@ -41,7 +46,7 @@ RSpec.describe Namespace::PackageSetting do
context 'package types with package_settings' do
# As more package types gain settings they will be added to this list
- [:maven_package].each do |format|
+ [:maven_package, :generic_package].each do |format|
let_it_be(:package) { create(format, name: 'foo', version: 'beta') } # rubocop:disable Rails/SaveBang
let_it_be(:package_type) { package.package_type }
let_it_be(:package_setting) { package.project.namespace.package_settings }
@@ -70,7 +75,7 @@ RSpec.describe Namespace::PackageSetting do
end
context 'package types without package_settings' do
- [:npm_package, :conan_package, :nuget_package, :pypi_package, :composer_package, :generic_package, :golang_package, :debian_package].each do |format|
+ [:npm_package, :conan_package, :nuget_package, :pypi_package, :composer_package, :golang_package, :debian_package].each do |format|
let_it_be(:package) { create(format) } # rubocop:disable Rails/SaveBang
let_it_be(:package_setting) { package.project.namespace.package_settings }
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index a739f523008..7748846f6a5 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1006,19 +1006,58 @@ RSpec.describe Repository do
end
end
- context 'when specifying a path with wildcard' do
- let(:path) { 'files/*/*.png' }
+ context 'when specifying a wildcard path' do
+ let(:path) { '*.md' }
+
+ it 'returns files matching the path in the root folder' do
+ expect(result).to contain_exactly('CONTRIBUTING.md',
+ 'MAINTENANCE.md',
+ 'PROCESS.md',
+ 'README.md')
+ end
+ end
+
+ context 'when specifying a wildcard path for all' do
+ let(:path) { '**.md' }
+
+ it 'returns all matching files in all folders' do
+ expect(result).to contain_exactly('CONTRIBUTING.md',
+ 'MAINTENANCE.md',
+ 'PROCESS.md',
+ 'README.md',
+ 'files/markdown/ruby-style-guide.md',
+ 'with space/README.md')
+ end
+ end
+
+ context 'when specifying a path to subfolders using two asterisks and a slash' do
+ let(:path) { 'files/**/*.md' }
it 'returns all files matching the path' do
- expect(result).to contain_exactly('files/images/logo-black.png',
- 'files/images/logo-white.png')
+ expect(result).to contain_exactly('files/markdown/ruby-style-guide.md')
+ end
+ end
+
+ context 'when specifying a wildcard path to subfolder with just two asterisks' do
+ let(:path) { 'files/**.md' }
+
+ it 'returns all files in the matching path' do
+ expect(result).to contain_exactly('files/markdown/ruby-style-guide.md')
+ end
+ end
+
+ context 'when specifying a wildcard path to subfolder with one asterisk' do
+ let(:path) { 'files/*/*.md' }
+
+ it 'returns all files in the matching path' do
+ expect(result).to contain_exactly('files/markdown/ruby-style-guide.md')
end
end
- context 'when specifying an extension with wildcard' do
- let(:path) { '*.rb' }
+ context 'when specifying a wildcard path for an unknown number of subfolder levels' do
+ let(:path) { '**/*.rb' }
- it 'returns all files matching the extension' do
+ it 'returns all matched files in all subfolders' do
expect(result).to contain_exactly('encoding/russian.rb',
'files/ruby/popen.rb',
'files/ruby/regex.rb',
@@ -1026,6 +1065,14 @@ RSpec.describe Repository do
end
end
+ context 'when specifying a wildcard path to one level of subfolders' do
+ let(:path) { '*/*.rb' }
+
+ it 'returns all matched files in one subfolder' do
+ expect(result).to contain_exactly('encoding/russian.rb')
+ end
+ end
+
context 'when sending regexp' do
let(:path) { '.*\.rb' }
diff --git a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
index 749373e7b8d..202e7e7c333 100644
--- a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
@@ -12,7 +12,9 @@ RSpec.describe 'Updating the package settings' do
{
namespace_path: namespace.full_path,
maven_duplicates_allowed: false,
- maven_duplicate_exception_regex: 'foo-.*'
+ maven_duplicate_exception_regex: 'foo-.*',
+ generic_duplicates_allowed: false,
+ generic_duplicate_exception_regex: 'bar-.*'
}
end
@@ -22,6 +24,8 @@ RSpec.describe 'Updating the package settings' do
packageSettings {
mavenDuplicatesAllowed
mavenDuplicateExceptionRegex
+ genericDuplicatesAllowed
+ genericDuplicateExceptionRegex
}
errors
QL
@@ -40,6 +44,8 @@ RSpec.describe 'Updating the package settings' do
expect(mutation_response['errors']).to be_empty
expect(package_settings_response['mavenDuplicatesAllowed']).to eq(params[:maven_duplicates_allowed])
expect(package_settings_response['mavenDuplicateExceptionRegex']).to eq(params[:maven_duplicate_exception_regex])
+ expect(package_settings_response['genericDuplicatesAllowed']).to eq(params[:generic_duplicates_allowed])
+ expect(package_settings_response['genericDuplicateExceptionRegex']).to eq(params[:generic_duplicate_exception_regex])
end
end
@@ -69,8 +75,8 @@ RSpec.describe 'Updating the package settings' do
RSpec.shared_examples 'accepting the mutation request updating the package settings' do
it_behaves_like 'updating the namespace package setting attributes',
- from: { maven_duplicates_allowed: true, maven_duplicate_exception_regex: 'SNAPSHOT' },
- to: { maven_duplicates_allowed: false, maven_duplicate_exception_regex: 'foo-.*' }
+ from: { maven_duplicates_allowed: true, maven_duplicate_exception_regex: 'SNAPSHOT', generic_duplicates_allowed: true, generic_duplicate_exception_regex: 'foo' },
+ to: { maven_duplicates_allowed: false, maven_duplicate_exception_regex: 'foo-.*', generic_duplicates_allowed: false, generic_duplicate_exception_regex: 'bar-.*' }
it_behaves_like 'returning a success'
it_behaves_like 'rejecting invalid regex'
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index 47d0c872eb6..7a2cec974b9 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -67,26 +67,26 @@ RSpec.describe API::Internal::Kubernetes do
context 'is authenticated for an agent' do
let!(:agent_token) { create(:cluster_agent_token) }
- it 'returns no_content for valid gitops_sync_count' do
- send_request(params: { gitops_sync_count: 10 })
+ it 'returns no_content for valid events' do
+ send_request(params: { gitops_sync_count: 10, k8s_api_proxy_request_count: 5 })
expect(response).to have_gitlab_http_status(:no_content)
end
- it 'returns no_content 0 gitops_sync_count' do
- send_request(params: { gitops_sync_count: 0 })
+ it 'returns no_content for counts of zero' do
+ send_request(params: { gitops_sync_count: 0, k8s_api_proxy_request_count: 0 })
expect(response).to have_gitlab_http_status(:no_content)
end
it 'returns 400 for non number' do
- send_request(params: { gitops_sync_count: 'string' })
+ send_request(params: { gitops_sync_count: 'string', k8s_api_proxy_request_count: 1 })
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'returns 400 for negative number' do
- send_request(params: { gitops_sync_count: '-1' })
+ send_request(params: { gitops_sync_count: -1, k8s_api_proxy_request_count: 1 })
expect(response).to have_gitlab_http_status(:bad_request)
end
diff --git a/spec/services/namespaces/package_settings/update_service_spec.rb b/spec/services/namespaces/package_settings/update_service_spec.rb
index fa0c58e4c9b..030bc03038e 100644
--- a/spec/services/namespaces/package_settings/update_service_spec.rb
+++ b/spec/services/namespaces/package_settings/update_service_spec.rb
@@ -32,7 +32,9 @@ RSpec.describe ::Namespaces::PackageSettings::UpdateService do
end
shared_examples 'updating the namespace package setting' do
- it_behaves_like 'updating the namespace package setting attributes', from: { maven_duplicates_allowed: true, maven_duplicate_exception_regex: 'SNAPSHOT' }, to: { maven_duplicates_allowed: false, maven_duplicate_exception_regex: 'RELEASE' }
+ it_behaves_like 'updating the namespace package setting attributes',
+ from: { maven_duplicates_allowed: true, maven_duplicate_exception_regex: 'SNAPSHOT', generic_duplicates_allowed: true, generic_duplicate_exception_regex: 'foo' },
+ to: { maven_duplicates_allowed: false, maven_duplicate_exception_regex: 'RELEASE', generic_duplicates_allowed: false, generic_duplicate_exception_regex: 'bar' }
it_behaves_like 'returning a success'
@@ -60,7 +62,12 @@ RSpec.describe ::Namespaces::PackageSettings::UpdateService do
context 'with existing namespace package setting' do
let_it_be(:package_settings) { create(:namespace_package_setting, namespace: namespace) }
- let_it_be(:params) { { maven_duplicates_allowed: false, maven_duplicate_exception_regex: 'RELEASE' } }
+ let_it_be(:params) do
+ { maven_duplicates_allowed: false,
+ maven_duplicate_exception_regex: 'RELEASE',
+ generic_duplicates_allowed: false,
+ generic_duplicate_exception_regex: 'bar' }
+ end
where(:user_role, :shared_examples_name) do
:maintainer | 'updating the namespace package setting'
diff --git a/spec/services/packages/generic/create_package_file_service_spec.rb b/spec/services/packages/generic/create_package_file_service_spec.rb
index 10c54369f26..1c9eb53cfc7 100644
--- a/spec/services/packages/generic/create_package_file_service_spec.rb
+++ b/spec/services/packages/generic/create_package_file_service_spec.rb
@@ -6,13 +6,16 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:pipeline) { create(:ci_pipeline, user: user) }
+ let_it_be(:file_name) { 'myfile.tar.gz.1' }
+
let(:build) { double('build', pipeline: pipeline) }
describe '#execute' do
+ let_it_be(:package) { create(:generic_package, project: project) }
+
let(:sha256) { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }
let(:temp_file) { Tempfile.new("test") }
let(:file) { UploadedFile.new(temp_file.path, sha256: sha256) }
- let(:package) { create(:generic_package, project: project) }
let(:package_service) { double }
let(:params) do
@@ -20,7 +23,7 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
package_name: 'mypackage',
package_version: '0.0.1',
file: file,
- file_name: 'myfile.tar.gz.1',
+ file_name: file_name,
build: build
}
end
@@ -34,7 +37,7 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
}
end
- subject { described_class.new(project, user, params).execute }
+ subject(:execute_service) { described_class.new(project, user, params).execute }
before do
FileUtils.touch(temp_file)
@@ -47,14 +50,14 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
end
it 'creates package file', :aggregate_failures do
- expect { subject }.to change { package.package_files.count }.by(1)
+ expect { execute_service }.to change { package.package_files.count }.by(1)
.and change { Packages::PackageFileBuildInfo.count }.by(1)
package_file = package.package_files.last
aggregate_failures do
expect(package_file.package.status).to eq('default')
expect(package_file.package).to eq(package)
- expect(package_file.file_name).to eq('myfile.tar.gz.1')
+ expect(package_file.file_name).to eq(file_name)
expect(package_file.size).to eq(file.size)
expect(package_file.file_sha256).to eq(sha256)
end
@@ -65,7 +68,7 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
let(:package_params) { super().merge(status: 'hidden') }
it 'updates an existing packages status' do
- expect { subject }.to change { package.package_files.count }.by(1)
+ expect { execute_service }.to change { package.package_files.count }.by(1)
.and change { Packages::PackageFileBuildInfo.count }.by(1)
package_file = package.package_files.last
@@ -76,5 +79,32 @@ RSpec.describe Packages::Generic::CreatePackageFileService do
end
it_behaves_like 'assigns build to package file'
+
+ context 'with existing package' do
+ before do
+ create(:package_file, package: package, file_name: file_name)
+ end
+
+ it { expect { execute_service }.to change { project.package_files.count }.by(1) }
+
+ context 'when duplicates are not allowed' do
+ before do
+ package.project.namespace.package_settings.update!(generic_duplicates_allowed: false)
+ end
+
+ it 'does not allow duplicates' do
+ expect { execute_service }.to raise_error(::Packages::DuplicatePackageError)
+ .and change { project.package_files.count }.by(0)
+ end
+
+ context 'when the package name matches the exception regex' do
+ before do
+ package.project.namespace.package_settings.update!(generic_duplicate_exception_regex: '.*')
+ end
+
+ it { expect { execute_service }.to change { project.package_files.count }.by(1) }
+ end
+ end
+ end
end
end
diff --git a/spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb b/spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb
index 8398dd3c453..f7a6bd3676a 100644
--- a/spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb
+++ b/spec/support/shared_examples/services/namespace_package_settings_shared_examples.rb
@@ -7,6 +7,8 @@ RSpec.shared_examples 'updating the namespace package setting attributes' do |fr
expect { subject }
.to change { namespace.package_settings.reload.maven_duplicates_allowed }.from(from[:maven_duplicates_allowed]).to(to[:maven_duplicates_allowed])
.and change { namespace.package_settings.reload.maven_duplicate_exception_regex }.from(from[:maven_duplicate_exception_regex]).to(to[:maven_duplicate_exception_regex])
+ .and change { namespace.package_settings.reload.generic_duplicates_allowed }.from(from[:generic_duplicates_allowed]).to(to[:generic_duplicates_allowed])
+ .and change { namespace.package_settings.reload.generic_duplicate_exception_regex }.from(from[:generic_duplicate_exception_regex]).to(to[:generic_duplicate_exception_regex])
end
end
@@ -26,6 +28,8 @@ RSpec.shared_examples 'creating the namespace package setting' do
expect(namespace.package_setting_relation.maven_duplicates_allowed).to eq(package_settings[:maven_duplicates_allowed])
expect(namespace.package_setting_relation.maven_duplicate_exception_regex).to eq(package_settings[:maven_duplicate_exception_regex])
+ expect(namespace.package_setting_relation.generic_duplicates_allowed).to eq(package_settings[:generic_duplicates_allowed])
+ expect(namespace.package_setting_relation.generic_duplicate_exception_regex).to eq(package_settings[:generic_duplicate_exception_regex])
end
it_behaves_like 'returning a success'