Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-06-07 18:10:23 +00:00
parent 79f98200f8
commit 21e144f387
94 changed files with 596 additions and 315 deletions

View File

@ -2,6 +2,24 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 13.12.3 (2021-06-07)
### Added (1 change)
- [Add an option to expose description_html in Release API](gitlab-org/gitlab@47f3fba10dfa82c65b6b006d56cc1724aac411eb) ([merge request](gitlab-org/gitlab!63393))
### Fixed (5 changes)
- [Fix spam detection with Akismet client](gitlab-org/gitlab@75dbe8d017ed691d0517f0a6ca7b9bdd866fa9d9) ([merge request](gitlab-org/gitlab!63393))
- [Set CSP back to disabled by default](gitlab-org/gitlab@f8f2dbf229693e20171185ae8e31fd59ce2131b3) ([merge request](gitlab-org/gitlab!63393))
- [Fix CSP issues related to captchas](gitlab-org/gitlab@cec54814460994ea40311f1091fb7f091d04964f) ([merge request](gitlab-org/gitlab!63393))
- [Fix issue with frames not loading in Safari](gitlab-org/gitlab@77b9355f244370b1c184943581f3b6cc27495931) ([merge request](gitlab-org/gitlab!63393))
- [Catch PgQuery::ParseError errors and log as-is](gitlab-org/gitlab@a4f36df3701208b5d015e1e818f3d5be3577697a) ([merge request](gitlab-org/gitlab!62795))
### Changed (1 change)
- [Improve SSH key expiration warning emails](gitlab-org/gitlab@2e3929503046ab1da5635ef295321ce08843f937) ([merge request](gitlab-org/gitlab!63393))
## 13.12.1 (2021-05-25)
### Fixed (3 changes)

View File

@ -76,6 +76,7 @@ export default {
<gl-sorting
:text="sortText"
:is-ascending="isDirectionAscending"
data-testid="releases-sort"
@sortDirectionChange="onDirectionChange"
>
<gl-sorting-item

View File

@ -1,7 +1,7 @@
<script>
import { EDITOR_TYPES } from '~/static_site_editor/rich_content_editor/constants';
import RichContentEditor from '~/static_site_editor/rich_content_editor/rich_content_editor.vue';
import parseSourceFile from '~/static_site_editor/services/parse_source_file';
import { EDITOR_TYPES } from '~/vue_shared/components/rich_content_editor/constants';
import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
import imageRepository from '../image_repository';
import formatter from '../services/formatter';
import renderImage from '../services/renderers/render_image';

View File

@ -5,6 +5,9 @@
- paginatable = local_assigns.fetch(:paginatable, false)
- provider_title = Gitlab::ImportSources.title(provider)
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
#import-projects-mount-element{ data: { provider: provider, provider_title: provider_title,
can_select_namespace: current_user.can_select_namespace?.to_s,
ci_cd_only: has_ci_cd_only_params?.to_s,

View File

@ -1,7 +1,6 @@
- title = _('Bitbucket Server Import')
- page_title title
- breadcrumb_title title
- header_title _("Projects"), root_path
- page_title _('Bitbucket Server Import')
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
%h3.page-title.d-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center

View File

@ -1,5 +1,4 @@
- page_title _('Bitbucket Server import')
- header_title _('Projects'), root_path
%h3.page-title.d-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center

View File

@ -1,5 +1,7 @@
- page_title _("FogBugz Import")
- header_title _("Projects"), root_path
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
%h3.page-title.d-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('bug', css_class: 'gl-mr-2')

View File

@ -1,5 +1,7 @@
- page_title _('User map'), _('FogBugz import')
- header_title _("Projects"), root_path
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
%h3.page-title.d-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('bug', css_class: 'gl-mr-2')

View File

@ -1,5 +1,4 @@
- page_title _("FogBugz import")
- header_title _("Projects"), root_path
%h3.page-title.d-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('bug', css_class: 'gl-mr-2')

View File

@ -1,5 +1,6 @@
- page_title _("Gitea Import")
- header_title _("Projects"), root_path
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
%h3.page-title
= custom_icon('gitea_logo')

View File

@ -1,5 +1,4 @@
- page_title _("Gitea Import")
- header_title _("Projects"), root_path
%h3.page-title
= custom_icon('gitea_logo')
= _('Import Projects from Gitea')

View File

@ -1,9 +1,9 @@
- title = _('Authenticate with GitHub')
- page_title title
- breadcrumb_title title
- header_title _("Projects"), root_path
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
%h2.page-title
%h3.page-title
= title
%p

View File

@ -1,7 +1,5 @@
- title = has_ci_cd_only_params? ? _('Connect repositories from GitHub') : _('GitHub import')
- page_title title
- breadcrumb_title title
- header_title _("Projects"), root_path
%h3.page-title.mb-0.gl-display-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('github', css_class: 'gl-mr-2')

View File

@ -1,5 +1,4 @@
- page_title _("GitLab.com import")
- header_title _("Projects"), root_path
%h3.page-title
= sprite_icon('heart', css_class: 'gl-vertical-align-middle')
= _('Import projects from GitLab.com')

View File

@ -1,5 +1,6 @@
- page_title _("GitLab Import")
- header_title _("Projects"), root_path
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
%h3.page-title.d-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center

View File

@ -1,5 +1,7 @@
- page_title _("Manifest file import")
- header_title _("Projects"), root_path
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
%h3.page-title
= _('Manifest file import')

View File

@ -1,5 +1,4 @@
- page_title _("Manifest import")
- header_title _("Projects"), root_path
%h3.page-title
= _('Manifest file import')

View File

@ -1,7 +1,6 @@
- title = _('Phabricator Server Import')
- page_title title
- breadcrumb_title title
- header_title _("Projects"), root_path
- page_title _('Phabricator Server Import')
- header_title _("New project"), new_project_path
- add_to_breadcrumbs s_('ProjectsNew|Import project'), new_projects_path(anchor: 'import_project')
%h3.page-title.d-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center

View File

@ -97,7 +97,7 @@
#{job.coverage}%
%td
.gl-display-flex
.gl-text-right
.btn-group
- if can?(current_user, :read_job_artifacts, job) && job.artifacts?
= link_to download_project_job_artifacts_path(job.project, job), rel: 'nofollow', download: '', title: _('Download artifacts'), class: 'gl-button btn btn-default btn-icon' do

View File

@ -12,7 +12,7 @@
= s_('Jobs|Use jobs to automate your tasks')
%p
= s_('Jobs|Jobs are the building blocks of a GitLab CI/CD pipeline. Each job has a specific task, like testing code. To set up jobs in a CI/CD pipeline, add a CI/CD configuration file to your project.')
= link_to s_('Jobs|Create CI/CD configuration file'), project_ci_pipeline_editor_path(project), class: 'btn gl-button btn-info js-empty-state-button'
= link_to s_('Jobs|Create CI/CD configuration file'), project_ci_pipeline_editor_path(project), class: 'btn gl-button btn-confirm js-empty-state-button'
- else
.nothing-here-block= s_('Jobs|No jobs to show')
- else

View File

@ -1,7 +1,9 @@
# frozen_string_literal: true
# # frozen_string_literal: true
if Gitlab::Utils.to_boolean(ENV['ENABLE_ACTIVERECORD_EMPTY_PING'], default: true)
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(Gitlab::Database::PostgresqlAdapter::EmptyQueryPing)
end
if Gitlab::Utils.to_boolean(ENV['ENABLE_ACTIVERECORD_TYPEMAP_CACHE'], default: false)
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(Gitlab::Database::PostgresqlAdapter::TypeMapCache)
end

View File

@ -180,7 +180,7 @@ successfully, you must replicate their data using some other means.
|[Project wiki repository](../../../user/project/wiki/) | **Yes** (10.2) | **Yes** (10.7) | No | |
|[Group wiki repository](../../../user/project/wiki/index.md#group-wikis) | [**Yes** (13.10)](https://gitlab.com/gitlab-org/gitlab/-/issues/208147) | No | No | Behind feature flag `geo_group_wiki_repository_replication`, enabled by default. |
|[Uploads](../../uploads.md) | **Yes** (10.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | No | Verified only on transfer or manually using [Integrity Check Rake Task](../../raketasks/check.md) on both sites and comparing the output between them. |
|[LFS objects](../../lfs/index.md) | **Yes** (10.2) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8922) | Via Object Storage provider if supported. Native Geo support (Beta). | Verified only on transfer or manually using [Integrity Check Rake Task](../../raketasks/check.md) on both sites and comparing the output between them. GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/-/issues/32696). |
|[LFS objects](../../lfs/index.md) | **Yes** (10.2) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8922) | Via Object Storage provider if supported. Native Geo support (Beta). | Verified only on transfer or manually using [Integrity Check Rake Task](../../raketasks/check.md) on both sites and comparing the output between them. GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/-/issues/32696).<br /><br />Behind feature flag `geo_lfs_object_replication`, enabled by default. |
|[Personal snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | No | |
|[Project snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | No | |
|[CI job artifacts (other than Job Logs)](../../../ci/pipelines/job_artifacts.md) | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Via Object Storage provider if supported. Native Geo support (Beta). | Verified only manually using [Integrity Check Rake Task](../../raketasks/check.md) on both sites and comparing the output between them. |
@ -205,33 +205,3 @@ successfully, you must replicate their data using some other means.
|[GitLab Pages](../../pages/index.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/589) | No | No | |
|[Dependency proxy images](../../../user/packages/dependency_proxy/index.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/259694) | No | No | Blocked on [Geo: Secondary Mimicry](https://gitlab.com/groups/gitlab-org/-/epics/1528). Note that replication of this cache is not needed for Disaster Recovery purposes because it can be recreated from external sources. |
|[Vulnerability Export](../../../user/application_security/vulnerability_report/#export-vulnerability-details) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/3111) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Not planned because they are ephemeral and sensitive. They can be regenerated on demand. |
#### LFS object replication using the self service framework
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276696) in GitLab 13.12.
> - [Deployed behind a feature flag](../../../user/feature_flags.md), enabled by default.
> - Not enabled on GitLab.com as Geo is not enabled.
> - Recommended for production use.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-lfs-object-replication-using-the-self-service-framework).
There can be [risks when disabling released features](../../../user/feature_flags.md#risks-when-disabling-released-features).
Refer to this feature's version history for more details.
##### Enable or disable LFS object replication using the self service framework
LFS object replication using the self service framework is under development but ready for production use. It is
deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can opt to disable it.
To enable it:
```ruby
Feature.enable(:geo_lfs_object_replication)
```
To disable it:
```ruby
Feature.disable(:geo_lfs_object_replication)
```

View File

@ -246,7 +246,7 @@ control over how the Pages daemon runs and serves content in your environment.
| `gitlab_retrieval_timeout` | The maximum time to wait for a response from the GitLab API per request (default: 30s). |
| `gitlab_retrieval_interval` | The interval to wait before retrying to resolve a domain's configuration via the GitLab API (default: 1s). |
| `gitlab_retrieval_retries` | The maximum number of times to retry to resolve a domain's configuration via the API (default: 3). |
| `domain_config_source` | Domain configuration source (default: `auto`) |
| `domain_config_source` | This parameter was removed in 14.0, on earlier versions it can be used to enable and test API domain configuration source |
| `gitlab_id` | The OAuth application public ID. Leave blank to automatically fill when Pages authenticates with GitLab. |
| `gitlab_secret` | The OAuth application secret. Leave blank to automatically fill when Pages authenticates with GitLab. |
| `auth_scope` | The OAuth application scope to use for authentication. Must match GitLab Pages OAuth application settings. Leave blank to use `api` scope by default. |
@ -281,6 +281,7 @@ control over how the Pages daemon runs and serves content in your environment.
| **`pages_nginx[]`** | |
| `enable` | Include a virtual host `server{}` block for Pages inside NGINX. Needed for NGINX to proxy traffic back to the Pages daemon. Set to `false` if the Pages daemon should directly receive all requests, for example, when using [custom domains](index.md#custom-domains). |
| `FF_ENABLE_REDIRECTS` | Feature flag to disable redirects (enabled by default). Read the [redirects documentation](../../user/project/pages/redirects.md#disable-redirects) for more information. |
| `use_legacy_storage` | Temporarily-introduced parameter allowing to use legacy domain configuration source and storage. [Will be removed in GitLab 14.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6166). |
---
@ -756,51 +757,37 @@ Pages server.
## Domain source configuration
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217912) in GitLab 13.3.
When GitLab Pages daemon serves pages requests it firstly needs to identify which project should be used to
serve the requested URL and how its content is stored.
GitLab Pages can use different sources to get domain configuration.
The default value for Omnibus installations is `nil`.
Before GitLab 13.3, all pages content was extracted to the special shared directory,
and each project had a special configuration file.
The Pages daemon was reading these configuration files and storing their content in memory.
```ruby
gitlab_pages['domain_config_source'] = nil
```
This approach had several disadvantages and was replaced with GitLab Pages using the internal GitLab API
every time a new domain is requested.
The domain information is also cached by the Pages daemon to speed up subsequent requests.
If left unchanged, GitLab Pages tries to use any available source (either `gitlab` or `disk`). The
preferred source is `gitlab`, which uses [API-based configuration](#gitlab-api-based-configuration).
From [GitLab 13.3 to GitLab 13.12](#domain-source-configuration-before-140) GitLab Pages supported both ways of obtaining domain information.
On large GitLab instances, using the API-based configuration significantly improves the pages daemon startup time, as there is no need to load all custom domains configuration into memory.
Starting from [GitLab 14.0](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5993) GitLab Pages uses API
by default and fails to start if it can't connect to it.
For common issues, see the [troubleshooting section](#failed-to-connect-to-the-internal-gitlab-api).
For more details see this [blog post](https://about.gitlab.com/blog/2020/08/03/how-gitlab-pages-uses-the-gitlab-api-to-serve-content/).
### Deprecated `domain_config_source`
### Domain source configuration before 14.0
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217912) in GitLab 13.3.
WARNING:
The flag `gitlab_pages['domain_config_source']` is deprecated for use in [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/217913),
and is planned for removal in GitLab 14.0.
`domain_config_source` parameter is removed and has no effect starting from [GitLab 14.0](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5993)
GitLab 13.0 introduced the special flag `domain_config_source` to support manual opt-in to
[API-based configuration](#gitlab-api-based-configuration).
GitLab 13.7 introduced the [`auto` value](https://gitlab.com/gitlab-org/gitlab/-/issues/218358)
to support a smoother transition to API-based configuration.
From [GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/217912) to [GitLab 13.12](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5993) GitLab Pages can either use `disk` or `gitlab` domain configuration source.
Starting with GitLab 14.0, GitLab Pages only supports API-based configuration, and
[disk source configuration is removed](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/382).
Therefore, GitLab 14.0 also removes `domain_config_source`.
We highly advise you to use `gitlab` configuration source as it will make transition to newer versions easier.
GitLab Pages fails to start if it can't connect to the GitLab API. For other common issues, see the
[troubleshooting section](#failed-to-connect-to-the-internal-gitlab-api)
or report an issue.
### GitLab API-based configuration
WARNING:
The flag `gitlab_pages['domain_config_source']` is deprecated for use in [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/217913),
and is planned for removal in GitLab 14.0. In GitLab 14.0 and later, GitLab Pages attempts to
connect to the API automatically, without requiring the manual configuration steps shown here. Pages
fails to start if this automatic connection fails.
GitLab Pages can use an API-based configuration. This replaces disk source configuration, which
was used prior to GitLab 13.0. Follow these steps to enable it:
To explicitly enable API source:
1. Add the following to your `/etc/gitlab/gitlab.rb` file:
@ -810,14 +797,15 @@ was used prior to GitLab 13.0. Follow these steps to enable it:
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
If you encounter an issue, you can disable it by choosing `disk`:
Or if you want to use legacy confiration source you can:
```ruby
gitlab_pages['domain_config_source'] = "disk"
```
1. Add the following to your `/etc/gitlab/gitlab.rb` file:
For other common issues, see the [troubleshooting section](#failed-to-connect-to-the-internal-gitlab-api)
or report an issue.
```ruby
gitlab_pages['domain_config_source'] = "disk"
```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
### GitLab API cache configuration
@ -1052,7 +1040,7 @@ To migrate GitLab Pages to GitLab 14.0:
1. If your current GitLab version is lower than 13.12, then you first need to upgrade to 13.12.
Upgrading directly to 14.0 may cause downtime for some web-sites hosted on GitLab Pages
until you finish the following steps.
1. Enable the [API-based configuration](#gitlab-api-based-configuration), which
1. Set [`domain_config_source` to `gitlab`](#domain-source-configuration-before-140), which
is the default starting from GitLab 14.0. Skip this step if you're already running GitLab 14.0 or above.
1. If you want to store your pages content in the [object storage](#using-object-storage), make sure to configure it.
If you want to store the pages content locally or continue using an NFS server, skip this step.
@ -1082,6 +1070,16 @@ but commented out to help encourage others to add to it in the future. -->
## Troubleshooting
### How to see GitLab Pages logs
You can see Pages daemon logs by running:
```shell
sudo gitlab-ctl tail gitlab-pages
```
You can also find the log file in `/var/log/gitlab/gitlab-pages/current`.
### `open /etc/ssl/ca-bundle.pem: permission denied`
GitLab Pages runs inside a `chroot` jail, usually in a uniquely numbered directory like
@ -1216,7 +1214,7 @@ Alternatively, run the CI pipelines of those projects that contain a `pages` job
### Failed to connect to the internal GitLab API
If you have enabled [API-based configuration](#gitlab-api-based-configuration) and see the following error:
If you see the following error:
```plaintext
ERRO[0010] Failed to connect to the internal GitLab API after 0.50s error="failed to connect to internal Pages API: HTTP status: 401"
@ -1237,11 +1235,6 @@ error="failed to connect to internal Pages API: Get \"https://gitlab.example.com
### Pages cannot communicate with an instance of the GitLab API
WARNING:
The flag `gitlab_pages['domain_config_source']` is [deprecated](#deprecated-domain_config_source)
for use in [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/217913),
and is planned for removal in GitLab 14.0.
If you use the default value for `domain_config_source=auto` and run multiple instances of GitLab
Pages, you may see intermittent 502 error responses while serving Pages content. You may also see
the following warning in the Pages logs:
@ -1322,3 +1315,25 @@ To enable disk access:
```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
### GitLab Pages doesn't work after upgrading to GitLab 14.0 or above
GitLab 14.0 introduces a number of changes to GitLab Pages which may require manual intervention.
1. Firstly [follow the migration guide](#migrate-gitlab-pages-to-140).
1. If it doesn't work, see [GitLab Pages logs](#how-to-see-gitlab-pages-logs), and if you see any errors there then search them on this page.
WARNING:
As the last resort you can temporarily enable legacy storage and configuration mechanisms. Support for them [will be removed in GitLab 14.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6166), so GitLab Pages will stop working if don't resolve the underlying issue.
To do that:
1. Please describe the issue you're seeing in [here](https://gitlab.com/gitlab-org/gitlab/-/issues/331699).
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_pages['use_legacy_storage'] = true
```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).

View File

@ -250,7 +250,8 @@ Example response:
"path_with_namespace": "diaspora/diaspora-project-site",
"created_at": "2018-07-03T05:48:49.982Z",
"default_branch": null,
"tag_list": [],
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"ssh_url_to_repo": "ssh://user@example.com/diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",

View File

@ -302,7 +302,8 @@ Example response:
"id": 9,
"description": "foo",
"default_branch": "master",
"tag_list": [],
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"archived": false,
"visibility": "internal",
"ssh_url_to_repo": "git@gitlab.example.com/html5-boilerplate.git",
@ -381,9 +382,8 @@ Example response:
"path_with_namespace":"h5bp/html5-boilerplate",
"created_at":"2020-04-27T06:13:22.642Z",
"default_branch":"master",
"tag_list":[
],
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo":"ssh://git@gitlab.com/h5bp/html5-boilerplate.git",
"http_url_to_repo":"http://gitlab.com/h5bp/html5-boilerplate.git",
"web_url":"http://gitlab.com/h5bp/html5-boilerplate",
@ -540,7 +540,8 @@ Example response:
"id": 7,
"description": "Voluptas veniam qui et beatae voluptas doloremque explicabo facilis.",
"default_branch": "master",
"tag_list": [],
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"archived": false,
"visibility": "public",
"ssh_url_to_repo": "git@gitlab.example.com:twitter/typeahead-js.git",
@ -578,7 +579,8 @@ Example response:
"id": 6,
"description": "Aspernatur omnis repudiandae qui voluptatibus eaque.",
"default_branch": "master",
"tag_list": [],
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"archived": false,
"visibility": "internal",
"ssh_url_to_repo": "git@gitlab.example.com:twitter/flight.git",
@ -618,7 +620,8 @@ Example response:
"id": 8,
"description": "Velit eveniet provident fugiat saepe eligendi autem.",
"default_branch": "master",
"tag_list": [],
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"archived": false,
"visibility": "private",
"ssh_url_to_repo": "git@gitlab.example.com:h5bp/html5-boilerplate.git",
@ -886,7 +889,8 @@ Example response:
"id": 9,
"description": "foo",
"default_branch": "master",
"tag_list": [],
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"public": false,
"archived": false,
"visibility": "internal",

View File

@ -151,7 +151,8 @@ Example response:
"path_with_namespace":"root/project-with-clusters-api",
"created_at":"2019-01-02T20:13:32.600Z",
"default_branch":null,
"tag_list":[],
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo":"ssh://gitlab.example.com/root/project-with-clusters-api.git",
"http_url_to_repo":"https://gitlab.example.com/root/project-with-clusters-api.git",
"web_url":"https://gitlab.example.com/root/project-with-clusters-api",
@ -247,7 +248,8 @@ Example response:
"path_with_namespace":"root/project-with-clusters-api",
"created_at":"2019-01-02T20:13:32.600Z",
"default_branch":null,
"tag_list":[],
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo":"ssh:://gitlab.example.com/root/project-with-clusters-api.git",
"http_url_to_repo":"https://gitlab.example.com/root/project-with-clusters-api.git",
"web_url":"https://gitlab.example.com/root/project-with-clusters-api",
@ -357,7 +359,8 @@ Example response:
"path_with_namespace":"root/project-with-clusters-api",
"created_at":"2019-01-02T20:13:32.600Z",
"default_branch":null,
"tag_list":[],
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo":"ssh:://gitlab.example.com/root/project-with-clusters-api.git",
"http_url_to_repo":"https://gitlab.example.com/root/project-with-clusters-api.git",
"web_url":"https://gitlab.example.com/root/project-with-clusters-api",

View File

@ -59,7 +59,7 @@ GET /projects
| `sort` | string | **{dotted-circle}** No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
| `starred` | boolean | **{dotted-circle}** No | Limit by projects starred by the current user. |
| `statistics` | boolean | **{dotted-circle}** No | Include project statistics. |
| `topic` | string | **{dotted-circle}** No | Comma-separated topic names. Limit results to projects that match all of given topics. See `tag_list` attribute. |
| `topic` | string | **{dotted-circle}** No | Comma-separated topic names. Limit results to projects that match all of given topics. See `topics` attribute. |
| `visibility` | string | **{dotted-circle}** No | Limit by visibility `public`, `internal`, or `private`. |
| `wiki_checksum_failed` **(PREMIUM)** | boolean | **{dotted-circle}** No | Limit projects where the wiki checksum calculation has failed ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6137) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2). |
| `with_custom_attributes` | boolean | **{dotted-circle}** No | Include [custom attributes](custom_attributes.md) in response. _(admins only)_ |
@ -82,7 +82,11 @@ When `simple=true` or the user is unauthenticated this returns something like:
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora client"
],
"topics": [
"example",
"disapora client"
],
@ -116,7 +120,11 @@ When the user is authenticated and `simple` is not set this returns something li
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora client"
],
"topics": [
"example",
"disapora client"
],
@ -200,7 +208,11 @@ When the user is authenticated and `simple` is not set this returns something li
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
"web_url": "http://example.com/brightbox/puppet",
"readme_url": "http://example.com/brightbox/puppet/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"puppet"
],
"topics": [
"example",
"puppet"
],
@ -300,6 +312,10 @@ When the user is authenticated and `simple` is not set this returns something li
]
```
NOTE:
The `tag_list` attribute has been deprecated
and is removed in API v5 in favor of the `topics` attribute.
NOTE:
For users of [GitLab Premium or higher](https://about.gitlab.com/pricing/),
the `marked_for_deletion_at` attribute has been deprecated, and is removed
@ -378,7 +394,11 @@ GET /users/:user_id/projects
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora client"
],
"topics": [
"example",
"disapora client"
],
@ -462,7 +482,11 @@ GET /users/:user_id/projects
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
"web_url": "http://example.com/brightbox/puppet",
"readme_url": "http://example.com/brightbox/puppet/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"puppet"
],
"topics": [
"example",
"puppet"
],
@ -606,7 +630,11 @@ Example response:
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora client"
],
"topics": [
"example",
"disapora client"
],
@ -683,7 +711,11 @@ Example response:
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
"web_url": "http://example.com/brightbox/puppet",
"readme_url": "http://example.com/brightbox/puppet/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"puppet"
],
"topics": [
"example",
"puppet"
],
@ -804,7 +836,11 @@ GET /projects/:id
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
"readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
],
"topics": [
"example",
"disapora project"
],
@ -940,6 +976,10 @@ GET /projects/:id
}
```
NOTE:
The `tag_list` attribute has been deprecated
and is removed in API v5 in favor of the `topics` attribute.
Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/)
can also see the `approvals_before_merge` parameter:
@ -974,7 +1014,8 @@ If the project is a fork, and you provide a valid token to authenticate, the
"path_with_namespace":"gitlab-org/gitlab-foss",
"created_at":"2013-09-26T06:02:36.000Z",
"default_branch":"master",
"tag_list":[],
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo":"git@gitlab.com:gitlab-org/gitlab-foss.git",
"http_url_to_repo":"https://gitlab.com/gitlab-org/gitlab-foss.git",
"web_url":"https://gitlab.com/gitlab-org/gitlab-foss",
@ -1393,7 +1434,11 @@ Example responses:
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
"readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
],
"topics": [
"example",
"disapora project"
],
@ -1480,7 +1525,11 @@ Example response:
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
"readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
],
"topics": [
"example",
"disapora project"
],
@ -1573,7 +1622,11 @@ Example response:
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
"readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
],
"topics": [
"example",
"disapora project"
],
@ -1741,7 +1794,11 @@ Example response:
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
"readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
],
"topics": [
"example",
"disapora project"
],
@ -1855,7 +1912,11 @@ Example response:
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
"readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
"tag_list": [
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
],
"topics": [
"example",
"disapora project"
],
@ -2441,7 +2502,8 @@ Example response:
"path_with_namespace": "cute-cats/hello-world",
"created_at": "2020-10-15T16:25:22.415Z",
"default_branch": "master",
"tag_list": [],
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"ssh_url_to_repo": "git@gitlab.example.com:cute-cats/hello-world.git",
"http_url_to_repo": "https://gitlab.example.com/cute-cats/hello-world.git",
"web_url": "https://gitlab.example.com/cute-cats/hello-world",

View File

@ -54,7 +54,8 @@ Example response:
"path_with_namespace": "twitter/flight",
"created_at": "2017-09-05T07:58:01.621Z",
"default_branch": "master",
"tag_list":[],
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo": "ssh://jarka@localhost:2222/twitter/flight.git",
"http_url_to_repo": "http://localhost:3000/twitter/flight.git",
"web_url": "http://localhost:3000/twitter/flight",
@ -475,7 +476,8 @@ Example response:
"path_with_namespace": "twitter/flight",
"created_at": "2017-09-05T07:58:01.621Z",
"default_branch": "master",
"tag_list":[],
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo": "ssh://jarka@localhost:2222/twitter/flight.git",
"http_url_to_repo": "http://localhost:3000/twitter/flight.git",
"web_url": "http://localhost:3000/twitter/flight",

View File

@ -1,6 +1,6 @@
---
stage: package
group: package
stage: Package
group: Package
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
comments: false
description: 'Container Registry metadata database'

View File

@ -7174,6 +7174,18 @@ Status: `data_available`
Tiers: `free`
### `license_billable_users`
Number of all billable users (active users excluding bots and guests).
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/license/20210531204603_license_billable_users.yml)
Group: `group::product intelligence`
Status: `implemented`
Tiers: `premium`, `ultimate`
### `license_expires_at`
The date the license ends

View File

@ -175,7 +175,7 @@ You can [configure](#customizing-the-container-scanning-settings) analyzers by u
| `CI_APPLICATION_TAG` | `$CI_COMMIT_SHA` | Docker repository tag for the image to be scanned. | All |
| `CS_ANALYZER_IMAGE` | `$SECURE_ANALYZERS_PREFIX/$CS_PROJECT:$CS_MAJOR_VERSION` | Docker image of the analyzer. | All |
| `CS_DOCKER_INSECURE` | `"false"` | Allow access to secure Docker registries using HTTPS without validating the certificates. | All |
| `CS_REGISTRY_INSECURE` | `"false"` | Allow access to insecure registries (HTTP only). Should only be set to `true` when testing the image locally. | All |
| `CS_REGISTRY_INSECURE` | `"false"` | Allow access to insecure registries (HTTP only). Should only be set to `true` when testing the image locally. | Trivy. The registry must listen on port `80/tcp`. |
| `CS_SEVERITY_THRESHOLD` | `UNKNOWN` | Severity level threshold. The scanner outputs vulnerabilities with severity level higher than or equal to this threshold. Supported levels are Unknown, Low, Medium, High, and Critical. | Trivy |
| `DOCKER_IMAGE` | `$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG` | The Docker image to be scanned. If set, this variable overrides the `$CI_APPLICATION_REPOSITORY` and `$CI_APPLICATION_TAG` variables. | All |
| `DOCKER_PASSWORD` | `$CI_REGISTRY_PASSWORD` | Password for accessing a Docker registry requiring authentication. | All |

View File

@ -4,15 +4,13 @@ module API
module Entities
class BasicProjectDetails < Entities::ProjectIdentity
include ::API::ProjectsRelationBuilder
include Gitlab::Utils::StrongMemoize
expose :default_branch, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) }
# Avoids an N+1 query: https://github.com/mbleigh/acts-as-taggable-on/issues/91#issuecomment-168273770
expose :tag_list do |project|
# Tags is a preloaded association. If we perform then sorting
# through the database, it will trigger a new query, ending up
# in an N+1 if we have several projects
project.tags.pluck(:name).sort # rubocop:disable CodeReuse/ActiveRecord
end
expose :topic_names, as: :tag_list
expose :topic_names, as: :topics
expose :ssh_url_to_repo, :http_url_to_repo, :web_url, :readme_url
@ -40,7 +38,7 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def self.preload_relation(projects_relation, options = {})
# Preloading tags, should be done with using only `:tags`,
# Preloading topics, should be done with using only `:tags`,
# as `:tags` are defined as: `has_many :tags, through: :taggings`
# N+1 is solved then by using `subject.tags.map(&:name)`
# MR describing the solution: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/20555
@ -50,6 +48,19 @@ module API
.preload(namespace: [:route, :owner])
end
# rubocop: enable CodeReuse/ActiveRecord
private
alias_method :project, :object
def topic_names
# Topics is a preloaded association. If we perform then sorting
# through the database, it will trigger a new query, ending up
# in an N+1 if we have several projects
strong_memoize(:topic_names) do
project.tags.pluck(:name).sort # rubocop:disable CodeReuse/ActiveRecord
end
end
end
end
end

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
# Caches loading of additional types from the DB
# https://github.com/rails/rails/blob/v6.0.3.2/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L521-L589
# rubocop:disable Gitlab/ModuleWithInstanceVariables
module Gitlab
module Database
module PostgresqlAdapter
module TypeMapCache
extend ActiveSupport::Concern
TYPE_MAP_CACHE_MONITOR = ::Monitor.new
class_methods do
def type_map_cache
TYPE_MAP_CACHE_MONITOR.synchronize do
@type_map_cache ||= {}
end
end
end
def initialize_type_map(map = type_map)
TYPE_MAP_CACHE_MONITOR.synchronize do
cached_type_map = self.class.type_map_cache[@connection_parameters.hash]
break @type_map = cached_type_map if cached_type_map
super
self.class.type_map_cache[@connection_parameters.hash] = map
end
end
def reload_type_map
TYPE_MAP_CACHE_MONITOR.synchronize do
self.class.type_map_cache[@connection_parameters.hash] = nil
end
super
end
end
end
end
end

View File

@ -242,7 +242,7 @@ module Gitlab
def self.encode(object, limit: 25.megabytes)
return ::Gitlab::Json.dump(object) unless Feature.enabled?(:json_limited_encoder)
buffer = []
buffer = StringIO.new
buffer_size = 0
::Yajl::Encoder.encode(object) do |data_chunk|
@ -254,7 +254,7 @@ module Gitlab
buffer_size += chunk_size
end
buffer.join('')
buffer.string
end
end
end

View File

@ -19162,9 +19162,6 @@ msgstr ""
msgid "LFS"
msgstr ""
msgid "LFS object"
msgstr ""
msgid "LFS objects"
msgstr ""

View File

@ -23,9 +23,17 @@ module QA
#
# @return [void]
def configure_allure
# Match job names like ee:relative, ce:update etc. and set as execution environment
env_matcher = /^(?<env>\w{2}:\S+)/
AllureRspec.configure do |config|
config.results_directory = 'tmp/allure-results'
config.clean_results_directory = true
# Set custom environment name to separate same specs executed on different environments
if Env.running_in_ci? && Env.ci_job_name.match?(env_matcher)
config.environment = Env.ci_job_name.match(env_matcher).named_captures['env']
end
end
end
@ -67,7 +75,7 @@ module QA
issue = example.metadata.dig(:quarantine, :issue)
example.issue('Issue', issue) if issue
example.add_link(name: "Job(#{ENV['CI_JOB_NAME']})", url: ENV['CI_JOB_URL']) if ENV['CI']
example.add_link(name: "Job(#{Env.ci_job_name})", url: Env.ci_job_url) if Env.running_in_ci?
end
end
end

View File

@ -81,7 +81,8 @@ RSpec.describe 'Groups > Members > Manage members' do
category: 'Members::CreateService',
action: 'create_member',
label: 'unknown',
property: 'existing_user'
property: 'existing_user',
user: user1
)
end
@ -189,7 +190,8 @@ RSpec.describe 'Groups > Members > Manage members' do
category: 'Members::InviteService',
action: 'create_member',
label: 'unknown',
property: 'net_new_user'
property: 'net_new_user',
user: user1
)
end
end

View File

@ -30,14 +30,14 @@ RSpec.describe 'Import/Export - project import integration test', :js do
it 'user imports an exported project successfully', :sidekiq_might_not_need_inline do
visit new_project_path
click_import_project_tab
click_import_project
click_link 'GitLab export'
fill_in :name, with: 'Test Project Name', visible: true
fill_in :path, with: 'test-project-path', visible: true
attach_file('file', file)
expect { click_on 'Import project' }.to change { Project.count }.by(1)
expect { click_button 'Import project' }.to change { Project.count }.by(1)
project = Project.last
expect(project).not_to be_nil
@ -49,11 +49,11 @@ RSpec.describe 'Import/Export - project import integration test', :js do
visit new_project_path
click_import_project_tab
click_import_project
click_link 'GitLab export'
fill_in :name, with: project.name, visible: true
attach_file('file', file)
click_on 'Import project'
click_button 'Import project'
page.within('.flash-container') do
expect(page).to have_content('Project could not be imported')
@ -61,7 +61,7 @@ RSpec.describe 'Import/Export - project import integration test', :js do
end
end
def click_import_project_tab
def click_import_project
find('[data-qa-selector="import_project_link"]').click
end
end

View File

@ -60,7 +60,8 @@ RSpec.describe 'Project members list', :js do
category: 'Members::CreateService',
action: 'create_member',
label: 'unknown',
property: 'existing_user'
property: 'existing_user',
user: user1
)
end
@ -117,7 +118,8 @@ RSpec.describe 'Project members list', :js do
category: 'Members::InviteService',
action: 'create_member',
label: 'unknown',
property: 'net_new_user'
property: 'net_new_user',
user: user1
)
end

View File

@ -15,134 +15,151 @@ RSpec.describe 'User views releases', :js do
let_it_be(:guest) { create(:user) }
before do
stub_feature_flags(releases_index_apollo_client: false)
project.add_maintainer(maintainer)
project.add_guest(guest)
end
context('when the user is a maintainer') do
before do
sign_in(maintainer)
shared_examples 'releases index page' do
context('when the user is a maintainer') do
before do
sign_in(maintainer)
visit project_releases_path(project)
end
it 'sees the release' do
page.within("##{release_v1.tag}") do
expect(page).to have_content(release_v1.name)
expect(page).to have_content(release_v1.tag)
expect(page).not_to have_content('Upcoming Release')
visit project_releases_path(project)
end
end
context 'when there is a link as an asset' do
let!(:release_link) { create(:release_link, release: release_v1, url: url ) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{release_link.filepath}" }
it 'sees the link' do
page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_css('[data-testid="external-link-indicator"]')
it 'sees the release' do
page.within("##{release_v1.tag}") do
expect(page).to have_content(release_v1.name)
expect(page).to have_content(release_v1.tag)
expect(page).not_to have_content('Upcoming Release')
end
end
context 'when there is a link redirect' do
let!(:release_link) { create(:release_link, release: release_v1, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
context 'when there is a link as an asset' do
let!(:release_link) { create(:release_link, release: release_v1, url: url ) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{release_link.filepath}" }
it 'sees the link', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/329301' do
it 'sees the link' do
page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_css('[data-testid="external-link-indicator"]')
end
end
end
context 'when url points to external resource' do
let(:url) { 'http://google.com/download' }
context 'when there is a link redirect' do
let!(:release_link) { create(:release_link, release: release_v1, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
it 'sees that the link is external resource', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/329302' do
page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_css('[data-testid="external-link-indicator"]')
it 'sees the link', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/329301' do
page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_css('[data-testid="external-link-indicator"]')
end
end
end
end
end
context 'with an upcoming release' do
it 'sees the upcoming tag' do
page.within("##{release_v3.tag}") do
expect(page).to have_content('Upcoming Release')
end
end
end
context 'when url points to external resource' do
let(:url) { 'http://google.com/download' }
context 'with a tag containing a slash' do
it 'sees the release' do
page.within("##{release_v2.tag.parameterize}") do
expect(page).to have_content(release_v2.name)
expect(page).to have_content(release_v2.tag)
end
end
end
context 'sorting' do
def sort_page(by:, direction:)
within '[data-testid="releases-sort"]' do
find('.dropdown-toggle').click
click_button(by, class: 'dropdown-item')
find('.sorting-direction-button').click if direction == :ascending
end
end
shared_examples 'releases sort order' do
it "sorts the releases #{description}" do
card_titles = page.all('.release-block .card-title', minimum: expected_releases.count)
card_titles.each_with_index do |title, index|
expect(title).to have_content(expected_releases[index].name)
it 'sees that the link is external resource', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/329302' do
page.within("##{release_v1.tag} .js-assets-list") do
expect(page).to have_css('[data-testid="external-link-indicator"]')
end
end
end
end
context "when the page is sorted by the default sort order" do
let(:expected_releases) { [release_v3, release_v2, release_v1] }
it_behaves_like 'releases sort order'
context 'with an upcoming release' do
it 'sees the upcoming tag' do
page.within("##{release_v3.tag}") do
expect(page).to have_content('Upcoming Release')
end
end
end
context "when the page is sorted by created_at ascending " do
let(:expected_releases) { [release_v2, release_v1, release_v3] }
context 'with a tag containing a slash' do
it 'sees the release' do
page.within("##{release_v2.tag.parameterize}") do
expect(page).to have_content(release_v2.name)
expect(page).to have_content(release_v2.tag)
end
end
end
before do
sort_page by: 'Created date', direction: :ascending
context 'sorting' do
def sort_page(by:, direction:)
within '[data-testid="releases-sort"]' do
find('.dropdown-toggle').click
click_button(by, class: 'dropdown-item')
find('.sorting-direction-button').click if direction == :ascending
end
end
it_behaves_like 'releases sort order'
shared_examples 'releases sort order' do
it "sorts the releases #{description}" do
card_titles = page.all('.release-block .card-title', minimum: expected_releases.count)
card_titles.each_with_index do |title, index|
expect(title).to have_content(expected_releases[index].name)
end
end
end
context "when the page is sorted by the default sort order" do
let(:expected_releases) { [release_v3, release_v2, release_v1] }
it_behaves_like 'releases sort order'
end
context "when the page is sorted by created_at ascending " do
let(:expected_releases) { [release_v2, release_v1, release_v3] }
before do
sort_page by: 'Created date', direction: :ascending
end
it_behaves_like 'releases sort order'
end
end
end
context('when the user is a guest') do
before do
sign_in(guest)
end
it 'renders release info except for Git-related data' do
visit project_releases_path(project)
within('.release-block', match: :first) do
expect(page).to have_content(release_v3.description)
# The following properties (sometimes) include Git info,
# so they are not rendered for Guest users
expect(page).not_to have_content(release_v3.name)
expect(page).not_to have_content(release_v3.tag)
expect(page).not_to have_content(release_v3.commit.short_id)
end
end
end
end
context('when the user is a guest') do
context 'when the releases_index_apollo_client feature flag is enabled' do
before do
sign_in(guest)
stub_feature_flags(releases_index_apollo_client: true)
end
it 'renders release info except for Git-related data' do
visit project_releases_path(project)
it_behaves_like 'releases index page'
end
within('.release-block', match: :first) do
expect(page).to have_content(release_v3.description)
# The following properties (sometimes) include Git info,
# so they are not rendered for Guest users
expect(page).not_to have_content(release_v3.name)
expect(page).not_to have_content(release_v3.tag)
expect(page).not_to have_content(release_v3.commit.short_id)
end
context 'when the releases_index_apollo_client feature flag is disabled' do
before do
stub_feature_flags(releases_index_apollo_client: false)
end
it_behaves_like 'releases index page'
end
end

View File

@ -15,6 +15,7 @@
"description",
"default_branch",
"tag_list",
"topics",
"ssh_url_to_repo",
"http_url_to_repo",
"web_url",
@ -34,6 +35,7 @@
"description": { "type": ["string", "null"] },
"default_branch": { "type": ["string", "null"] },
"tag_list": { "type": "array" },
"topics": { "type": "array" },
"ssh_url_to_repo": { "type": "string" },
"http_url_to_repo": { "type": "string" },
"web_url": { "type": "string" },

View File

@ -15,6 +15,12 @@
"type": "string"
}
},
"topics": {
"type": "array",
"items": {
"type": "string"
}
},
"ssh_url_to_repo": { "type": "string" },
"http_url_to_repo": { "type": "string" },
"web_url": { "type": "string" },
@ -37,7 +43,7 @@
},
"required": [
"id", "name", "name_with_namespace", "description", "path",
"path_with_namespace", "created_at", "default_branch", "tag_list",
"path_with_namespace", "created_at", "default_branch", "tag_list", "topics",
"ssh_url_to_repo", "http_url_to_repo", "web_url", "readme_url", "avatar_url",
"star_count", "forks_count", "last_activity_at", "namespace"
],

View File

@ -3,6 +3,7 @@
"description": "",
"default_branch": null,
"tag_list": [],
"topics": [],
"public": true,
"archived": false,
"visibility_level": 20,
@ -54,6 +55,7 @@
"description": "Voluptatem quae nulla eius numquam ullam voluptatibus quia modi.",
"default_branch": "master",
"tag_list": [],
"topics": [],
"public": false,
"archived": false,
"visibility_level": 0,
@ -114,6 +116,7 @@
"description": "Modi odio mollitia dolorem qui.",
"default_branch": "master",
"tag_list": [],
"topics": [],
"public": false,
"archived": false,
"visibility_level": 0,
@ -162,6 +165,7 @@
"description": "Omnis asperiores ipsa et beatae quidem necessitatibus quia.",
"default_branch": "master",
"tag_list": [],
"topics": [],
"public": true,
"archived": false,
"visibility_level": 20,
@ -210,6 +214,7 @@
"description": "Voluptatem commodi voluptate placeat architecto beatae illum dolores fugiat.",
"default_branch": "master",
"tag_list": [],
"topics": [],
"public": false,
"archived": false,
"visibility_level": 0,
@ -258,6 +263,7 @@
"description": "Aut molestias quas est ut aperiam officia quod libero.",
"default_branch": "master",
"tag_list": [],
"topics": [],
"public": true,
"archived": false,
"visibility_level": 20,
@ -309,6 +315,7 @@
"description": "Excepturi molestiae quia repellendus omnis est illo illum eligendi.",
"default_branch": "master",
"tag_list": [],
"topics": [],
"public": true,
"archived": false,
"visibility_level": 20,
@ -357,6 +364,7 @@
"description": "Adipisci quaerat dignissimos enim sed ipsam dolorem quia.",
"default_branch": "master",
"tag_list": [],
"topics": [],
"public": false,
"archived": false,
"visibility_level": 10,
@ -408,6 +416,7 @@
"description": "Vel voluptatem maxime saepe ex quia.",
"default_branch": "master",
"tag_list": [],
"topics": [],
"public": false,
"archived": false,
"visibility_level": 0,

View File

@ -7,8 +7,8 @@ import EditDrawer from '~/static_site_editor/components/edit_drawer.vue';
import EditHeader from '~/static_site_editor/components/edit_header.vue';
import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue';
import UnsavedChangesConfirmDialog from '~/static_site_editor/components/unsaved_changes_confirm_dialog.vue';
import { EDITOR_TYPES } from '~/vue_shared/components/rich_content_editor/constants';
import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
import { EDITOR_TYPES } from '~/static_site_editor/rich_content_editor/constants';
import RichContentEditor from '~/static_site_editor/rich_content_editor/rich_content_editor.vue';
import {
sourceContentTitle as title,

View File

@ -1,5 +1,5 @@
import buildCustomRenderer from '~/vue_shared/components/rich_content_editor/services/build_custom_renderer';
import buildHTMLToMarkdownRenderer from '~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer';
import buildCustomRenderer from '~/static_site_editor/rich_content_editor/services/build_custom_renderer';
import buildHTMLToMarkdownRenderer from '~/static_site_editor/rich_content_editor/services/build_html_to_markdown_renderer';
import {
generateToolbarItem,
addCustomEventListener,
@ -9,12 +9,12 @@ import {
insertVideo,
getMarkdown,
getEditorOptions,
} from '~/vue_shared/components/rich_content_editor/services/editor_service';
import sanitizeHTML from '~/vue_shared/components/rich_content_editor/services/sanitize_html';
} from '~/static_site_editor/rich_content_editor/services/editor_service';
import sanitizeHTML from '~/static_site_editor/rich_content_editor/services/sanitize_html';
jest.mock('~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer');
jest.mock('~/vue_shared/components/rich_content_editor/services/build_custom_renderer');
jest.mock('~/vue_shared/components/rich_content_editor/services/sanitize_html');
jest.mock('~/static_site_editor/rich_content_editor/services/build_html_to_markdown_renderer');
jest.mock('~/static_site_editor/rich_content_editor/services/build_custom_renderer');
jest.mock('~/static_site_editor/rich_content_editor/services/sanitize_html');
describe('Editor Service', () => {
let mockInstance;

View File

@ -1,8 +1,8 @@
import { GlModal, GlTabs } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { IMAGE_TABS } from '~/vue_shared/components/rich_content_editor/constants';
import AddImageModal from '~/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue';
import UploadImageTab from '~/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab.vue';
import { IMAGE_TABS } from '~/static_site_editor/rich_content_editor/constants';
import AddImageModal from '~/static_site_editor/rich_content_editor/modals/add_image/add_image_modal.vue';
import UploadImageTab from '~/static_site_editor/rich_content_editor/modals/add_image/upload_image_tab.vue';
describe('Add Image Modal', () => {
let wrapper;

View File

@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import UploadImageTab from '~/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab.vue';
import UploadImageTab from '~/static_site_editor/rich_content_editor/modals/add_image/upload_image_tab.vue';
describe('Upload Image Tab', () => {
let wrapper;

View File

@ -1,6 +1,6 @@
import { GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import InsertVideoModal from '~/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue';
import InsertVideoModal from '~/static_site_editor/rich_content_editor/modals/insert_video_modal.vue';
describe('Insert Video Modal', () => {
let wrapper;

View File

@ -1,8 +1,8 @@
import Editor from '@toast-ui/editor';
import buildMarkdownToHTMLRenderer from '~/vue_shared/components/rich_content_editor/services/build_custom_renderer';
import { registerHTMLToMarkdownRenderer } from '~/vue_shared/components/rich_content_editor/services/editor_service';
import buildMarkdownToHTMLRenderer from '~/static_site_editor/rich_content_editor/services/build_custom_renderer';
import { registerHTMLToMarkdownRenderer } from '~/static_site_editor/rich_content_editor/services/editor_service';
describe('vue_shared/components/rich_content_editor', () => {
describe('static_site_editor/rich_content_editor', () => {
let editor;
const buildEditor = () => {

View File

@ -5,10 +5,10 @@ import {
EDITOR_HEIGHT,
EDITOR_PREVIEW_STYLE,
CUSTOM_EVENTS,
} from '~/vue_shared/components/rich_content_editor/constants';
import AddImageModal from '~/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue';
import InsertVideoModal from '~/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue';
import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
} from '~/static_site_editor/rich_content_editor/constants';
import AddImageModal from '~/static_site_editor/rich_content_editor/modals/add_image/add_image_modal.vue';
import InsertVideoModal from '~/static_site_editor/rich_content_editor/modals/insert_video_modal.vue';
import RichContentEditor from '~/static_site_editor/rich_content_editor/rich_content_editor.vue';
import {
addCustomEventListener,
@ -18,9 +18,9 @@ import {
registerHTMLToMarkdownRenderer,
getEditorOptions,
getMarkdown,
} from '~/vue_shared/components/rich_content_editor/services/editor_service';
} from '~/static_site_editor/rich_content_editor/services/editor_service';
jest.mock('~/vue_shared/components/rich_content_editor/services/editor_service', () => ({
jest.mock('~/static_site_editor/rich_content_editor/services/editor_service', () => ({
addCustomEventListener: jest.fn(),
removeCustomEventListener: jest.fn(),
addImage: jest.fn(),

View File

@ -1,4 +1,4 @@
import buildCustomHTMLRenderer from '~/vue_shared/components/rich_content_editor/services/build_custom_renderer';
import buildCustomHTMLRenderer from '~/static_site_editor/rich_content_editor/services/build_custom_renderer';
describe('Build Custom Renderer Service', () => {
describe('buildCustomHTMLRenderer', () => {

View File

@ -1,4 +1,4 @@
import buildHTMLToMarkdownRenderer from '~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer';
import buildHTMLToMarkdownRenderer from '~/static_site_editor/rich_content_editor/services/build_html_to_markdown_renderer';
import { attributeDefinition } from './renderers/mock_data';
describe('rich_content_editor/services/html_to_markdown_renderer', () => {

View File

@ -6,7 +6,7 @@ import {
buildUneditableBlockTokens,
buildUneditableInlineTokens,
buildUneditableHtmlAsTextTokens,
} from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
} from '~/static_site_editor/rich_content_editor/services/renderers/build_uneditable_token';
import {
originInlineToken,

View File

@ -1,4 +1,4 @@
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_attribute_definition';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_attribute_definition';
import { attributeDefinition } from './mock_data';
describe('rich_content_editor/renderers/render_attribute_definition', () => {

View File

@ -1,5 +1,5 @@
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_embedded_ruby_text';
import { renderUneditableLeaf } from '~/vue_shared/components/rich_content_editor/services/renderers/render_utils';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_embedded_ruby_text';
import { renderUneditableLeaf } from '~/static_site_editor/rich_content_editor/services/renderers/render_utils';
import { buildMockTextNode, normalTextNode } from './mock_data';

View File

@ -1,5 +1,5 @@
import { buildUneditableInlineTokens } from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_font_awesome_html_inline';
import { buildUneditableInlineTokens } from '~/static_site_editor/rich_content_editor/services/renderers/build_uneditable_token';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_font_awesome_html_inline';
import { normalTextNode } from './mock_data';

View File

@ -1,5 +1,5 @@
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_heading';
import * as renderUtils from '~/vue_shared/components/rich_content_editor/services/renderers/render_utils';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_heading';
import * as renderUtils from '~/static_site_editor/rich_content_editor/services/renderers/render_utils';
describe('rich_content_editor/renderers/render_heading', () => {
it('canRender delegates to renderUtils.willAlwaysRender', () => {

View File

@ -1,5 +1,5 @@
import { buildUneditableHtmlAsTextTokens } from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_html_block';
import { buildUneditableHtmlAsTextTokens } from '~/static_site_editor/rich_content_editor/services/renderers/build_uneditable_token';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_html_block';
describe('rich_content_editor/services/renderers/render_html_block', () => {
const htmlBlockNode = {

View File

@ -1,5 +1,5 @@
import { buildUneditableInlineTokens } from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text';
import { buildUneditableInlineTokens } from '~/static_site_editor/rich_content_editor/services/renderers/build_uneditable_token';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_identifier_instance_text';
import { buildMockTextNode, normalTextNode } from './mock_data';

View File

@ -1,4 +1,4 @@
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_identifier_paragraph';
import { buildMockTextNode } from './mock_data';

View File

@ -1,5 +1,5 @@
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_list_item';
import * as renderUtils from '~/vue_shared/components/rich_content_editor/services/renderers/render_utils';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_list_item';
import * as renderUtils from '~/static_site_editor/rich_content_editor/services/renderers/render_utils';
describe('rich_content_editor/renderers/render_list_item', () => {
it('canRender delegates to renderUtils.willAlwaysRender', () => {

View File

@ -1,4 +1,4 @@
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_softbreak';
import renderer from '~/static_site_editor/rich_content_editor/services/renderers/render_softbreak';
describe('Render softbreak renderer', () => {
describe('canRender', () => {

View File

@ -1,13 +1,13 @@
import {
buildUneditableBlockTokens,
buildUneditableOpenTokens,
} from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
} from '~/static_site_editor/rich_content_editor/services/renderers/build_uneditable_token';
import {
renderUneditableLeaf,
renderUneditableBranch,
renderWithAttributeDefinitions,
willAlwaysRender,
} from '~/vue_shared/components/rich_content_editor/services/renderers/render_utils';
} from '~/static_site_editor/rich_content_editor/services/renderers/render_utils';
import { originToken, uneditableCloseToken, attributeDefinition } from './mock_data';

View File

@ -1,4 +1,4 @@
import sanitizeHTML from '~/vue_shared/components/rich_content_editor/services/sanitize_html';
import sanitizeHTML from '~/static_site_editor/rich_content_editor/services/sanitize_html';
describe('rich_content_editor/services/sanitize_html', () => {
it.each`

View File

@ -1,7 +1,7 @@
import { GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import ToolbarItem from '~/vue_shared/components/rich_content_editor/toolbar_item.vue';
import ToolbarItem from '~/static_site_editor/rich_content_editor/toolbar_item.vue';
describe('Toolbar Item', () => {
let wrapper;

View File

@ -0,0 +1,75 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::PostgresqlAdapter::TypeMapCache do
let(:db_config) { ActiveRecord::Base.configurations.configs_for(env_name: 'test', name: 'primary').configuration_hash }
let(:adapter_class) do
Class.new(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
end
describe '#initialize_type_map' do
it 'caches loading of types in memory' do
initialize_connection.disconnect!
recorder_without_cache = ActiveRecord::QueryRecorder.new(skip_schema_queries: false) { initialize_connection.disconnect! }
expect(recorder_without_cache.log).to include(a_string_matching(/FROM pg_type/)).twice
adapter_class.prepend(described_class)
initialize_connection.disconnect!
recorder_with_cache = ActiveRecord::QueryRecorder.new(skip_schema_queries: false) { initialize_connection.disconnect! }
expect(recorder_with_cache.count).to be < recorder_without_cache.count
# There's still one pg_type query left here because `#add_pg_decoders` executes another pg_type query
# in https://github.com/rails/rails/blob/v6.1.3.2/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L912.
# This query is much cheaper because it only returns very few records.
expect(recorder_with_cache.log).to include(a_string_matching(/FROM pg_type/)).once
end
it 'only reuses the cache if the connection parameters are exactly the same' do
adapter_class.prepend(described_class)
initialize_connection.disconnect!
other_config = db_config.dup
other_config[:connect_timeout] = db_config[:connect_timeout].to_i + 10
recorder = ActiveRecord::QueryRecorder.new(skip_schema_queries: false) { initialize_connection(other_config).disconnect! }
expect(recorder.log).to include(a_string_matching(/FROM pg_type/)).twice
end
end
describe '#reload_type_map' do
it 'clears the cache and executes the type map query again' do
adapter_class.prepend(described_class)
initialize_connection.disconnect!
connection = initialize_connection
recorder = ActiveRecord::QueryRecorder.new(skip_schema_queries: false) { connection.reload_type_map }
expect(recorder.log).to include(a_string_matching(/FROM pg_type/)).once
end
end
# Based on https://github.com/rails/rails/blob/v6.1.3.2/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L36-L41
def initialize_connection(config = db_config)
conn_params = config.symbolize_keys.compact
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
conn_params.slice!(*valid_conn_param_keys)
adapter_class.new(
adapter_class.new_client(conn_params),
ActiveRecord::Base.logger,
conn_params,
config
)
end
end

View File

@ -411,7 +411,7 @@ RSpec.describe Gitlab::Json do
end
describe Gitlab::Json::LimitedEncoder do
subject { described_class.encode(obj, limit: 8.kilobytes) }
subject { described_class.encode(obj, limit: 10.kilobytes) }
context 'when object size is acceptable' do
let(:obj) { { test: true } }
@ -431,6 +431,16 @@ RSpec.describe Gitlab::Json do
end
end
context 'when object contains ASCII-8BIT encoding' do
let(:obj) { [{ a: "\x8F" }] * 1000 }
it 'does not raise encoding error' do
expect { subject }.not_to raise_error
expect(subject).to be_a(String)
expect(subject.size).to eq(10001)
end
end
context 'when json_limited_encoder is disabled' do
let(:obj) { [{ test: true }] * 1000 }

View File

@ -69,6 +69,7 @@ itself: # project
- shared_with_groups
- ssh_url_to_repo
- tag_list
- topics
- web_url
build_auto_devops: # auto_devops

View File

@ -184,13 +184,14 @@ RSpec.describe API::Projects do
end
end
it 'includes the project labels as the tag_list' do
it 'includes project topics' do
get api('/projects', user)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.first.keys).to include('tag_list')
expect(json_response.first.keys).to include('tag_list') # deprecated in favor of 'topics'
expect(json_response.first.keys).to include('topics')
end
it 'includes open_issues_count' do
@ -1892,7 +1893,8 @@ RSpec.describe API::Projects do
expect(json_response['id']).to eq(project.id)
expect(json_response['description']).to eq(project.description)
expect(json_response['default_branch']).to eq(project.default_branch)
expect(json_response['tag_list']).to be_an Array
expect(json_response['tag_list']).to be_an Array # deprecated in favor of 'topics'
expect(json_response['topics']).to be_an Array
expect(json_response['archived']).to be_falsey
expect(json_response['visibility']).to be_present
expect(json_response['ssh_url_to_repo']).to be_present
@ -1969,7 +1971,8 @@ RSpec.describe API::Projects do
expect(json_response['id']).to eq(project.id)
expect(json_response['description']).to eq(project.description)
expect(json_response['default_branch']).to eq(project.default_branch)
expect(json_response['tag_list']).to be_an Array
expect(json_response['tag_list']).to be_an Array # deprecated in favor of 'topics'
expect(json_response['topics']).to be_an Array
expect(json_response['archived']).to be_falsey
expect(json_response['visibility']).to be_present
expect(json_response['ssh_url_to_repo']).to be_present

View File

@ -2,15 +2,16 @@
module ActiveRecord
class QueryRecorder
attr_reader :log, :skip_cached, :cached, :data
attr_reader :log, :skip_cached, :skip_schema_queries, :cached, :data
UNKNOWN = %w[unknown unknown].freeze
def initialize(skip_cached: true, log_file: nil, query_recorder_debug: false, &block)
def initialize(skip_cached: true, skip_schema_queries: true, log_file: nil, query_recorder_debug: false, &block)
@data = Hash.new { |h, k| h[k] = { count: 0, occurrences: [], backtrace: [], durations: [] } }
@log = []
@cached = []
@skip_cached = skip_cached
@skip_schema_queries = skip_schema_queries
@query_recorder_debug = ENV['QUERY_RECORDER_DEBUG'] || query_recorder_debug
@log_file = log_file
record(&block) if block_given?
@ -79,7 +80,7 @@ module ActiveRecord
if values[:cached] && skip_cached
@cached << values[:sql]
elsif !values[:name]&.include?("SCHEMA")
elsif !skip_schema_queries || !values[:name]&.include?("SCHEMA")
backtrace = @query_recorder_debug ? show_backtrace(values, duration) : nil
@log << values[:sql]
store_sql_by_source(values: values, duration: duration, backtrace: backtrace)

View File

@ -5,6 +5,7 @@ import (
"context"
"fmt"
"io"
"mime"
"net/http"
"os"
"os/exec"
@ -52,6 +53,14 @@ func (e *entry) Inject(w http.ResponseWriter, r *http.Request, sendData string)
}
}
func detectFileContentType(fileName string) string {
contentType := mime.TypeByExtension(filepath.Ext(fileName))
if contentType == "" {
contentType = "application/octet-stream"
}
return contentType
}
func unpackFileFromZip(ctx context.Context, archivePath, encodedFilename string, headers http.Header, output io.Writer) error {
fileName, err := zipartifacts.DecodeFileEntry(encodedFilename)
if err != nil {
@ -88,15 +97,7 @@ func unpackFileFromZip(ctx context.Context, archivePath, encodedFilename string,
// Write http headers about the file
headers.Set("Content-Length", contentLength)
// Using application/octet-stream tells the client that we don't
// really know what Content-Type is. Since this file is being sent
// as attachment, browsers don't need to know to save the
// file. Chrome doesn't appear to pay attention to Content-Type when
// Content-Disposition is an attachment, and Firefox only uses it if there
// is no extension in the filename. Thus, there's no need for
// Workhorse to guess Content-Type based on the filename.
headers.Set("Content-Type", "application/octet-stream")
headers.Set("Content-Type", detectFileContentType(fileName))
headers.Set("Content-Disposition", "attachment; filename=\""+escapeQuotes(basename)+"\"")
// Copy file body to client
if _, err := io.Copy(output, reader); err != nil {

View File

@ -54,7 +54,7 @@ func TestDownloadingFromValidArchive(t *testing.T) {
testhelper.RequireResponseHeader(t, response,
"Content-Type",
"application/octet-stream")
"text/plain; charset=utf-8")
testhelper.RequireResponseHeader(t, response,
"Content-Disposition",
"attachment; filename=\"test.txt\"")
@ -88,7 +88,7 @@ func TestDownloadingFromValidHTTPArchive(t *testing.T) {
testhelper.RequireResponseHeader(t, response,
"Content-Type",
"application/octet-stream")
"text/plain; charset=utf-8")
testhelper.RequireResponseHeader(t, response,
"Content-Disposition",
"attachment; filename=\"test.txt\"")