Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
046d6f5277
commit
5da842297d
|
@ -9,4 +9,5 @@ export const dateFormats = {
|
||||||
isoDate,
|
isoDate,
|
||||||
defaultDate: mediumDate,
|
defaultDate: mediumDate,
|
||||||
defaultDateTime: 'mmm d, yyyy h:MMtt',
|
defaultDateTime: 'mmm d, yyyy h:MMtt',
|
||||||
|
month: 'mmmm',
|
||||||
};
|
};
|
||||||
|
|
|
@ -247,7 +247,11 @@ export default class FileTemplateMediator {
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilename(name) {
|
setFilename(name) {
|
||||||
this.$filenameInput.val(name).trigger('change');
|
const input = this.$filenameInput.get(0);
|
||||||
|
if (name !== undefined && input.value !== name) {
|
||||||
|
input.value = name;
|
||||||
|
input.dispatchEvent(new Event('change'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelected() {
|
getSelected() {
|
||||||
|
|
|
@ -107,7 +107,9 @@ export default {
|
||||||
this.groupToFilterBy = this.userGroups.find(
|
this.groupToFilterBy = this.userGroups.find(
|
||||||
(group) => getIdFromGraphQLId(group.id) === groupId,
|
(group) => getIdFromGraphQLId(group.id) === groupId,
|
||||||
);
|
);
|
||||||
this.setNamespace(this.groupToFilterBy);
|
if (this.groupToFilterBy) {
|
||||||
|
this.setNamespace(this.groupToFilterBy);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setNamespace({ id, fullPath }) {
|
setNamespace({ id, fullPath }) {
|
||||||
this.selectedNamespace = {
|
this.selectedNamespace = {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { s__, __ } from '~/locale';
|
||||||
export const CONTAINER_REGISTRY_TITLE = s__('ContainerRegistry|Container Registry');
|
export const CONTAINER_REGISTRY_TITLE = s__('ContainerRegistry|Container Registry');
|
||||||
export const CONNECTION_ERROR_TITLE = s__('ContainerRegistry|Docker connection error');
|
export const CONNECTION_ERROR_TITLE = s__('ContainerRegistry|Docker connection error');
|
||||||
export const CONNECTION_ERROR_MESSAGE = s__(
|
export const CONNECTION_ERROR_MESSAGE = s__(
|
||||||
`ContainerRegistry|We are having trouble connecting to the Registry, which could be due to an issue with your project name or path. %{docLinkStart}More information%{docLinkEnd}`,
|
`ContainerRegistry|We are having trouble connecting to the Container Registry. Please try refreshing the page. If this error persists, please review %{docLinkStart}the troubleshooting documentation%{docLinkEnd}.`,
|
||||||
);
|
);
|
||||||
export const LIST_INTRO_TEXT = s__(
|
export const LIST_INTRO_TEXT = s__(
|
||||||
`ContainerRegistry|With the GitLab Container Registry, every project can have its own space to store images. %{docLinkStart}More information%{docLinkEnd}`,
|
`ContainerRegistry|With the GitLab Container Registry, every project can have its own space to store images. %{docLinkStart}More information%{docLinkEnd}`,
|
||||||
|
|
|
@ -36,6 +36,8 @@ export default () => {
|
||||||
isAdmin,
|
isAdmin,
|
||||||
showCleanupPolicyOnAlert,
|
showCleanupPolicyOnAlert,
|
||||||
showUnfinishedTagCleanupCallout,
|
showUnfinishedTagCleanupCallout,
|
||||||
|
connectionError,
|
||||||
|
invalidPathError,
|
||||||
...config
|
...config
|
||||||
} = el.dataset;
|
} = el.dataset;
|
||||||
|
|
||||||
|
@ -67,6 +69,8 @@ export default () => {
|
||||||
isAdmin: parseBoolean(isAdmin),
|
isAdmin: parseBoolean(isAdmin),
|
||||||
showCleanupPolicyOnAlert: parseBoolean(showCleanupPolicyOnAlert),
|
showCleanupPolicyOnAlert: parseBoolean(showCleanupPolicyOnAlert),
|
||||||
showUnfinishedTagCleanupCallout: parseBoolean(showUnfinishedTagCleanupCallout),
|
showUnfinishedTagCleanupCallout: parseBoolean(showUnfinishedTagCleanupCallout),
|
||||||
|
connectionError: parseBoolean(connectionError),
|
||||||
|
invalidPathError: parseBoolean(invalidPathError),
|
||||||
},
|
},
|
||||||
/* eslint-disable @gitlab/require-i18n-strings */
|
/* eslint-disable @gitlab/require-i18n-strings */
|
||||||
dockerBuildCommand: `docker build -t ${config.repositoryUrl} .`,
|
dockerBuildCommand: `docker build -t ${config.repositoryUrl} .`,
|
||||||
|
|
|
@ -171,6 +171,9 @@ export default {
|
||||||
showDeleteAlert() {
|
showDeleteAlert() {
|
||||||
return this.deleteAlertType && this.itemToDelete?.path;
|
return this.deleteAlertType && this.itemToDelete?.path;
|
||||||
},
|
},
|
||||||
|
showConnectionError() {
|
||||||
|
return this.config.connectionError || this.config.invalidPathError;
|
||||||
|
},
|
||||||
deleteImageAlertMessage() {
|
deleteImageAlertMessage() {
|
||||||
return this.deleteAlertType === 'success'
|
return this.deleteAlertType === 'success'
|
||||||
? DELETE_IMAGE_SUCCESS_MESSAGE
|
? DELETE_IMAGE_SUCCESS_MESSAGE
|
||||||
|
@ -292,7 +295,7 @@ export default {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<gl-empty-state
|
<gl-empty-state
|
||||||
v-if="config.characterError"
|
v-if="showConnectionError"
|
||||||
:title="$options.i18n.CONNECTION_ERROR_TITLE"
|
:title="$options.i18n.CONNECTION_ERROR_TITLE"
|
||||||
:svg-path="config.containersErrorImage"
|
:svg-path="config.containersErrorImage"
|
||||||
>
|
>
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Registry
|
||||||
|
module ConnectionErrorsHandler
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
rescue_from ContainerRegistry::Path::InvalidRegistryPathError, with: :invalid_registry_path
|
||||||
|
rescue_from Faraday::Error, with: :connection_error
|
||||||
|
|
||||||
|
before_action :ping_container_registry
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||||
|
# These instance variables are only read by a view helper to pass
|
||||||
|
# them to the frontend
|
||||||
|
# See app/views/projects/registry/repositories/index.html.haml
|
||||||
|
# app/views/groups/registry/repositories/index.html.haml
|
||||||
|
def invalid_registry_path
|
||||||
|
@invalid_path_error = true
|
||||||
|
|
||||||
|
render :index
|
||||||
|
end
|
||||||
|
|
||||||
|
def connection_error
|
||||||
|
@connection_error = true
|
||||||
|
|
||||||
|
render :index
|
||||||
|
end
|
||||||
|
# rubocop:enable Gitlab/ModuleWithInstanceVariables
|
||||||
|
|
||||||
|
def ping_container_registry
|
||||||
|
ContainerRegistry::Client.registry_info
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,6 +3,7 @@ module Groups
|
||||||
module Registry
|
module Registry
|
||||||
class RepositoriesController < Groups::ApplicationController
|
class RepositoriesController < Groups::ApplicationController
|
||||||
include PackagesHelper
|
include PackagesHelper
|
||||||
|
include ::Registry::ConnectionErrorsHandler
|
||||||
|
|
||||||
before_action :verify_container_registry_enabled!
|
before_action :verify_container_registry_enabled!
|
||||||
before_action :authorize_read_container_image!
|
before_action :authorize_read_container_image!
|
||||||
|
|
|
@ -4,6 +4,7 @@ module Projects
|
||||||
module Registry
|
module Registry
|
||||||
class RepositoriesController < ::Projects::Registry::ApplicationController
|
class RepositoriesController < ::Projects::Registry::ApplicationController
|
||||||
include PackagesHelper
|
include PackagesHelper
|
||||||
|
include ::Registry::ConnectionErrorsHandler
|
||||||
|
|
||||||
before_action :authorize_update_container_image!, only: [:destroy]
|
before_action :authorize_update_container_image!, only: [:destroy]
|
||||||
|
|
||||||
|
@ -48,8 +49,6 @@ module Projects
|
||||||
repository.save! if repository.has_tags?
|
repository.save! if repository.has_tags?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue ContainerRegistry::Path::InvalidRegistryPathError
|
|
||||||
@character_error = true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,5 +17,11 @@ module Types
|
||||||
def can_delete
|
def can_delete
|
||||||
Ability.allowed?(current_user, :destroy_container_image, object)
|
Ability.allowed?(current_user, :destroy_container_image, object)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tags
|
||||||
|
object.tags
|
||||||
|
rescue Faraday::Error
|
||||||
|
raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, 'We are having trouble connecting to the Container Registry. If this error persists, please review the troubleshooting documentation.'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,5 +28,11 @@ module Types
|
||||||
def project
|
def project
|
||||||
Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find
|
Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def tags_count
|
||||||
|
object.tags_count
|
||||||
|
rescue Faraday::Error
|
||||||
|
raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, 'We are having trouble connecting to the Container Registry. If this error persists, please review the troubleshooting documentation.'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
is_group_page: "true",
|
is_group_page: "true",
|
||||||
"group_path": @group.full_path,
|
"group_path": @group.full_path,
|
||||||
"gid_prefix": container_repository_gid_prefix,
|
"gid_prefix": container_repository_gid_prefix,
|
||||||
character_error: @character_error.to_s,
|
connection_error: (!!@connection_error).to_s,
|
||||||
|
invalid_path_error: (!!@invalid_path_error).to_s,
|
||||||
user_callouts_path: user_callouts_path,
|
user_callouts_path: user_callouts_path,
|
||||||
user_callout_id: UserCalloutsHelper::UNFINISHED_TAG_CLEANUP_CALLOUT,
|
user_callout_id: UserCalloutsHelper::UNFINISHED_TAG_CLEANUP_CALLOUT,
|
||||||
show_unfinished_tag_cleanup_callout: show_unfinished_tag_cleanup_callout?.to_s } }
|
show_unfinished_tag_cleanup_callout: show_unfinished_tag_cleanup_callout?.to_s } }
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
"is_admin": current_user&.admin.to_s,
|
"is_admin": current_user&.admin.to_s,
|
||||||
"show_cleanup_policy_on_alert": show_cleanup_policy_on_alert(@project).to_s,
|
"show_cleanup_policy_on_alert": show_cleanup_policy_on_alert(@project).to_s,
|
||||||
"cleanup_policies_settings_path": project_settings_packages_and_registries_path(@project),
|
"cleanup_policies_settings_path": project_settings_packages_and_registries_path(@project),
|
||||||
character_error: @character_error.to_s,
|
connection_error: (!!@connection_error).to_s,
|
||||||
|
invalid_path_error: (!!@invalid_path_error).to_s,
|
||||||
user_callouts_path: user_callouts_path,
|
user_callouts_path: user_callouts_path,
|
||||||
user_callout_id: UserCalloutsHelper::UNFINISHED_TAG_CLEANUP_CALLOUT,
|
user_callout_id: UserCalloutsHelper::UNFINISHED_TAG_CLEANUP_CALLOUT,
|
||||||
show_unfinished_tag_cleanup_callout: show_unfinished_tag_cleanup_callout?.to_s, } }
|
show_unfinished_tag_cleanup_callout: show_unfinished_tag_cleanup_callout?.to_s, } }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: jira_connect_asymmetric_jwt
|
name: jira_connect_asymmetric_jwt
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71080
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71080
|
||||||
rollout_issue_url:
|
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/342808
|
||||||
milestone: '14.4'
|
milestone: '14.4'
|
||||||
type: development
|
type: development
|
||||||
group: group::integrations
|
group: group::integrations
|
||||||
|
|
|
@ -126,6 +126,7 @@ Supported attributes:
|
||||||
## Get file archive
|
## Get file archive
|
||||||
|
|
||||||
> Support for [including Git LFS blobs](../topics/git/lfs/index.md#lfs-objects-in-project-archives) was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15079) in GitLab 13.5.
|
> Support for [including Git LFS blobs](../topics/git/lfs/index.md#lfs-objects-in-project-archives) was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15079) in GitLab 13.5.
|
||||||
|
> Support for downloading a subfolder was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/28827) in GitLab 14.4.
|
||||||
|
|
||||||
Get an archive of the repository. This endpoint can be accessed without
|
Get an archive of the repository. This endpoint can be accessed without
|
||||||
authentication if the repository is publicly accessible.
|
authentication if the repository is publicly accessible.
|
||||||
|
@ -147,11 +148,12 @@ Supported attributes:
|
||||||
|:------------|:---------------|:---------|:----------------------|
|
|:------------|:---------------|:---------|:----------------------|
|
||||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
|
||||||
| `sha` | string | no | The commit SHA to download. A tag, branch reference, or SHA can be used. This defaults to the tip of the default branch if not specified. |
|
| `sha` | string | no | The commit SHA to download. A tag, branch reference, or SHA can be used. This defaults to the tip of the default branch if not specified. |
|
||||||
|
| `path` | string | no | The subpath of the repository to download. This defaults to the whole repository (empty string). |
|
||||||
|
|
||||||
Example request:
|
Example request:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.com/api/v4/projects/<project_id>/repository/archive?sha=<commit_sha>"
|
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.com/api/v4/projects/<project_id>/repository/archive?sha=<commit_sha>&path=<path>"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Compare branches, tags or commits
|
## Compare branches, tags or commits
|
||||||
|
|
|
@ -156,11 +156,3 @@ LIMIT 20
|
||||||
### Web-specific parameters
|
### Web-specific parameters
|
||||||
|
|
||||||
Snowplow JS adds [web-specific parameters](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol/#Web-specific_parameters) to all web events by default.
|
Snowplow JS adds [web-specific parameters](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol/#Web-specific_parameters) to all web events by default.
|
||||||
|
|
||||||
## Implement Snowplow tracking
|
|
||||||
|
|
||||||
See the [Implementation](implementation.md) guide.
|
|
||||||
|
|
||||||
## Snowplow schemas
|
|
||||||
|
|
||||||
See the [Snowplow schemas](schemas.md) guide.
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
> - Dependency Scanning metrics [added](https://gitlab.com/gitlab-org/gitlab/-/issues/328034) in GitLab 14.2.
|
> - Dependency Scanning metrics [added](https://gitlab.com/gitlab-org/gitlab/-/issues/328034) in GitLab 14.2.
|
||||||
> - Multiselect [added](https://gitlab.com/gitlab-org/gitlab/-/issues/333586) in GitLab 14.2.
|
> - Multiselect [added](https://gitlab.com/gitlab-org/gitlab/-/issues/333586) in GitLab 14.2.
|
||||||
> - Overview table [added](https://gitlab.com/gitlab-org/gitlab/-/issues/335638) in GitLab 14.3.
|
> - Overview table [added](https://gitlab.com/gitlab-org/gitlab/-/issues/335638) in GitLab 14.3.
|
||||||
|
> - Adoption over time chart [added](https://gitlab.com/gitlab-org/gitlab/-/issues/337561) in GitLab 14.4.
|
||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
|
|
||||||
|
@ -69,6 +70,13 @@ Each group appears as a separate row in the table.
|
||||||
For each row, a feature is considered "adopted" if it has been used in a project in the given group
|
For each row, a feature is considered "adopted" if it has been used in a project in the given group
|
||||||
during the time period (including projects in any subgroups of the given group).
|
during the time period (including projects in any subgroups of the given group).
|
||||||
|
|
||||||
|
## Adoption over time
|
||||||
|
|
||||||
|
The **Adoption over time** chart in the **Overview** tab displays DevOps Adoption over time. The chart displays the total number of adopted features from the previous twelve months,
|
||||||
|
from when you enabled DevOps Adoption for the group.
|
||||||
|
|
||||||
|
The tooltip displays information about the features tracked for individual months.
|
||||||
|
|
||||||
## When is a feature considered adopted
|
## When is a feature considered adopted
|
||||||
|
|
||||||
A feature is considered "adopted" if it has been used anywhere in the group in the specified time.
|
A feature is considered "adopted" if it has been used anywhere in the group in the specified time.
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
module API
|
module API
|
||||||
class ContainerRepositories < ::API::Base
|
class ContainerRepositories < ::API::Base
|
||||||
include Gitlab::Utils::StrongMemoize
|
include Gitlab::Utils::StrongMemoize
|
||||||
|
include ::API::Helpers::ContainerRegistryHelpers
|
||||||
|
|
||||||
helpers ::API::Helpers::PackagesHelpers
|
helpers ::API::Helpers::PackagesHelpers
|
||||||
|
|
||||||
before { authenticate! }
|
before { authenticate! }
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
module API
|
module API
|
||||||
class GroupContainerRepositories < ::API::Base
|
class GroupContainerRepositories < ::API::Base
|
||||||
include PaginationParams
|
include PaginationParams
|
||||||
|
include ::API::Helpers::ContainerRegistryHelpers
|
||||||
|
|
||||||
helpers ::API::Helpers::PackagesHelpers
|
helpers ::API::Helpers::PackagesHelpers
|
||||||
|
|
||||||
|
|
|
@ -430,8 +430,8 @@ module API
|
||||||
render_api_error!('406 Not Acceptable', 406)
|
render_api_error!('406 Not Acceptable', 406)
|
||||||
end
|
end
|
||||||
|
|
||||||
def service_unavailable!
|
def service_unavailable!(message = nil)
|
||||||
render_api_error!('503 Service Unavailable', 503)
|
render_api_error!(message || '503 Service Unavailable', 503)
|
||||||
end
|
end
|
||||||
|
|
||||||
def conflict!(message = nil)
|
def conflict!(message = nil)
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module API
|
||||||
|
module Helpers
|
||||||
|
module ContainerRegistryHelpers
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
rescue_from Faraday::Error, ContainerRegistry::Path::InvalidRegistryPathError do |e|
|
||||||
|
service_unavailable!('We are having trouble connecting to the Container Registry. If this error persists, please review the troubleshooting documentation.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,6 +3,8 @@
|
||||||
module API
|
module API
|
||||||
class ProjectContainerRepositories < ::API::Base
|
class ProjectContainerRepositories < ::API::Base
|
||||||
include PaginationParams
|
include PaginationParams
|
||||||
|
include ::API::Helpers::ContainerRegistryHelpers
|
||||||
|
|
||||||
helpers ::API::Helpers::PackagesHelpers
|
helpers ::API::Helpers::PackagesHelpers
|
||||||
|
|
||||||
REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
|
REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
|
||||||
|
|
|
@ -101,6 +101,7 @@ module API
|
||||||
params do
|
params do
|
||||||
optional :sha, type: String, desc: 'The commit sha of the archive to be downloaded'
|
optional :sha, type: String, desc: 'The commit sha of the archive to be downloaded'
|
||||||
optional :format, type: String, desc: 'The archive format'
|
optional :format, type: String, desc: 'The archive format'
|
||||||
|
optional :path, type: String, desc: 'Subfolder of the repository to be downloaded'
|
||||||
end
|
end
|
||||||
get ':id/repository/archive', requirements: { format: Gitlab::PathRegex.archive_formats_regex } do
|
get ':id/repository/archive', requirements: { format: Gitlab::PathRegex.archive_formats_regex } do
|
||||||
if archive_rate_limit_reached?(current_user, user_project)
|
if archive_rate_limit_reached?(current_user, user_project)
|
||||||
|
@ -109,7 +110,7 @@ module API
|
||||||
|
|
||||||
not_acceptable! if Gitlab::HotlinkingDetector.intercept_hotlinking?(request)
|
not_acceptable! if Gitlab::HotlinkingDetector.intercept_hotlinking?(request)
|
||||||
|
|
||||||
send_git_archive user_project.repository, ref: params[:sha], format: params[:format], append_sha: true
|
send_git_archive user_project.repository, ref: params[:sha], format: params[:format], append_sha: true, path: params[:path]
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
not_found!('File')
|
not_found!('File')
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,6 +51,15 @@ module ContainerRegistry
|
||||||
client.supports_tag_delete?
|
client.supports_tag_delete?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.registry_info
|
||||||
|
registry_config = Gitlab.config.registry
|
||||||
|
return unless registry_config.enabled && registry_config.api_url.present?
|
||||||
|
|
||||||
|
token = Auth::ContainerRegistryAuthenticationService.access_token([], [])
|
||||||
|
client = new(registry_config.api_url, token: token)
|
||||||
|
client.registry_info
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(base_uri, options = {})
|
def initialize(base_uri, options = {})
|
||||||
@base_uri = base_uri
|
@base_uri = base_uri
|
||||||
@options = options
|
@options = options
|
||||||
|
|
|
@ -9111,7 +9111,7 @@ msgstr ""
|
||||||
msgid "ContainerRegistry|To widen your search, change or remove the filters above."
|
msgid "ContainerRegistry|To widen your search, change or remove the filters above."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "ContainerRegistry|We are having trouble connecting to the Registry, which could be due to an issue with your project name or path. %{docLinkStart}More information%{docLinkEnd}"
|
msgid "ContainerRegistry|We are having trouble connecting to the Container Registry. Please try refreshing the page. If this error persists, please review %{docLinkStart}the troubleshooting documentation%{docLinkEnd}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. %{docLinkStart}More Information%{docLinkEnd}"
|
msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. %{docLinkStart}More Information%{docLinkEnd}"
|
||||||
|
@ -11704,6 +11704,9 @@ msgstr ""
|
||||||
msgid "DevopsAdoption|Adoption by subgroup"
|
msgid "DevopsAdoption|Adoption by subgroup"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DevopsAdoption|Adoption over time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DevopsAdoption|An error occurred while removing the group. Please try again."
|
msgid "DevopsAdoption|An error occurred while removing the group. Please try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -11782,6 +11785,9 @@ msgstr ""
|
||||||
msgid "DevopsAdoption|No results…"
|
msgid "DevopsAdoption|No results…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DevopsAdoption|No tracked features"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DevopsAdoption|Not adopted"
|
msgid "DevopsAdoption|Not adopted"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -11827,6 +11833,9 @@ msgstr ""
|
||||||
msgid "DevopsAdoption|This group has no subgroups"
|
msgid "DevopsAdoption|This group has no subgroups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DevopsAdoption|Total number of features adopted"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DevopsAdoption|You cannot remove the group you are currently in."
|
msgid "DevopsAdoption|You cannot remove the group you are currently in."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -24104,7 +24113,7 @@ msgstr ""
|
||||||
msgid "PQL|Submit information"
|
msgid "PQL|Submit information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "PQL|Thank you for reaching out! Our sales team will bet back to you soon."
|
msgid "PQL|Thank you for reaching out! Our sales team will get back to you soon."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Package Registry"
|
msgid "Package Registry"
|
||||||
|
|
|
@ -19,6 +19,7 @@ RSpec.describe Groups::Registry::RepositoriesController do
|
||||||
before do
|
before do
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
stub_container_registry_tags(repository: :any, tags: [])
|
stub_container_registry_tags(repository: :any, tags: [])
|
||||||
|
stub_container_registry_info
|
||||||
group.add_owner(user)
|
group.add_owner(user)
|
||||||
group.add_guest(guest)
|
group.add_guest(guest)
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
|
@ -37,6 +38,18 @@ RSpec.describe Groups::Registry::RepositoriesController do
|
||||||
'name' => repo.name
|
'name' => repo.name
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
[ContainerRegistry::Path::InvalidRegistryPathError, Faraday::Error].each do |error_class|
|
||||||
|
context "when there is a #{error_class}" do
|
||||||
|
it 'displays a connection error message' do
|
||||||
|
expect(::ContainerRegistry::Client).to receive(:registry_info).and_raise(error_class, nil, nil)
|
||||||
|
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'with name parameter' do
|
shared_examples 'with name parameter' do
|
||||||
|
@ -71,6 +84,18 @@ RSpec.describe Groups::Registry::RepositoriesController do
|
||||||
expect(response).to have_gitlab_http_status(:ok)
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
expect_no_snowplow_event
|
expect_no_snowplow_event
|
||||||
end
|
end
|
||||||
|
|
||||||
|
[ContainerRegistry::Path::InvalidRegistryPathError, Faraday::Error].each do |error_class|
|
||||||
|
context "when there is an invalid path error #{error_class}" do
|
||||||
|
it 'displays a connection error message' do
|
||||||
|
expect(::ContainerRegistry::Client).to receive(:registry_info).and_raise(error_class, nil, nil)
|
||||||
|
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'json format' do
|
context 'json format' do
|
||||||
|
|
|
@ -9,6 +9,7 @@ RSpec.describe Projects::Registry::RepositoriesController do
|
||||||
before do
|
before do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
|
stub_container_registry_info
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when user has access to registry' do
|
context 'when user has access to registry' do
|
||||||
|
@ -30,6 +31,18 @@ RSpec.describe Projects::Registry::RepositoriesController do
|
||||||
|
|
||||||
expect(response).to have_gitlab_http_status(:not_found)
|
expect(response).to have_gitlab_http_status(:not_found)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
[ContainerRegistry::Path::InvalidRegistryPathError, Faraday::Error].each do |error_class|
|
||||||
|
context "when there is a #{error_class}" do
|
||||||
|
it 'displays a connection error message' do
|
||||||
|
expect(::ContainerRegistry::Client).to receive(:registry_info).and_raise(error_class, nil, nil)
|
||||||
|
|
||||||
|
go_to_index
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'renders a list of repositories' do
|
shared_examples 'renders a list of repositories' do
|
||||||
|
|
|
@ -16,6 +16,7 @@ RSpec.describe 'Container Registry', :js do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
stub_container_registry_tags(repository: :any, tags: [])
|
stub_container_registry_tags(repository: :any, tags: [])
|
||||||
|
stub_container_registry_info
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has a page title set' do
|
it 'has a page title set' do
|
||||||
|
@ -57,6 +58,16 @@ RSpec.describe 'Container Registry', :js do
|
||||||
expect(page).to have_content 'latest'
|
expect(page).to have_content 'latest'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
[ContainerRegistry::Path::InvalidRegistryPathError, Faraday::Error].each do |error_class|
|
||||||
|
context "when there is a #{error_class}" do
|
||||||
|
before do
|
||||||
|
expect(::ContainerRegistry::Client).to receive(:registry_info).and_raise(error_class, nil, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'handling feature network errors with the container registry'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'image repo details' do
|
describe 'image repo details' do
|
||||||
before do
|
before do
|
||||||
visit_container_registry_details 'my/image'
|
visit_container_registry_details 'my/image'
|
||||||
|
|
|
@ -20,6 +20,7 @@ RSpec.describe 'Container Registry', :js do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
project.add_developer(user)
|
project.add_developer(user)
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
|
stub_container_registry_info
|
||||||
stub_container_registry_tags(repository: :any, tags: [])
|
stub_container_registry_tags(repository: :any, tags: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -122,6 +123,16 @@ RSpec.describe 'Container Registry', :js do
|
||||||
expect(page).to have_content('Digest: N/A')
|
expect(page).to have_content('Digest: N/A')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
[ContainerRegistry::Path::InvalidRegistryPathError, Faraday::Error].each do |error_class|
|
||||||
|
context "when there is a #{error_class}" do
|
||||||
|
before do
|
||||||
|
expect(::ContainerRegistry::Client).to receive(:registry_info).and_raise(error_class, nil, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'handling feature network errors with the container registry'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'image repo details when image has no name' do
|
describe 'image repo details when image has no name' do
|
||||||
|
|
|
@ -553,6 +553,7 @@ RSpec.describe "Internal Project Access" do
|
||||||
before do
|
before do
|
||||||
stub_container_registry_tags(repository: :any, tags: ['latest'])
|
stub_container_registry_tags(repository: :any, tags: ['latest'])
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
|
stub_container_registry_info
|
||||||
project.container_repositories << container_repository
|
project.container_repositories << container_repository
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -570,6 +570,7 @@ RSpec.describe "Private Project Access" do
|
||||||
before do
|
before do
|
||||||
stub_container_registry_tags(repository: :any, tags: ['latest'])
|
stub_container_registry_tags(repository: :any, tags: ['latest'])
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
|
stub_container_registry_info
|
||||||
project.container_repositories << container_repository
|
project.container_repositories << container_repository
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -552,6 +552,7 @@ RSpec.describe "Public Project Access" do
|
||||||
before do
|
before do
|
||||||
stub_container_registry_tags(repository: :any, tags: ['latest'])
|
stub_container_registry_tags(repository: :any, tags: ['latest'])
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
|
stub_container_registry_info
|
||||||
project.container_repositories << container_repository
|
project.container_repositories << container_repository
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import TemplateSelectorMediator from '~/blob/file_template_mediator';
|
||||||
|
|
||||||
|
describe('Template Selector Mediator', () => {
|
||||||
|
let mediator;
|
||||||
|
|
||||||
|
describe('setFilename', () => {
|
||||||
|
let input;
|
||||||
|
const newFileName = 'foo';
|
||||||
|
const editor = jest.fn().mockImplementationOnce(() => ({
|
||||||
|
getValue: jest.fn().mockImplementation(() => {}),
|
||||||
|
}))();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
setFixtures('<div class="file-editor"><input class="js-file-path-name-input" /></div>');
|
||||||
|
input = document.querySelector('.js-file-path-name-input');
|
||||||
|
mediator = new TemplateSelectorMediator({
|
||||||
|
editor,
|
||||||
|
currentAction: jest.fn(),
|
||||||
|
projectId: jest.fn(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fills out the input field', () => {
|
||||||
|
expect(input.value).toBe('');
|
||||||
|
mediator.setFilename(newFileName);
|
||||||
|
expect(input.value).toBe(newFileName);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
name | newName | shouldDispatch
|
||||||
|
${newFileName} | ${newFileName} | ${false}
|
||||||
|
${newFileName} | ${''} | ${true}
|
||||||
|
${newFileName} | ${undefined} | ${false}
|
||||||
|
${''} | ${''} | ${false}
|
||||||
|
${''} | ${newFileName} | ${true}
|
||||||
|
${''} | ${undefined} | ${false}
|
||||||
|
`(
|
||||||
|
'correctly reacts to the name change when current name is $name and newName is $newName',
|
||||||
|
({ name, newName, shouldDispatch }) => {
|
||||||
|
input.value = name;
|
||||||
|
const eventHandler = jest.fn();
|
||||||
|
input.addEventListener('change', eventHandler);
|
||||||
|
|
||||||
|
mediator.setFilename(newName);
|
||||||
|
if (shouldDispatch) {
|
||||||
|
expect(eventHandler).toHaveBeenCalledTimes(1);
|
||||||
|
} else {
|
||||||
|
expect(eventHandler).not.toHaveBeenCalled();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -129,13 +129,16 @@ describe('List Page', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('connection error', () => {
|
describe.each([
|
||||||
|
{ error: 'connectionError', errorName: 'connection error' },
|
||||||
|
{ error: 'invalidPathError', errorName: 'invalid path error' },
|
||||||
|
])('handling $errorName', ({ error }) => {
|
||||||
const config = {
|
const config = {
|
||||||
characterError: true,
|
|
||||||
containersErrorImage: 'foo',
|
containersErrorImage: 'foo',
|
||||||
helpPagePath: 'bar',
|
helpPagePath: 'bar',
|
||||||
isGroupPage: false,
|
isGroupPage: false,
|
||||||
};
|
};
|
||||||
|
config[error] = true;
|
||||||
|
|
||||||
it('should show an empty state', () => {
|
it('should show an empty state', () => {
|
||||||
mountComponent({ config });
|
mountComponent({ config });
|
||||||
|
|
|
@ -111,6 +111,49 @@ RSpec.describe ContainerRegistry::Client do
|
||||||
it_behaves_like 'handling timeouts'
|
it_behaves_like 'handling timeouts'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
shared_examples 'handling repository info' do
|
||||||
|
context 'when the check is successful' do
|
||||||
|
context 'when using the GitLab container registry' do
|
||||||
|
before do
|
||||||
|
stub_registry_info(headers: {
|
||||||
|
'GitLab-Container-Registry-Version' => '2.9.1-gitlab',
|
||||||
|
'GitLab-Container-Registry-Features' => 'a,b,c'
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'identifies the vendor as "gitlab"' do
|
||||||
|
expect(subject).to include(vendor: 'gitlab')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'identifies version and features' do
|
||||||
|
expect(subject).to include(version: '2.9.1-gitlab', features: %w[a b c])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when using a third-party container registry' do
|
||||||
|
before do
|
||||||
|
stub_registry_info
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'identifies the vendor as "other"' do
|
||||||
|
expect(subject).to include(vendor: 'other')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not identify version or features' do
|
||||||
|
expect(subject).to include(version: nil, features: [])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the check is not successful' do
|
||||||
|
it 'does not identify vendor, version or features' do
|
||||||
|
stub_registry_info(status: 500)
|
||||||
|
|
||||||
|
expect(subject).to eq({})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#repository_manifest' do
|
describe '#repository_manifest' do
|
||||||
subject { client.repository_manifest('group/test', 'mytag') }
|
subject { client.repository_manifest('group/test', 'mytag') }
|
||||||
|
|
||||||
|
@ -316,46 +359,7 @@ RSpec.describe ContainerRegistry::Client do
|
||||||
describe '#registry_info' do
|
describe '#registry_info' do
|
||||||
subject { client.registry_info }
|
subject { client.registry_info }
|
||||||
|
|
||||||
context 'when the check is successful' do
|
it_behaves_like 'handling repository info'
|
||||||
context 'when using the GitLab container registry' do
|
|
||||||
before do
|
|
||||||
stub_registry_info(headers: {
|
|
||||||
'GitLab-Container-Registry-Version' => '2.9.1-gitlab',
|
|
||||||
'GitLab-Container-Registry-Features' => 'a,b,c'
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'identifies the vendor as "gitlab"' do
|
|
||||||
expect(subject).to include(vendor: 'gitlab')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'identifies version and features' do
|
|
||||||
expect(subject).to include(version: '2.9.1-gitlab', features: %w[a b c])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when using a third-party container registry' do
|
|
||||||
before do
|
|
||||||
stub_registry_info
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'identifies the vendor as "other"' do
|
|
||||||
expect(subject).to include(vendor: 'other')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not identify version or features' do
|
|
||||||
expect(subject).to include(version: nil, features: [])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the check is not successful' do
|
|
||||||
it 'does not identify vendor, version or features' do
|
|
||||||
stub_registry_info(status: 500)
|
|
||||||
|
|
||||||
expect(subject).to eq({})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.supports_tag_delete?' do
|
describe '.supports_tag_delete?' do
|
||||||
|
@ -418,6 +422,16 @@ RSpec.describe ContainerRegistry::Client do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.registry_info' do
|
||||||
|
subject { described_class.registry_info }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_container_registry_config(enabled: true, api_url: registry_api_url, key: 'spec/fixtures/x509_certificate_pk.key')
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'handling repository info'
|
||||||
|
end
|
||||||
|
|
||||||
def stub_upload(path, content, digest, status = 200)
|
def stub_upload(path, content, digest, status = 200)
|
||||||
stub_request(:post, "#{registry_api_url}/v2/#{path}/blobs/uploads/")
|
stub_request(:post, "#{registry_api_url}/v2/#{path}/blobs/uploads/")
|
||||||
.with(headers: headers_with_accept_types)
|
.with(headers: headers_with_accept_types)
|
||||||
|
|
|
@ -48,6 +48,19 @@ RSpec.describe API::ContainerRepositories do
|
||||||
expect(response).to match_response_schema('registry/repository')
|
expect(response).to match_response_schema('registry/repository')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with a network error' do
|
||||||
|
before do
|
||||||
|
stub_container_registry_network_error(client_method: :repository_tags)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a matching schema' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
expect(response).to match_response_schema('registry/repository')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with tags param' do
|
context 'with tags param' do
|
||||||
let(:url) { "/registry/repositories/#{repository.id}?tags=true" }
|
let(:url) { "/registry/repositories/#{repository.id}?tags=true" }
|
||||||
|
|
||||||
|
@ -61,6 +74,19 @@ RSpec.describe API::ContainerRepositories do
|
||||||
expect(json_response['id']).to eq(repository.id)
|
expect(json_response['id']).to eq(repository.id)
|
||||||
expect(response.body).to include('tags')
|
expect(response.body).to include('tags')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with a network error' do
|
||||||
|
before do
|
||||||
|
stub_container_registry_network_error(client_method: :repository_tags)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a connection error message' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:service_unavailable)
|
||||||
|
expect(json_response['message']).to include('We are having trouble connecting to the Container Registry')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with tags_count param' do
|
context 'with tags_count param' do
|
||||||
|
|
|
@ -153,4 +153,6 @@ RSpec.describe 'container repository details' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'handling graphql network errors with the container registry'
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,11 +14,12 @@ RSpec.describe 'getting container repositories in a group' do
|
||||||
let_it_be(:container_repositories) { [container_repository, container_repositories_delete_scheduled, container_repositories_delete_failed].flatten }
|
let_it_be(:container_repositories) { [container_repository, container_repositories_delete_scheduled, container_repositories_delete_failed].flatten }
|
||||||
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
|
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
|
||||||
|
|
||||||
|
let(:excluded_fields) { [] }
|
||||||
let(:container_repositories_fields) do
|
let(:container_repositories_fields) do
|
||||||
<<~GQL
|
<<~GQL
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
#{all_graphql_fields_for('container_repositories'.classify, max_depth: 1)}
|
#{all_graphql_fields_for('container_repositories'.classify, max_depth: 1, excluded: excluded_fields)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GQL
|
GQL
|
||||||
|
@ -152,6 +153,12 @@ RSpec.describe 'getting container repositories in a group' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'handling graphql network errors with the container registry'
|
||||||
|
|
||||||
|
it_behaves_like 'not hitting graphql network errors with the container registry' do
|
||||||
|
let(:excluded_fields) { %w[tags tagsCount] }
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns the total count of container repositories' do
|
it 'returns the total count of container repositories' do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,12 @@ RSpec.describe 'getting container repositories in a project' do
|
||||||
let_it_be(:container_repositories) { [container_repository, container_repositories_delete_scheduled, container_repositories_delete_failed].flatten }
|
let_it_be(:container_repositories) { [container_repository, container_repositories_delete_scheduled, container_repositories_delete_failed].flatten }
|
||||||
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
|
let_it_be(:container_expiration_policy) { project.container_expiration_policy }
|
||||||
|
|
||||||
|
let(:excluded_fields) { %w[pipeline jobs] }
|
||||||
let(:container_repositories_fields) do
|
let(:container_repositories_fields) do
|
||||||
<<~GQL
|
<<~GQL
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
#{all_graphql_fields_for('container_repositories'.classify, excluded: %w(pipeline jobs))}
|
#{all_graphql_fields_for('container_repositories'.classify, excluded: excluded_fields)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GQL
|
GQL
|
||||||
|
@ -151,6 +152,12 @@ RSpec.describe 'getting container repositories in a project' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'handling graphql network errors with the container registry'
|
||||||
|
|
||||||
|
it_behaves_like 'not hitting graphql network errors with the container registry' do
|
||||||
|
let(:excluded_fields) { %w[pipeline jobs tags tagsCount] }
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns the total count of container repositories' do
|
it 'returns the total count of container repositories' do
|
||||||
subject
|
subject
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,14 @@ RSpec.describe API::GroupContainerRepositories do
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:api_user) { reporter }
|
let(:api_user) { reporter }
|
||||||
|
let(:params) { {} }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
group.add_reporter(reporter)
|
group.add_reporter(reporter)
|
||||||
group.add_guest(guest)
|
group.add_guest(guest)
|
||||||
|
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
|
stub_container_registry_info
|
||||||
|
|
||||||
root_repository
|
root_repository
|
||||||
test_repository
|
test_repository
|
||||||
|
@ -35,10 +37,13 @@ RSpec.describe API::GroupContainerRepositories do
|
||||||
let(:url) { "/groups/#{group.id}/registry/repositories" }
|
let(:url) { "/groups/#{group.id}/registry/repositories" }
|
||||||
let(:snowplow_gitlab_standard_context) { { user: api_user, namespace: group } }
|
let(:snowplow_gitlab_standard_context) { { user: api_user, namespace: group } }
|
||||||
|
|
||||||
subject { get api(url, api_user) }
|
subject { get api(url, api_user), params: params }
|
||||||
|
|
||||||
it_behaves_like 'rejected container repository access', :guest, :forbidden
|
it_behaves_like 'rejected container repository access', :guest, :forbidden
|
||||||
it_behaves_like 'rejected container repository access', :anonymous, :not_found
|
it_behaves_like 'rejected container repository access', :anonymous, :not_found
|
||||||
|
it_behaves_like 'handling network errors with the container registry' do
|
||||||
|
let(:params) { { tags: true } }
|
||||||
|
end
|
||||||
|
|
||||||
it_behaves_like 'returns repositories for allowed users', :reporter, 'group' do
|
it_behaves_like 'returns repositories for allowed users', :reporter, 'group' do
|
||||||
let(:object) { group }
|
let(:object) { group }
|
||||||
|
|
|
@ -52,6 +52,7 @@ RSpec.describe API::ProjectContainerRepositories do
|
||||||
test_repository
|
test_repository
|
||||||
|
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
|
stub_container_registry_info
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_context 'using API user' do
|
shared_context 'using API user' do
|
||||||
|
@ -105,6 +106,9 @@ RSpec.describe API::ProjectContainerRepositories do
|
||||||
it_behaves_like 'rejected container repository access', :guest, :forbidden unless context == 'using job token'
|
it_behaves_like 'rejected container repository access', :guest, :forbidden unless context == 'using job token'
|
||||||
it_behaves_like 'rejected container repository access', :anonymous, :not_found
|
it_behaves_like 'rejected container repository access', :anonymous, :not_found
|
||||||
it_behaves_like 'a package tracking event', described_class.name, 'list_repositories'
|
it_behaves_like 'a package tracking event', described_class.name, 'list_repositories'
|
||||||
|
it_behaves_like 'handling network errors with the container registry' do
|
||||||
|
let(:params) { { tags: true } }
|
||||||
|
end
|
||||||
|
|
||||||
it_behaves_like 'returns repositories for allowed users', :reporter, 'project' do
|
it_behaves_like 'returns repositories for allowed users', :reporter, 'project' do
|
||||||
let(:object) { project }
|
let(:object) { project }
|
||||||
|
@ -154,6 +158,7 @@ RSpec.describe API::ProjectContainerRepositories do
|
||||||
|
|
||||||
it_behaves_like 'rejected container repository access', :guest, :forbidden unless context == 'using job token'
|
it_behaves_like 'rejected container repository access', :guest, :forbidden unless context == 'using job token'
|
||||||
it_behaves_like 'rejected container repository access', :anonymous, :not_found
|
it_behaves_like 'rejected container repository access', :anonymous, :not_found
|
||||||
|
it_behaves_like 'handling network errors with the container registry'
|
||||||
|
|
||||||
context 'for reporter' do
|
context 'for reporter' do
|
||||||
let(:api_user) { reporter }
|
let(:api_user) { reporter }
|
||||||
|
|
|
@ -305,6 +305,18 @@ RSpec.describe API::Repositories do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns only a part of the repository with path set' do
|
||||||
|
path = 'bar'
|
||||||
|
get api("#{route}?path=#{path}", current_user)
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
|
||||||
|
type, params = workhorse_send_data
|
||||||
|
|
||||||
|
expect(type).to eq('git-archive')
|
||||||
|
expect(params['ArchivePath']).to match(/#{project.path}\-[^\.]+\-#{path}\.tar.gz/)
|
||||||
|
end
|
||||||
|
|
||||||
it 'rate limits user when thresholds hit' do
|
it 'rate limits user when thresholds hit' do
|
||||||
allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
|
allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ RSpec.describe Groups::Registry::RepositoriesController do
|
||||||
before do
|
before do
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
stub_container_registry_tags(repository: :any, tags: [])
|
stub_container_registry_tags(repository: :any, tags: [])
|
||||||
|
stub_container_registry_info
|
||||||
group.add_reporter(user)
|
group.add_reporter(user)
|
||||||
login_as(user)
|
login_as(user)
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,6 +79,18 @@ module StubGitlabCalls
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def stub_container_registry_info(info: {})
|
||||||
|
allow(ContainerRegistry::Client)
|
||||||
|
.to receive(:registry_info)
|
||||||
|
.and_return(info)
|
||||||
|
end
|
||||||
|
|
||||||
|
def stub_container_registry_network_error(client_method:)
|
||||||
|
allow_next_instance_of(ContainerRegistry::Client) do |client|
|
||||||
|
allow(client).to receive(client_method).and_raise(::Faraday::Error, nil, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def stub_commonmark_sourcepos_disabled
|
def stub_commonmark_sourcepos_disabled
|
||||||
allow_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark)
|
allow_any_instance_of(Banzai::Filter::MarkdownEngines::CommonMark)
|
||||||
.to receive(:render_options)
|
.to receive(:render_options)
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.shared_examples 'handling feature network errors with the container registry' do
|
||||||
|
it 'displays the error message' do
|
||||||
|
visit_container_registry
|
||||||
|
|
||||||
|
expect(page).to have_content 'We are having trouble connecting to the Container Registry'
|
||||||
|
end
|
||||||
|
end
|
|
@ -79,3 +79,40 @@ RSpec.shared_examples 'returns repositories for allowed users' do |user_type, sc
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
RSpec.shared_examples 'handling network errors with the container registry' do
|
||||||
|
before do
|
||||||
|
stub_container_registry_network_error(client_method: :repository_tags)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a connection error' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:service_unavailable)
|
||||||
|
expect(json_response['message']).to include('We are having trouble connecting to the Container Registry')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec.shared_examples 'handling graphql network errors with the container registry' do
|
||||||
|
before do
|
||||||
|
stub_container_registry_network_error(client_method: :repository_tags)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a connection error' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect_graphql_errors_to_include('We are having trouble connecting to the Container Registry')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec.shared_examples 'not hitting graphql network errors with the container registry' do
|
||||||
|
before do
|
||||||
|
stub_container_registry_network_error(client_method: :repository_tags)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not return any error' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect_graphql_errors_to_be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue