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:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-18 12:14:26 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-18 12:14:26 +0300
commit92de2642b384f7d6ac3bf3c1f0862b067306c9be (patch)
treea9a7c3305edbb11360b7d8c92b9297739a2d39df
parentf5eac201c2b887d75800674ad5663d1cda8cbeb9 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/stylesheets/framework/awards.scss5
-rw-r--r--app/assets/stylesheets/vendors/atwho.scss6
-rw-r--r--app/components/projects/ml/show_ml_model_component.rb2
-rw-r--r--app/models/packages/tag.rb11
-rw-r--r--app/services/packages/npm/generate_metadata_service.rb2
-rw-r--r--app/workers/all_queues.yml9
-rw-r--r--app/workers/gitlab/bitbucket_server_import/stage/import_repository_worker.rb6
-rw-r--r--app/workers/gitlab/bitbucket_server_import/stage/import_users_worker.rb25
-rw-r--r--config/feature_flags/development/bitbucket_server_convert_mentions_to_users.yml8
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--doc/administration/settings/jira_cloud_app.md14
-rw-r--r--doc/install/docker.md22
-rw-r--r--doc/integration/jira/connect-app.md5
-rw-r--r--doc/integration/jira/troubleshooting.md21
-rw-r--r--doc/user/project/integrations/webhook_events.md2
-rw-r--r--lib/bitbucket_server/client.rb5
-rw-r--r--lib/bitbucket_server/representation/user.rb21
-rw-r--r--lib/gitlab/bitbucket_server_import/importers/users_importer.rb63
-rw-r--r--lib/gitlab/bitbucket_server_import/user_caching.rb13
-rw-r--r--lib/gitlab/ci/templates/Verify/Accessibility.gitlab-ci.yml2
-rw-r--r--qa/Gemfile2
-rw-r--r--qa/Gemfile.lock6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb6
-rw-r--r--spec/components/projects/ml/show_ml_model_component_spec.rb10
-rw-r--r--spec/lib/bitbucket_server/client_spec.rb19
-rw-r--r--spec/lib/bitbucket_server/representation/user_spec.rb19
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importers/users_importer_spec.rb65
-rw-r--r--spec/models/packages/tag_spec.rb26
-rw-r--r--spec/services/packages/npm/generate_metadata_service_spec.rb16
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb1
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb15
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/stage/import_users_worker_spec.rb77
-rw-r--r--workhorse/go.mod6
-rw-r--r--workhorse/go.sum12
34 files changed, 483 insertions, 41 deletions
diff --git a/app/assets/stylesheets/framework/awards.scss b/app/assets/stylesheets/framework/awards.scss
index fc694e0d37f..e11fa7d8801 100644
--- a/app/assets/stylesheets/framework/awards.scss
+++ b/app/assets/stylesheets/framework/awards.scss
@@ -254,11 +254,10 @@
display: contents;
gl-emoji {
- margin-top: -1px;
- margin-bottom: -1px;
+ margin-block: -0.1em;
img {
- top: 0;
+ top: -0.025em;
}
}
}
diff --git a/app/assets/stylesheets/vendors/atwho.scss b/app/assets/stylesheets/vendors/atwho.scss
index e77e09bb85d..6a2f37beed0 100644
--- a/app/assets/stylesheets/vendors/atwho.scss
+++ b/app/assets/stylesheets/vendors/atwho.scss
@@ -79,6 +79,12 @@
gl-emoji {
@include gl-mr-2;
+ vertical-align: text-top;
+
+ img {
+ margin-block: -0.1em;
+ top: 0.05em;
+ }
}
.dropdown-label-box {
diff --git a/app/components/projects/ml/show_ml_model_component.rb b/app/components/projects/ml/show_ml_model_component.rb
index 03300f01f64..26155df3e81 100644
--- a/app/components/projects/ml/show_ml_model_component.rb
+++ b/app/components/projects/ml/show_ml_model_component.rb
@@ -18,7 +18,7 @@ module Projects
id: model.id,
name: model.name,
path: model.path,
- description: "This is a placeholder for the short description",
+ description: model.description,
latest_version: latest_version_view_model,
version_count: model.version_count
}
diff --git a/app/models/packages/tag.rb b/app/models/packages/tag.rb
index 0df64bfba54..95cf312c174 100644
--- a/app/models/packages/tag.rb
+++ b/app/models/packages/tag.rb
@@ -19,6 +19,17 @@ class Packages::Tag < ApplicationRecord
.limit(FOR_PACKAGES_TAGS_LIMIT)
end
+ def self.for_package_ids_with_distinct_names(package_ids)
+ inner_query = select('DISTINCT ON (name) *').order(:name).for_package_ids(package_ids)
+
+ cte = Gitlab::SQL::CTE.new(:distinct_names_cte, inner_query)
+ cte_alias = cte.table.alias(table_name)
+
+ with(cte.to_arel)
+ .from(cte_alias)
+ .order(updated_at: :desc)
+ end
+
def ensure_project_id
self.project_id ||= package.project_id
end
diff --git a/app/services/packages/npm/generate_metadata_service.rb b/app/services/packages/npm/generate_metadata_service.rb
index 8eaac547f7e..240c657039f 100644
--- a/app/services/packages/npm/generate_metadata_service.rb
+++ b/app/services/packages/npm/generate_metadata_service.rb
@@ -105,7 +105,7 @@ module Packages
end
def package_tags
- Packages::Tag.for_package_ids(packages)
+ Packages::Tag.for_package_ids_with_distinct_names(packages)
.preload_package
end
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 249a3a23aed..63cc855e4bd 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -2577,6 +2577,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: bitbucket_server_import_stage_import_users
+ :worker_name: Gitlab::BitbucketServerImport::Stage::ImportUsersWorker
+ :feature_category: :importers
+ :has_external_dependencies: true
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
- :name: bulk_import
:worker_name: BulkImportWorker
:feature_category: :importers
diff --git a/app/workers/gitlab/bitbucket_server_import/stage/import_repository_worker.rb b/app/workers/gitlab/bitbucket_server_import/stage/import_repository_worker.rb
index b378d07d59c..573c73cd7df 100644
--- a/app/workers/gitlab/bitbucket_server_import/stage/import_repository_worker.rb
+++ b/app/workers/gitlab/bitbucket_server_import/stage/import_repository_worker.rb
@@ -14,7 +14,11 @@ module Gitlab
importer.execute
- ImportPullRequestsWorker.perform_async(project.id)
+ if Feature.enabled?(:bitbucket_server_convert_mentions_to_users, project.creator)
+ ImportUsersWorker.perform_async(project.id)
+ else
+ ImportPullRequestsWorker.perform_async(project.id)
+ end
end
def importer_class
diff --git a/app/workers/gitlab/bitbucket_server_import/stage/import_users_worker.rb b/app/workers/gitlab/bitbucket_server_import/stage/import_users_worker.rb
new file mode 100644
index 00000000000..dd18139fc9e
--- /dev/null
+++ b/app/workers/gitlab/bitbucket_server_import/stage/import_users_worker.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketServerImport
+ module Stage
+ class ImportUsersWorker # rubocop:disable Scalability/IdempotentWorker -- ImportPullRequestsWorker is not idempotent
+ include StageMethods
+
+ private
+
+ def import(project)
+ importer = importer_class.new(project)
+
+ importer.execute
+
+ ImportPullRequestsWorker.perform_async(project.id)
+ end
+
+ def importer_class
+ Importers::UsersImporter
+ end
+ end
+ end
+ end
+end
diff --git a/config/feature_flags/development/bitbucket_server_convert_mentions_to_users.yml b/config/feature_flags/development/bitbucket_server_convert_mentions_to_users.yml
new file mode 100644
index 00000000000..90ea8d56c0a
--- /dev/null
+++ b/config/feature_flags/development/bitbucket_server_convert_mentions_to_users.yml
@@ -0,0 +1,8 @@
+---
+name: bitbucket_server_convert_mentions_to_users
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139097
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/434453
+milestone: '16.7'
+type: development
+group: group::import and integrate
+default_enabled: false
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 7af1f3422e8..74f97e3bbe9 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -129,6 +129,8 @@
- 1
- - bitbucket_server_import_stage_import_repository
- 1
+- - bitbucket_server_import_stage_import_users
+ - 1
- - bulk_import
- 1
- - bulk_imports_entity
diff --git a/doc/administration/settings/jira_cloud_app.md b/doc/administration/settings/jira_cloud_app.md
index b73d75e52a1..c87c7c62a3a 100644
--- a/doc/administration/settings/jira_cloud_app.md
+++ b/doc/administration/settings/jira_cloud_app.md
@@ -18,6 +18,10 @@ To set up the GitLab for Jira Cloud app on your self-managed instance, do one of
- [Connect the GitLab for Jira Cloud app](#connect-the-gitlab-for-jira-cloud-app) (GitLab 15.7 and later).
- [Install the GitLab for Jira Cloud app manually](#install-the-gitlab-for-jira-cloud-app-manually).
+After you set up the app, you can use the [project toolchain](https://support.atlassian.com/jira-software-cloud/docs/what-is-the-project-toolchain-in-jira)
+developed and maintained by Atlassian to [link GitLab repositories to Jira projects](https://support.atlassian.com/jira-software-cloud/docs/link-repositories-to-a-project/#Link-repositories-using-the-toolchain-feature).
+The project toolchain does not affect how development information is synced between GitLab and Jira Cloud.
+
For Jira Data Center or Jira Server, use the [Jira DVCS connector](../../integration/jira/dvcs/index.md) developed and maintained by Atlassian.
## Set up OAuth authentication
@@ -245,6 +249,16 @@ Other GitLab instances that use the proxy must configure the following settings
The GitLab for Jira Cloud app connects GitLab and Jira. Data must be shared between the two applications, and access must be granted in both directions.
+### Using GitLab.com as a proxy
+
+When you use [GitLab.com as a proxy](#configure-your-gitlab-instance-to-serve-as-a-proxy),
+the Jira access token is shared with GitLab.com.
+
+The Jira access token is stored on GitLab.com because the token must be used to verify
+incoming requests from Jira before the requests are sent to your self-managed instance.
+The token is encrypted and is not used to access data in Jira.
+Any data from your self-managed instance is sent directly to Jira.
+
### Access to GitLab through OAuth
GitLab does not share an access token with Jira. However, users must authenticate through OAuth to configure the app.
diff --git a/doc/install/docker.md b/doc/install/docker.md
index 8251768986d..252f34f7120 100644
--- a/doc/install/docker.md
+++ b/doc/install/docker.md
@@ -42,24 +42,26 @@ To use the GitLab Docker images:
## Set up the volumes location
-Before setting everything else, configure a new environment variable `$GITLAB_HOME`
-pointing to the directory where the configuration, logs, and data files will reside.
-Ensure that the directory exists and appropriate permission have been granted.
-
-For Linux users, set the path to `/srv/gitlab`:
+Before setting everything else, create a directory where the configuration, logs,
+and data files will reside. It can be under your user's home directory (for example
+`~/gitlab-docker`), or in a directory like `/srv/gitlab`. To create that directory:
```shell
-export GITLAB_HOME=/srv/gitlab
+sudo mkdir -p /srv/gitlab
```
-For macOS users, use the user's `$HOME/gitlab` directory:
+If you're running Docker with a user other than `root`, ensure appropriate
+permissions have been granted to that directory.
+
+Configure a new environment variable `$GITLAB_HOME` that sets the path to the
+directory you created:
```shell
-export GITLAB_HOME=$HOME/gitlab
+export GITLAB_HOME=/srv/gitlab
```
-The `GITLAB_HOME` environment variable should be appended to your shell's profile so it is
-applied on all future terminal sessions:
+You can also append the `GITLAB_HOME` environment variable to your shell's
+profile so it is applied on all future terminal sessions:
- Bash: `~/.bash_profile`
- ZSH: `~/.zshrc`
diff --git a/doc/integration/jira/connect-app.md b/doc/integration/jira/connect-app.md
index a048541954d..6f6a882031a 100644
--- a/doc/integration/jira/connect-app.md
+++ b/doc/integration/jira/connect-app.md
@@ -14,6 +14,11 @@ With the [GitLab for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/
You can use the GitLab for Jira Cloud app to link top-level groups or subgroups. It's not possible to directly link projects or personal namespaces.
To set up the GitLab for Jira Cloud app on GitLab.com, [install the GitLab for Jira Cloud app](#install-the-gitlab-for-jira-cloud-app).
+
+After you set up the app, you can use the [project toolchain](https://support.atlassian.com/jira-software-cloud/docs/what-is-the-project-toolchain-in-jira)
+developed and maintained by Atlassian to [link GitLab repositories to Jira projects](https://support.atlassian.com/jira-software-cloud/docs/link-repositories-to-a-project/#Link-repositories-using-the-toolchain-feature).
+The project toolchain does not affect how development information is synced between GitLab and Jira Cloud.
+
For Jira Data Center or Jira Server, use the [Jira DVCS connector](dvcs/index.md) developed and maintained by Atlassian.
## GitLab data synced to Jira
diff --git a/doc/integration/jira/troubleshooting.md b/doc/integration/jira/troubleshooting.md
index ab9a750605d..0487c20af74 100644
--- a/doc/integration/jira/troubleshooting.md
+++ b/doc/integration/jira/troubleshooting.md
@@ -35,10 +35,13 @@ If you [restrict IP addresses for Jira access](https://support.atlassian.com/sec
For the root cause, check the [`integrations_json.log`](../../administration/logs/index.md#integrations_jsonlog) file. When GitLab tries to comment on a Jira issue, an `Error sending message` log entry might appear.
-In GitLab 16.1 and later, when an error occurs, the [`integrations_json.log`](../../administration/logs/index.md#integrations_jsonlog) file contains `client_*` keys in the outgoing API request to Jira.
+In GitLab 16.1 and later, when an error occurs, the `integrations_json.log` file contains `client_*` keys in the outgoing API request to Jira.
You can use the `client_*` keys to check the [Atlassian API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-group-issues) for why the error has occurred.
-In the following example, Jira responds with a `404` because the Jira issue `ALPHA-1` does not exist:
+In the following example, Jira responds with a `404`. This error might happen if:
+
+- The Jira user you created for the Jira issue integration does not have permission to view the issue.
+- The Jira issue ID you specified does not exist.
```json
{
@@ -53,6 +56,18 @@ In the following example, Jira responds with a `404` because the Jira issue `ALP
}
```
+For more information about returned status codes, see the [Jira Cloud platform REST API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issues/#api-rest-api-2-issue-issueidorkey-get-response).
+
+#### Using `curl` to verify access to a Jira issue
+
+To verify that a Jira user can access a specific Jira issue, run the following script:
+
+```shell
+curl --verbose --user "$USER:$API_TOKEN" "https://$ATLASSIAN_SUBDOMAIN.atlassian.net/rest/api/2/issue/$JIRA_ISSUE"
+```
+
+If the user can access the issue, Jira responds with a `200` and the returned JSON includes the Jira issue details.
+
### GitLab cannot close a Jira issue
If GitLab cannot close a Jira issue:
@@ -260,3 +275,5 @@ Both methods should return a JSON response:
- `total` gives a count of the issues that match the Jira project key.
- `issues` contains an array of the issues that match the Jira project key.
+
+For more information about returned status codes, see the [Jira Cloud platform REST API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issues/#api-rest-api-2-issue-issueidorkey-get-response).
diff --git a/doc/user/project/integrations/webhook_events.md b/doc/user/project/integrations/webhook_events.md
index cb84bf1ba53..11d164d68e9 100644
--- a/doc/user/project/integrations/webhook_events.md
+++ b/doc/user/project/integrations/webhook_events.md
@@ -1492,7 +1492,7 @@ Payload example:
"docker"
]
},
- "environment": null
+ "environment": null,
"source_pipeline":{
"project":{
"id": 41,
diff --git a/lib/bitbucket_server/client.rb b/lib/bitbucket_server/client.rb
index 8e84afe51d7..432928b0591 100644
--- a/lib/bitbucket_server/client.rb
+++ b/lib/bitbucket_server/client.rb
@@ -29,6 +29,11 @@ module BitbucketServer
get_collection(path, :repo, page_offset: page_offset, limit: limit)
end
+ def users(project_key, page_offset: 0, limit: nil)
+ path = "/projects/#{project_key}/permissions/users"
+ get_collection(path, :user, page_offset: page_offset, limit: limit)
+ end
+
def create_branch(project_key, repo, branch_name, sha)
payload = {
name: branch_name,
diff --git a/lib/bitbucket_server/representation/user.rb b/lib/bitbucket_server/representation/user.rb
new file mode 100644
index 00000000000..433baec1c42
--- /dev/null
+++ b/lib/bitbucket_server/representation/user.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module BitbucketServer
+ module Representation
+ class User < Representation::Base
+ def email
+ user['emailAddress']
+ end
+
+ def username
+ user['slug']
+ end
+
+ private
+
+ def user
+ raw['user']
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_server_import/importers/users_importer.rb b/lib/gitlab/bitbucket_server_import/importers/users_importer.rb
new file mode 100644
index 00000000000..f8d0521afb2
--- /dev/null
+++ b/lib/gitlab/bitbucket_server_import/importers/users_importer.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketServerImport
+ module Importers
+ class UsersImporter
+ include Loggable
+ include UserCaching
+
+ BATCH_SIZE = 100
+
+ def initialize(project)
+ @project = project
+ @project_id = project.id
+ end
+
+ attr_reader :project, :project_id
+
+ def execute
+ log_info(import_stage: 'import_users', message: 'starting')
+
+ page = 1
+
+ loop do
+ log_info(
+ import_stage: 'import_users',
+ message: "importing page #{page} using batch size #{BATCH_SIZE}"
+ )
+
+ users = client.users(project_key, page_offset: page, limit: BATCH_SIZE).to_a
+
+ break if users.empty?
+
+ cache_users(users)
+
+ page += 1
+ end
+
+ log_info(import_stage: 'import_users', message: 'finished')
+ end
+
+ private
+
+ def cache_users(users)
+ users_hash = users.each_with_object({}) do |user, hash|
+ cache_key = source_user_cache_key(project_id, user.username)
+ hash[cache_key] = user.email
+ end
+
+ ::Gitlab::Cache::Import::Caching.write_multiple(users_hash)
+ end
+
+ def client
+ @client ||= BitbucketServer::Client.new(project.import_data.credentials)
+ end
+
+ def project_key
+ project.import_data.data['project_key']
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_server_import/user_caching.rb b/lib/gitlab/bitbucket_server_import/user_caching.rb
new file mode 100644
index 00000000000..0f0169122c5
--- /dev/null
+++ b/lib/gitlab/bitbucket_server_import/user_caching.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketServerImport
+ module UserCaching
+ SOURCE_USER_CACHE_KEY = 'bitbucket_server/project/%s/source/username/%s'
+
+ def source_user_cache_key(project_id, username)
+ format(SOURCE_USER_CACHE_KEY, project_id, username)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/templates/Verify/Accessibility.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Accessibility.gitlab-ci.yml
index 488b035d189..c698bd49140 100644
--- a/lib/gitlab/ci/templates/Verify/Accessibility.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Verify/Accessibility.gitlab-ci.yml
@@ -3,7 +3,7 @@
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Verify/Accessibility.gitlab-ci.yml
-# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/accessibility_testing.html
+# Read more about the feature here: https://docs.gitlab.com/ee/ci/testing/accessibility_testing.html
stages:
- build
- test
diff --git a/qa/Gemfile b/qa/Gemfile
index 19800677673..5b1b5aeaec6 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -20,7 +20,7 @@ gem 'faker', '~> 3.2', '>= 3.2.2'
gem 'knapsack', '~> 4.0'
gem 'parallel_tests', '~> 4.3'
gem 'rotp', '~> 6.3.0'
-gem 'parallel', '~> 1.23'
+gem 'parallel', '~> 1.24'
gem 'rainbow', '~> 3.1.1'
gem 'rspec-parameterized', '~> 1.0.0'
gem 'octokit', '~> 8.0.0'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index d8d1fb4066a..0045d4555e1 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -221,7 +221,7 @@ GEM
faraday (>= 1, < 3)
sawyer (~> 0.9)
os (1.1.4)
- parallel (1.23.0)
+ parallel (1.24.0)
parallel_tests (4.3.0)
parallel
parser (3.2.2.1)
@@ -366,7 +366,7 @@ DEPENDENCIES
knapsack (~> 4.0)
nokogiri (~> 1.15, >= 1.15.5)
octokit (~> 8.0.0)
- parallel (~> 1.23)
+ parallel (~> 1.24)
parallel_tests (~> 4.3)
pry-byebug (~> 3.10.1)
rainbow (~> 3.1.1)
@@ -385,4 +385,4 @@ DEPENDENCIES
zeitwerk (~> 2.6, >= 2.6.12)
BUNDLED WITH
- 2.4.22
+ 2.5.1
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb
index 319b63291fd..66ea0cf913c 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb
@@ -9,7 +9,11 @@ module QA
end
it 'pulls an image from an existing repository',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412799' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412799',
+ quarantine: {
+ type: :test_environment,
+ issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/435585"
+ } do
project = build(:project, path_with_namespace: 'gitlab-qa/container-registry-sanity').reload!
project.visit!
diff --git a/spec/components/projects/ml/show_ml_model_component_spec.rb b/spec/components/projects/ml/show_ml_model_component_spec.rb
index ed989421679..2bb3e8fc9af 100644
--- a/spec/components/projects/ml/show_ml_model_component_spec.rb
+++ b/spec/components/projects/ml/show_ml_model_component_spec.rb
@@ -3,8 +3,12 @@
require "spec_helper"
RSpec.describe Projects::Ml::ShowMlModelComponent, type: :component, feature_category: :mlops do
- let_it_be(:project) { create(:project) } # rubocop:disable RSpec/FactoryBot/AvoidCreate -- build_stubbed breaks because it doesn't create iids properly.
- let_it_be(:model1) { create(:ml_models, :with_latest_version_and_package, project: project) } # rubocop:disable RSpec/FactoryBot/AvoidCreate -- build_stubbed breaks because it doesn't create iids properly.
+ # rubocop:disable RSpec/FactoryBot/AvoidCreate -- build_stubbed breaks because it doesn't create iids properly.
+ let_it_be(:project) { create(:project) }
+ let_it_be(:model1) do
+ create(:ml_models, :with_latest_version_and_package, project: project, description: "A description")
+ end
+ # rubocop:enable RSpec/FactoryBot/AvoidCreate
let_it_be(:experiment) { model1.default_experiment }
let_it_be(:candidate) { model1.latest_version.candidate }
@@ -26,7 +30,7 @@ RSpec.describe Projects::Ml::ShowMlModelComponent, type: :component, feature_cat
'id' => model1.id,
'name' => model1.name,
'path' => "/#{project.full_path}/-/ml/models/#{model1.id}",
- 'description' => 'This is a placeholder for the short description',
+ 'description' => 'A description',
'latestVersion' => {
'version' => model1.latest_version.version,
'description' => model1.latest_version.description,
diff --git a/spec/lib/bitbucket_server/client_spec.rb b/spec/lib/bitbucket_server/client_spec.rb
index 1d6e8492760..0d027234a0d 100644
--- a/spec/lib/bitbucket_server/client_spec.rb
+++ b/spec/lib/bitbucket_server/client_spec.rb
@@ -80,6 +80,25 @@ RSpec.describe BitbucketServer::Client, feature_category: :importers do
end
end
+ describe '#users' do
+ let(:path) { "/projects/#{project}/permissions/users" }
+
+ it 'requests a collection' do
+ expect(BitbucketServer::Paginator).to receive(:new).with(anything, path, :user, page_offset: 0, limit: nil)
+
+ subject.users(project)
+ end
+
+ it 'requests a collection with offset and limit' do
+ offset = 10
+ limit = 100
+
+ expect(BitbucketServer::Paginator).to receive(:new).with(anything, path, :user, page_offset: offset, limit: limit)
+
+ subject.users(project, page_offset: offset, limit: limit)
+ end
+ end
+
describe '#create_branch' do
let(:branch) { 'test-branch' }
let(:sha) { '12345678' }
diff --git a/spec/lib/bitbucket_server/representation/user_spec.rb b/spec/lib/bitbucket_server/representation/user_spec.rb
new file mode 100644
index 00000000000..32470e3a12f
--- /dev/null
+++ b/spec/lib/bitbucket_server/representation/user_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BitbucketServer::Representation::User, feature_category: :importers do
+ let(:email) { 'test@email.com' }
+ let(:username) { 'test_user' }
+ let(:sample_data) { { 'user' => { 'emailAddress' => email, 'slug' => username } } }
+
+ subject(:user) { described_class.new(sample_data) }
+
+ describe '#email' do
+ it { expect(user.email).to eq(email) }
+ end
+
+ describe '#username' do
+ it { expect(user.username).to eq(username) }
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importers/users_importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importers/users_importer_spec.rb
new file mode 100644
index 00000000000..33d6ab94513
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_server_import/importers/users_importer_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Importers::UsersImporter, feature_category: :importers do
+ let(:logger) { Gitlab::BitbucketServerImport::Logger }
+
+ let_it_be(:project) do
+ create(:project, :with_import_url, :import_started, :empty_repo,
+ import_data_attributes: {
+ data: { 'project_key' => 'key', 'repo_slug' => 'slug' },
+ credentials: { 'base_uri' => 'http://bitbucket.org/', 'user' => 'bitbucket', 'password' => 'password' }
+ }
+ )
+ end
+
+ let(:user_1) do
+ BitbucketServer::Representation::User.new(
+ { 'user' => { 'emailAddress' => 'email1', 'slug' => 'username1' } }
+ )
+ end
+
+ let(:user_2) do
+ BitbucketServer::Representation::User.new(
+ { 'user' => { 'emailAddress' => 'email2', 'slug' => 'username2' } }
+ )
+ end
+
+ let(:user_3) do
+ BitbucketServer::Representation::User.new(
+ { 'user' => { 'emailAddress' => 'email3', 'slug' => 'username3' } }
+ )
+ end
+
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 2)
+
+ allow_next_instance_of(BitbucketServer::Client) do |client|
+ allow(client).to receive(:users).with('key', limit: 2, page_offset: 1).and_return([user_1, user_2])
+ allow(client).to receive(:users).with('key', limit: 2, page_offset: 2).and_return([user_3])
+ allow(client).to receive(:users).with('key', limit: 2, page_offset: 3).and_return([])
+ end
+ end
+
+ subject(:importer) { described_class.new(project) }
+
+ describe '#execute' do
+ it 'writes the username and email to cache for every user in batches' do
+ expect(logger).to receive(:info).with(hash_including(message: 'starting'))
+ expect(logger).to receive(:info).with(hash_including(message: 'importing page 1 using batch size 2'))
+ expect(logger).to receive(:info).with(hash_including(message: 'importing page 2 using batch size 2'))
+ expect(logger).to receive(:info).with(hash_including(message: 'importing page 3 using batch size 2'))
+ expect(logger).to receive(:info).with(hash_including(message: 'finished'))
+
+ expect(Gitlab::Cache::Import::Caching).to receive(:write_multiple).and_call_original.twice
+
+ importer.execute
+
+ cache_key_prefix = "bitbucket_server/project/#{project.id}/source/username"
+ expect(Gitlab::Cache::Import::Caching.read("#{cache_key_prefix}/username1")).to eq('email1')
+ expect(Gitlab::Cache::Import::Caching.read("#{cache_key_prefix}/username2")).to eq('email2')
+ expect(Gitlab::Cache::Import::Caching.read("#{cache_key_prefix}/username3")).to eq('email3')
+ end
+ end
+end
diff --git a/spec/models/packages/tag_spec.rb b/spec/models/packages/tag_spec.rb
index 6842d1946e5..2d045615756 100644
--- a/spec/models/packages/tag_spec.rb
+++ b/spec/models/packages/tag_spec.rb
@@ -1,9 +1,10 @@
# frozen_string_literal: true
+
require 'spec_helper'
RSpec.describe Packages::Tag, type: :model, feature_category: :package_registry do
- let!(:project) { create(:project) }
- let!(:package) { create(:npm_package, version: '1.0.2', project: project, updated_at: 3.days.ago) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:package) { create(:npm_package, version: '1.0.2', project: project, updated_at: 3.days.ago) }
describe '#ensure_project_id' do
it 'sets the project_id before saving' do
@@ -83,4 +84,25 @@ RSpec.describe Packages::Tag, type: :model, feature_category: :package_registry
it { is_expected.to contain_exactly(tag1, tag3) }
end
end
+
+ describe '.for_package_ids_with_distinct_names' do
+ let_it_be(:package2) { create(:package, project: project) }
+ let_it_be(:package3) { create(:package, project: project) }
+ let_it_be(:tag1) { create(:packages_tag, name: 'latest', package: package, updated_at: 4.days.ago) }
+ let_it_be(:tag2) { create(:packages_tag, name: 'latest', package: package2, updated_at: 3.days.ago) }
+ let_it_be(:tag3) { create(:packages_tag, name: 'latest', package: package2, updated_at: 2.days.ago) }
+ let_it_be(:tag4) { create(:packages_tag, name: 'tag4', package: package3, updated_at: 5.days.ago) }
+ let_it_be(:tag5) { create(:packages_tag, name: 'tag5', package: package3, updated_at: 4.days.ago) }
+ let_it_be(:tag6) { create(:packages_tag, name: 'tag6', package: package3, updated_at: 6.days.ago) }
+
+ subject { described_class.for_package_ids_with_distinct_names(project.packages) }
+
+ before do
+ stub_const("#{described_class}::FOR_PACKAGES_TAGS_LIMIT", 3)
+ end
+
+ # `tag3` is returned because it's the most recently updated with the name `latest`.
+ # `tag5` is returned before `tag4` because it was updated more recently than `tag4`.
+ it { is_expected.to eq([tag3, tag5, tag4]) }
+ end
end
diff --git a/spec/services/packages/npm/generate_metadata_service_spec.rb b/spec/services/packages/npm/generate_metadata_service_spec.rb
index f5d7f13d22c..ad3d4fde665 100644
--- a/spec/services/packages/npm/generate_metadata_service_spec.rb
+++ b/spec/services/packages/npm/generate_metadata_service_spec.rb
@@ -5,7 +5,8 @@ require 'spec_helper'
RSpec.describe ::Packages::Npm::GenerateMetadataService, feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
- let_it_be(:project) { create(:project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, namespace: group) }
let_it_be(:package_name) { "@#{project.root_namespace.path}/test" }
let_it_be(:package1) { create(:npm_package, version: '2.0.4', project: project, name: package_name) }
let_it_be(:package2) { create(:npm_package, version: '2.0.6', project: project, name: package_name) }
@@ -156,6 +157,19 @@ RSpec.describe ::Packages::Npm::GenerateMetadataService, feature_category: :pack
end
end
end
+
+ context 'with duplicate tags' do
+ let_it_be(:project2) { create(:project, namespace: group) }
+ let_it_be(:package2) { create(:npm_package, version: '3.0.0', project: project2, name: package_name) }
+ let_it_be(:package_tag1) { create(:packages_tag, package: package1, name: 'latest') }
+ let_it_be(:package_tag2) { create(:packages_tag, package: package2, name: 'latest') }
+
+ let(:packages) { ::Packages::Package.for_projects([project.id, project2.id]).with_name(package_name) }
+
+ it "returns the tag of the latest package's version" do
+ expect(subject['latest']).to eq(package2.version)
+ end
+ end
end
end
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index 0b7c5b18f5a..e18f5ec2524 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -262,6 +262,7 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Gitlab::BitbucketServerImport::Stage::ImportNotesWorker' => 3,
'Gitlab::BitbucketServerImport::Stage::ImportPullRequestsWorker' => 3,
'Gitlab::BitbucketServerImport::Stage::ImportRepositoryWorker' => 3,
+ 'Gitlab::BitbucketServerImport::Stage::ImportUsersWorker' => 3,
'Gitlab::GithubImport::AdvanceStageWorker' => 3,
'Gitlab::GithubImport::Attachments::ImportReleaseWorker' => 5,
'Gitlab::GithubImport::Attachments::ImportNoteWorker' => 5,
diff --git a/spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb
index 7ea23041e79..1531b30089c 100644
--- a/spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb
+++ b/spec/workers/gitlab/bitbucket_server_import/stage/import_repository_worker_spec.rb
@@ -18,12 +18,25 @@ RSpec.describe Gitlab::BitbucketServerImport::Stage::ImportRepositoryWorker, fea
end
it 'schedules the next stage' do
- expect(Gitlab::BitbucketServerImport::Stage::ImportPullRequestsWorker).to receive(:perform_async)
+ expect(Gitlab::BitbucketServerImport::Stage::ImportUsersWorker).to receive(:perform_async)
.with(project.id)
worker.perform(project.id)
end
+ context 'when the bitbucket_server_convert_mentions_to_users flag is disabled' do
+ before do
+ stub_feature_flags(bitbucket_server_convert_mentions_to_users: false)
+ end
+
+ it 'skips the user import and schedules the next stage' do
+ expect(Gitlab::BitbucketServerImport::Stage::ImportPullRequestsWorker).to receive(:perform_async)
+ .with(project.id)
+
+ worker.perform(project.id)
+ end
+ end
+
it 'logs stage start and finish' do
expect(Gitlab::BitbucketServerImport::Logger)
.to receive(:info).with(hash_including(message: 'starting stage', project_id: project.id))
diff --git a/spec/workers/gitlab/bitbucket_server_import/stage/import_users_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/stage/import_users_worker_spec.rb
new file mode 100644
index 00000000000..d4cd1b82349
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/stage/import_users_worker_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::Stage::ImportUsersWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ let(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketServerImport::StageMethods
+
+ describe '#perform' do
+ context 'when the import succeeds' do
+ before do
+ allow_next_instance_of(Gitlab::BitbucketServerImport::Importers::UsersImporter) do |importer|
+ allow(importer).to receive(:execute)
+ end
+ end
+
+ it 'schedules the next stage' do
+ expect(Gitlab::BitbucketServerImport::Stage::ImportPullRequestsWorker).to receive(:perform_async)
+ .with(project.id)
+
+ worker.perform(project.id)
+ end
+
+ it 'logs stage start and finish' do
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(hash_including(message: 'starting stage', project_id: project.id))
+ expect(Gitlab::BitbucketServerImport::Logger)
+ .to receive(:info).with(hash_including(message: 'stage finished', project_id: project.id))
+
+ worker.perform(project.id)
+ end
+ end
+
+ context 'when project does not exists' do
+ it 'does not call importer' do
+ expect(Gitlab::BitbucketServerImport::Importers::UsersImporter).not_to receive(:new)
+
+ worker.perform(-1)
+ end
+ end
+
+ context 'when project import state is not `started`' do
+ it 'does not call importer' do
+ project = create(:project, :import_canceled)
+
+ expect(Gitlab::BitbucketServerImport::Importers::UsersImporter).not_to receive(:new)
+
+ worker.perform(project.id)
+ end
+ end
+
+ context 'when the importer fails' do
+ it 'does not schedule the next stage and raises error' do
+ exception = StandardError.new('Error')
+
+ allow_next_instance_of(Gitlab::BitbucketServerImport::Importers::UsersImporter) do |importer|
+ allow(importer).to receive(:execute).and_raise(exception)
+ end
+
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track).with(
+ project_id: project.id,
+ exception: exception,
+ error_source: described_class.name,
+ fail_import: false
+ ).and_call_original
+
+ expect { worker.perform(project.id) }
+ .to change { Gitlab::BitbucketServerImport::Stage::ImportUsersWorker.jobs.size }.by(0)
+ .and raise_error(exception)
+ end
+ end
+ end
+end
diff --git a/workhorse/go.mod b/workhorse/go.mod
index c7a78a64b84..73bcc940513 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -29,7 +29,7 @@ require (
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
golang.org/x/net v0.19.0
golang.org/x/oauth2 v0.11.0
- golang.org/x/tools v0.14.0
+ golang.org/x/tools v0.16.0
google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0
honnef.co/go/tools v0.4.6
@@ -111,8 +111,8 @@ require (
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a // indirect
- golang.org/x/mod v0.13.0 // indirect
- golang.org/x/sync v0.4.0 // indirect
+ golang.org/x/mod v0.14.0 // indirect
+ golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
diff --git a/workhorse/go.sum b/workhorse/go.sum
index c35369ddae5..2463cf20c5a 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -530,8 +530,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
-golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -608,8 +608,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
-golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
+golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -762,8 +762,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
-golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
-golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
+golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
+golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=