Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
6be8ed5a95
commit
c74f702c74
|
@ -1 +1 @@
|
|||
7c2fcde23bd4a962409897adbbb71da11c6db99a
|
||||
a31bd1be25d0ff03efaa7f756321ea9440122b24
|
||||
|
|
|
@ -13,6 +13,7 @@ import { __ } from '~/locale';
|
|||
import Tracking from '~/tracking';
|
||||
import {
|
||||
NOT_ENOUGH_DATA_ERROR,
|
||||
FIELD_KEY_TITLE,
|
||||
PAGINATION_SORT_FIELD_END_EVENT,
|
||||
PAGINATION_SORT_FIELD_DURATION,
|
||||
PAGINATION_SORT_DIRECTION_ASC,
|
||||
|
@ -22,7 +23,8 @@ import TotalTime from './total_time.vue';
|
|||
|
||||
const DEFAULT_WORKFLOW_TITLE_PROPERTIES = {
|
||||
thClass: 'gl-w-half',
|
||||
key: PAGINATION_SORT_FIELD_END_EVENT,
|
||||
key: FIELD_KEY_TITLE,
|
||||
sortable: false,
|
||||
};
|
||||
|
||||
const WORKFLOW_COLUMN_TITLES = {
|
||||
|
@ -132,14 +134,16 @@ export default {
|
|||
return [
|
||||
this.workflowTitle,
|
||||
{
|
||||
key: PAGINATION_SORT_FIELD_DURATION,
|
||||
label: __('Time'),
|
||||
thClass: 'gl-w-half',
|
||||
key: PAGINATION_SORT_FIELD_END_EVENT,
|
||||
label: __('Last event'),
|
||||
sortable: this.sortable,
|
||||
},
|
||||
].map((field) => ({
|
||||
...field,
|
||||
sortable: this.sortable,
|
||||
}));
|
||||
{
|
||||
key: PAGINATION_SORT_FIELD_DURATION,
|
||||
label: __('Duration'),
|
||||
sortable: this.sortable,
|
||||
},
|
||||
];
|
||||
},
|
||||
prevPage() {
|
||||
return Math.max(this.pagination.page - 1, 0);
|
||||
|
@ -201,7 +205,7 @@ export default {
|
|||
:empty-text="emptyStateMessage"
|
||||
@sort-changed="onSort"
|
||||
>
|
||||
<template v-if="stageCount" #head(end_event)="data">
|
||||
<template v-if="stageCount" #head(title)="data">
|
||||
<span>{{ data.label }}</span
|
||||
><gl-badge class="gl-ml-2" size="sm"
|
||||
><formatted-stage-count :stage-count="stageCount"
|
||||
|
@ -210,7 +214,10 @@ export default {
|
|||
<template #head(duration)="data">
|
||||
<span data-testid="vsa-stage-header-duration">{{ data.label }}</span>
|
||||
</template>
|
||||
<template #cell(end_event)="{ item }">
|
||||
<template #head(end_event)="data">
|
||||
<span data-testid="vsa-stage-header-last-event">{{ data.label }}</span>
|
||||
</template>
|
||||
<template #cell(title)="{ item }">
|
||||
<div data-testid="vsa-stage-event">
|
||||
<div v-if="item.id" data-testid="vsa-stage-content">
|
||||
<p class="gl-m-0">
|
||||
|
@ -282,6 +289,9 @@ export default {
|
|||
<template #cell(duration)="{ item }">
|
||||
<total-time :time="item.totalTime" data-testid="vsa-stage-event-time" />
|
||||
</template>
|
||||
<template #cell(end_event)="{ item }">
|
||||
<span data-testid="vsa-stage-last-event">{{ item.endEventTimestamp }}</span>
|
||||
</template>
|
||||
</gl-table>
|
||||
<gl-pagination
|
||||
v-if="pagination && !isLoading && !isEmptyStage"
|
||||
|
|
|
@ -22,6 +22,7 @@ export const PAGINATION_SORT_FIELD_END_EVENT = 'end_event';
|
|||
export const PAGINATION_SORT_FIELD_DURATION = 'duration';
|
||||
export const PAGINATION_SORT_DIRECTION_DESC = 'desc';
|
||||
export const PAGINATION_SORT_DIRECTION_ASC = 'asc';
|
||||
export const FIELD_KEY_TITLE = 'title';
|
||||
|
||||
export const I18N_VSA_ERROR_STAGES = __(
|
||||
'There was an error fetching value stream analytics stages.',
|
||||
|
|
|
@ -64,9 +64,10 @@ export default {
|
|||
v-if="isActive"
|
||||
name="arrow-right"
|
||||
class="icon-arrow-right gl-absolute gl-display-block"
|
||||
:size="14"
|
||||
/>
|
||||
|
||||
<ci-icon :status="job.status" />
|
||||
<ci-icon :status="job.status" class="gl-mr-2" :size="14" />
|
||||
|
||||
<span class="gl-text-truncate gl-w-full">{{ jobName }}</span>
|
||||
|
||||
|
|
|
@ -170,12 +170,6 @@
|
|||
width: 289px;
|
||||
overflow: auto;
|
||||
|
||||
svg {
|
||||
margin-right: 3px;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
a {
|
||||
padding: $gl-padding 10px $gl-padding 40px;
|
||||
width: 270px;
|
||||
|
|
|
@ -78,6 +78,7 @@ module ContainerRegistry
|
|||
return unless project
|
||||
return unless Feature.enabled?(:container_registry_project_statistics, project)
|
||||
|
||||
Rails.cache.delete(project.root_ancestor.container_repositories_size_cache_key)
|
||||
ProjectCacheWorker.perform_async(project.id, [], [:container_registry_size])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -863,6 +863,12 @@ class Group < Namespace
|
|||
end
|
||||
end
|
||||
|
||||
def gitlab_deploy_token
|
||||
strong_memoize(:gitlab_deploy_token) do
|
||||
deploy_tokens.gitlab_deploy_token
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def feature_flag_enabled_for_self_or_ancestor?(feature_flag)
|
||||
|
|
|
@ -427,14 +427,21 @@ class Namespace < ApplicationRecord
|
|||
aggregation_schedule.present?
|
||||
end
|
||||
|
||||
def container_repositories_size_cache_key
|
||||
"namespaces:#{id}:container_repositories_size"
|
||||
end
|
||||
|
||||
def container_repositories_size
|
||||
strong_memoize(:container_repositories_size) do
|
||||
next unless Gitlab.com?
|
||||
next unless root?
|
||||
next unless ContainerRegistry::GitlabApiClient.supports_gitlab_api?
|
||||
next 0 if all_container_repositories.empty?
|
||||
next unless all_container_repositories.all_migrated?
|
||||
|
||||
ContainerRegistry::GitlabApiClient.deduplicated_size(full_path)
|
||||
Rails.cache.fetch(container_repositories_size_cache_key, expires_in: 7.days) do
|
||||
ContainerRegistry::GitlabApiClient.deduplicated_size(full_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -81,7 +81,9 @@ class PoolRepository < ApplicationRecord
|
|||
object_pool.link(repository.raw)
|
||||
end
|
||||
|
||||
def mark_obsolete_if_last(repository)
|
||||
def unlink_repository(repository)
|
||||
repository.disconnect_alternates
|
||||
|
||||
if member_projects.where.not(id: repository.project.id).exists?
|
||||
true
|
||||
else
|
||||
|
|
|
@ -2509,7 +2509,13 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
def gitlab_deploy_token
|
||||
@gitlab_deploy_token ||= deploy_tokens.gitlab_deploy_token
|
||||
strong_memoize(:gitlab_deploy_token) do
|
||||
if Feature.enabled?(:ci_variable_for_group_gitlab_deploy_token, self)
|
||||
deploy_tokens.gitlab_deploy_token || group&.gitlab_deploy_token
|
||||
else
|
||||
deploy_tokens.gitlab_deploy_token
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def any_lfs_file_locks?
|
||||
|
@ -2566,7 +2572,7 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
def leave_pool_repository
|
||||
pool_repository&.mark_obsolete_if_last(repository) && update_column(:pool_repository_id, nil)
|
||||
pool_repository&.unlink_repository(repository) && update_column(:pool_repository_id, nil)
|
||||
end
|
||||
|
||||
def link_pool_repository
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: ci_variable_for_group_gitlab_deploy_token
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88696
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/363621
|
||||
milestone: '15.1'
|
||||
type: development
|
||||
group: group::pipeline authoring
|
||||
default_enabled: false
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddLicenseUsageDataExportedToApplicationSettings < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :application_settings, :license_usage_data_exported, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
55c13dd2cf8db2ca54d3fb1bd09d459e90a90e01b3c1f7ad950e4b618df241af
|
|
@ -11319,6 +11319,7 @@ CREATE TABLE application_settings (
|
|||
jira_connect_application_key text,
|
||||
globally_allowed_ips text DEFAULT ''::text NOT NULL,
|
||||
container_registry_pre_import_tags_rate numeric(6,2) DEFAULT 0.5 NOT NULL,
|
||||
license_usage_data_exported boolean DEFAULT false NOT NULL,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
|
||||
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
|
|
|
@ -898,6 +898,44 @@ def down
|
|||
end
|
||||
```
|
||||
|
||||
## Dropping a sequence
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88387) in GitLab 15.1.
|
||||
|
||||
Dropping a sequence is uncommon, but you can use the `drop_sequence` method provided by the database team.
|
||||
|
||||
Under the hood, it works like this:
|
||||
|
||||
Remove a sequence:
|
||||
|
||||
- Remove the default value if the sequence is actually used.
|
||||
- Execute `DROP SEQUENCE`.
|
||||
|
||||
Re-add a sequence:
|
||||
|
||||
- Create the sequence, with the possibility of specifying the current value.
|
||||
- Change the default value of the column.
|
||||
|
||||
A Rails migration example:
|
||||
|
||||
```ruby
|
||||
class DropSequenceTest < Gitlab::Database::Migration[2.0]
|
||||
def up
|
||||
drop_sequence(:ci_pipelines_config, :pipeline_id, :ci_pipelines_config_pipeline_id_seq)
|
||||
end
|
||||
|
||||
def down
|
||||
default_value = Ci::Pipeline.maximum(:id) + 10_000
|
||||
|
||||
add_sequence(:ci_pipelines_config, :pipeline_id, :ci_pipelines_config_pipeline_id_seq, default_value)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
NOTE:
|
||||
`add_sequence` should be avoided for columns with foreign keys.
|
||||
Adding sequence to these columns is **only allowed** in the down method (restore previous schema state).
|
||||
|
||||
## Integer column type
|
||||
|
||||
By default, an integer column can hold up to a 4-byte (32-bit) number. That is
|
||||
|
|
|
@ -43,8 +43,7 @@ To view value stream analytics for your project:
|
|||
- In the **From** field, select a start date.
|
||||
- In the **To** field, select an end date.
|
||||
1. Optional. Sort results by ascending or descending:
|
||||
- To sort by most recent or oldest workflow item, select the **Merge requests** or **Issues**
|
||||
header. The header name differs based on the stage you select.
|
||||
- To sort by most recent or oldest workflow item, select the **Last event** header.
|
||||
- To sort by most or least amount of time spent in each stage, select the **Time** header.
|
||||
|
||||
The table shows a list of related workflow items for the selected stage. Based on the stage you choose, this can be:
|
||||
|
|
|
@ -50,8 +50,7 @@ To view value stream analytics for your group:
|
|||
- In the **To** field, select an end date. The charts and list show workflow items created
|
||||
during the date range.
|
||||
1. Optional. Sort results by ascending or descending:
|
||||
- To sort by most recent or oldest workflow item, select the **Merge requests** or **Issues**
|
||||
header. The header name differs based on the stage you select.
|
||||
- To sort by most recent or oldest workflow item, select the **Last event** header.
|
||||
- To sort by most or least amount of time spent in each stage, select the **Time** header.
|
||||
|
||||
A badge next to the workflow items table header shows the number of workflow items that
|
||||
|
|
|
@ -190,6 +190,8 @@ To pull images from the Dependency Proxy, you must:
|
|||
|
||||
### GitLab deploy token
|
||||
|
||||
> Support for `gitlab-deploy-token` at the group level [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214014) in GitLab 15.1 [with a flag](../../../administration/feature_flags.md) named `ci_variable_for_group_gitlab_deploy_token`. Disabled by default.
|
||||
|
||||
There's a special case when it comes to deploy tokens. If a user creates one
|
||||
named `gitlab-deploy-token`, the username and token of the deploy token is
|
||||
automatically exposed to the CI/CD jobs as CI/CD variables: `CI_DEPLOY_USER`
|
||||
|
@ -203,9 +205,10 @@ docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
|
|||
```
|
||||
|
||||
NOTE:
|
||||
The special handling for the `gitlab-deploy-token` deploy token is not
|
||||
implemented for group deploy tokens. To make the group-level deploy token available for
|
||||
CI/CD jobs, the `CI_DEPLOY_USER` and `CI_DEPLOY_PASSWORD` variables should be set under **Settings** to the name and token of the group deploy token respectively.
|
||||
In GitLab 15.0 and earlier, the special handling for the `gitlab-deploy-token` deploy token
|
||||
does not work for group deploy tokens. To make the group-level deploy token available
|
||||
for CI/CD jobs, the `CI_DEPLOY_USER` and `CI_DEPLOY_PASSWORD` CI/CD variables must be
|
||||
set in **Settings > CI/CD > Variables** to the name and token of the group deploy token.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
@ -394,3 +394,27 @@ run tests:
|
|||
coverage_format: cobertura
|
||||
path: coverage/coverage.xml
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Test coverage visualization not displayed
|
||||
|
||||
If the test coverage visualization is not displayed in the diff view, you can check
|
||||
the coverage report itself and verify that:
|
||||
|
||||
- The file you are viewing in the diff view is mentioned in the coverage report.
|
||||
- The `source` and `filename` nodes in the report follows the [expected structure](#automatic-class-path-correction)
|
||||
to match the files in your repository.
|
||||
|
||||
Report artifacts are not downloadable by default. If you want the report to be downloadable
|
||||
from the job details page, add your coverage report to the artifact `paths`:
|
||||
|
||||
```yaml
|
||||
artifacts:
|
||||
paths:
|
||||
- coverage/cobertura-coverage.xml
|
||||
reports:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: coverage/cobertura-coverage.xml
|
||||
```
|
||||
|
|
|
@ -1499,6 +1499,20 @@ into similar problems in the future (e.g. when new tables are created).
|
|||
SQL
|
||||
end
|
||||
|
||||
def drop_sequence(table_name, column_name, sequence_name)
|
||||
execute <<~SQL
|
||||
ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} DROP DEFAULT;
|
||||
DROP SEQUENCE IF EXISTS #{quote_table_name(sequence_name)}
|
||||
SQL
|
||||
end
|
||||
|
||||
def add_sequence(table_name, column_name, sequence_name, start_value)
|
||||
execute <<~SQL
|
||||
CREATE SEQUENCE #{quote_table_name(sequence_name)} START #{start_value};
|
||||
ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT nextval(#{quote(sequence_name)})
|
||||
SQL
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_temporary_columns_and_triggers(table, columns, primary_key: :id, data_type: :bigint)
|
||||
|
|
|
@ -22362,6 +22362,9 @@ msgstr ""
|
|||
msgid "Last edited by %{link_start}%{avatar} %{name}%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last event"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last item before this page loaded in your browser:"
|
||||
msgstr ""
|
||||
|
||||
|
@ -33858,9 +33861,6 @@ msgstr ""
|
|||
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|Group level policy"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ const findTableHeadColumns = () => findTableHead().findAll('th');
|
|||
const findStageEventTitle = (ev) => extendedWrapper(ev).findByTestId('vsa-stage-event-title');
|
||||
const findStageEventLink = (ev) => extendedWrapper(ev).findByTestId('vsa-stage-event-link');
|
||||
const findStageTime = () => wrapper.findByTestId('vsa-stage-event-time');
|
||||
const findStageLastEvent = () => wrapper.findByTestId('vsa-stage-last-event');
|
||||
const findIcon = (name) => wrapper.findByTestId(`${name}-icon`);
|
||||
|
||||
function createComponent(props = {}, shallow = false) {
|
||||
|
@ -128,6 +129,10 @@ describe('StageTable', () => {
|
|||
expect(findStageTime().text()).toBe(createdAt);
|
||||
});
|
||||
|
||||
it('will render the end event', () => {
|
||||
expect(findStageLastEvent().text()).toBe(firstIssueEvent.endEventTimestamp);
|
||||
});
|
||||
|
||||
it('will render the author', () => {
|
||||
expect(wrapper.findByTestId('vsa-stage-event-author').text()).toContain(
|
||||
firstIssueEvent.author.name,
|
||||
|
@ -303,10 +308,20 @@ describe('StageTable', () => {
|
|||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('can sort the table by each column', () => {
|
||||
findTableHeadColumns().wrappers.forEach((w) => {
|
||||
expect(w.attributes('aria-sort')).toBe('none');
|
||||
});
|
||||
it('can sort the end event or duration', () => {
|
||||
findTableHeadColumns()
|
||||
.wrappers.slice(1)
|
||||
.forEach((w) => {
|
||||
expect(w.attributes('aria-sort')).toBe('none');
|
||||
});
|
||||
});
|
||||
|
||||
it('cannot be sorted by title', () => {
|
||||
findTableHeadColumns()
|
||||
.wrappers.slice(0, 1)
|
||||
.forEach((w) => {
|
||||
expect(w.attributes('aria-sort')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('clicking a table column will send tracking information', () => {
|
||||
|
|
|
@ -3281,4 +3281,20 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
|
|||
model.rename_constraint(:test_table, :fk_old_name, :fk_new_name)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#drop_sequence' do
|
||||
it "executes the statement to drop the sequence" do
|
||||
expect(model).to receive(:execute).with /ALTER TABLE "test_table" ALTER COLUMN "test_column" DROP DEFAULT;\nDROP SEQUENCE IF EXISTS "test_table_id_seq"/
|
||||
|
||||
model.drop_sequence(:test_table, :test_column, :test_table_id_seq)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#add_sequence' do
|
||||
it "executes the statement to add the sequence" do
|
||||
expect(model).to receive(:execute).with "CREATE SEQUENCE \"test_table_id_seq\" START 1;\nALTER TABLE \"test_table\" ALTER COLUMN \"test_column\" SET DEFAULT nextval(\'test_table_id_seq\')\n"
|
||||
|
||||
model.add_sequence(:test_table, :test_column, :test_table_id_seq, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3538,7 +3538,7 @@ RSpec.describe Ci::Build do
|
|||
]
|
||||
end
|
||||
|
||||
context 'when gitlab-deploy-token exists' do
|
||||
context 'when gitlab-deploy-token exists for project' do
|
||||
before do
|
||||
project.deploy_tokens << deploy_token
|
||||
end
|
||||
|
@ -3548,11 +3548,32 @@ RSpec.describe Ci::Build do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when gitlab-deploy-token does not exist' do
|
||||
context 'when gitlab-deploy-token does not exist for project' do
|
||||
it 'does not include deploy token variables' do
|
||||
expect(subject.find { |v| v[:key] == 'CI_DEPLOY_USER'}).to be_nil
|
||||
expect(subject.find { |v| v[:key] == 'CI_DEPLOY_PASSWORD'}).to be_nil
|
||||
end
|
||||
|
||||
context 'when gitlab-deploy-token exists for group' do
|
||||
before do
|
||||
group.deploy_tokens << deploy_token
|
||||
end
|
||||
|
||||
it 'includes deploy token variables' do
|
||||
is_expected.to include(*deploy_token_variables)
|
||||
end
|
||||
|
||||
context 'when the FF ci_variable_for_group_gitlab_deploy_token is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_variable_for_group_gitlab_deploy_token: false)
|
||||
end
|
||||
|
||||
it 'does not include deploy token variables' do
|
||||
expect(subject.find { |v| v[:key] == 'CI_DEPLOY_USER'}).to be_nil
|
||||
expect(subject.find { |v| v[:key] == 'CI_DEPLOY_PASSWORD'}).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -46,6 +46,12 @@ RSpec.describe ContainerRegistry::Event do
|
|||
handle!
|
||||
end
|
||||
|
||||
it 'clears the cache for the namespace container repositories size' do
|
||||
expect(Rails.cache).to receive(:delete).with(group.container_repositories_size_cache_key)
|
||||
|
||||
handle!
|
||||
end
|
||||
|
||||
shared_examples 'event without project statistics update' do
|
||||
it 'does not queue a project statistics update' do
|
||||
expect(ProjectCacheWorker).not_to receive(:perform_async)
|
||||
|
|
|
@ -3396,4 +3396,42 @@ RSpec.describe Group do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#gitlab_deploy_token' do
|
||||
subject(:gitlab_deploy_token) { group.gitlab_deploy_token }
|
||||
|
||||
context 'when there is a gitlab deploy token associated' do
|
||||
let!(:deploy_token) { create(:deploy_token, :group, :gitlab_deploy_token, groups: [group]) }
|
||||
|
||||
it { is_expected.to eq(deploy_token) }
|
||||
end
|
||||
|
||||
context 'when there is no a gitlab deploy token associated' do
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'when there is a gitlab deploy token associated but is has been revoked' do
|
||||
let!(:deploy_token) { create(:deploy_token, :group, :gitlab_deploy_token, :revoked, groups: [group]) }
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'when there is a gitlab deploy token associated but it is expired' do
|
||||
let!(:deploy_token) { create(:deploy_token, :group, :gitlab_deploy_token, :expired, groups: [group]) }
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'when there is a deploy token associated with a different name' do
|
||||
let!(:deploy_token) { create(:deploy_token, :group, groups: [group]) }
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'when there is a gitlab deploy token associated to a different group' do
|
||||
let!(:deploy_token) { create(:deploy_token, :group, :gitlab_deploy_token, groups: [create(:group)]) }
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -583,7 +583,13 @@ RSpec.describe Namespace do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#container_repositories_size' do
|
||||
describe '#container_repositories_size_cache_key' do
|
||||
it 'returns the correct cache key' do
|
||||
expect(namespace.container_repositories_size_cache_key).to eq "namespaces:#{namespace.id}:container_repositories_size"
|
||||
end
|
||||
end
|
||||
|
||||
describe '#container_repositories_size', :clean_gitlab_redis_cache do
|
||||
let(:project_namespace) { create(:namespace) }
|
||||
|
||||
subject { project_namespace.container_repositories_size }
|
||||
|
@ -611,12 +617,29 @@ RSpec.describe Namespace do
|
|||
end
|
||||
|
||||
it { is_expected.to eq(expected_result) }
|
||||
|
||||
it 'caches the result when all migrated' do
|
||||
if all_migrated
|
||||
expect(Rails.cache)
|
||||
.to receive(:fetch)
|
||||
.with(project_namespace.container_repositories_size_cache_key, expires_in: 7.days)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'not on gitlab.com' do
|
||||
it { is_expected.to eq(nil) }
|
||||
end
|
||||
|
||||
context 'for a sub-group' do
|
||||
let(:parent_namespace) { create(:group) }
|
||||
let(:project_namespace) { create(:group, parent: parent_namespace) }
|
||||
|
||||
it { is_expected.to eq(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#all_container_repositories' do
|
||||
|
|
|
@ -24,23 +24,35 @@ RSpec.describe PoolRepository do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#mark_obsolete_if_last' do
|
||||
describe '#unlink_repository' do
|
||||
let(:pool) { create(:pool_repository, :ready) }
|
||||
let(:repository_path) { File.join(TestEnv.repos_path, pool.source_project.repository.relative_path) }
|
||||
let(:alternates_file) { File.join(repository_path, 'objects', 'info', 'alternates') }
|
||||
|
||||
before do
|
||||
pool.link_repository(pool.source_project.repository)
|
||||
end
|
||||
|
||||
context 'when the last member leaves' do
|
||||
it 'schedules pool removal' do
|
||||
expect(::ObjectPool::DestroyWorker).to receive(:perform_async).with(pool.id).and_call_original
|
||||
|
||||
pool.mark_obsolete_if_last(pool.source_project.repository)
|
||||
pool.unlink_repository(pool.source_project.repository)
|
||||
|
||||
expect(File).not_to exist(alternates_file)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the second member leaves' do
|
||||
it 'does not schedule pool removal' do
|
||||
create(:project, :repository, pool_repository: pool)
|
||||
other_project = create(:project, :repository, pool_repository: pool)
|
||||
pool.link_repository(other_project.repository)
|
||||
|
||||
expect(::ObjectPool::DestroyWorker).not_to receive(:perform_async).with(pool.id)
|
||||
|
||||
pool.mark_obsolete_if_last(pool.source_project.repository)
|
||||
pool.unlink_repository(pool.source_project.repository)
|
||||
|
||||
expect(File).not_to exist(alternates_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6220,7 +6220,7 @@ RSpec.describe Project, factory_default: :keep do
|
|||
describe '#gitlab_deploy_token' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
subject { project.gitlab_deploy_token }
|
||||
subject(:gitlab_deploy_token) { project.gitlab_deploy_token }
|
||||
|
||||
context 'when there is a gitlab deploy token associated' do
|
||||
let!(:deploy_token) { create(:deploy_token, :gitlab_deploy_token, projects: [project]) }
|
||||
|
@ -6252,10 +6252,43 @@ RSpec.describe Project, factory_default: :keep do
|
|||
|
||||
context 'when there is a deploy token associated to a different project' do
|
||||
let(:project_2) { create(:project) }
|
||||
let!(:deploy_token) { create(:deploy_token, projects: [project_2]) }
|
||||
let!(:deploy_token) { create(:deploy_token, :gitlab_deploy_token, projects: [project_2]) }
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'when the project group has a gitlab deploy token associated' do
|
||||
let(:group) { create(:group) }
|
||||
let(:project) { create(:project, group: group) }
|
||||
let!(:deploy_token) { create(:deploy_token, :gitlab_deploy_token, :group, groups: [group]) }
|
||||
|
||||
it { is_expected.to eq(deploy_token) }
|
||||
|
||||
context 'when the FF ci_variable_for_group_gitlab_deploy_token is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_variable_for_group_gitlab_deploy_token: false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the project and its group has a gitlab deploy token associated' do
|
||||
let(:group) { create(:group) }
|
||||
let(:project) { create(:project, group: group) }
|
||||
let!(:project_deploy_token) { create(:deploy_token, :gitlab_deploy_token, projects: [project]) }
|
||||
let!(:group_deploy_token) { create(:deploy_token, :gitlab_deploy_token, :group, groups: [group]) }
|
||||
|
||||
it { is_expected.to eq(project_deploy_token) }
|
||||
|
||||
context 'when the FF ci_variable_for_group_gitlab_deploy_token is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_variable_for_group_gitlab_deploy_token: false)
|
||||
end
|
||||
|
||||
it { is_expected.to eq(project_deploy_token) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with uploads' do
|
||||
|
|
|
@ -14,20 +14,7 @@ RSpec.describe Projects::EnvironmentsController do
|
|||
sign_in(project.owner)
|
||||
end
|
||||
|
||||
it 'avoids N+1 queries', :use_sql_query_cache do
|
||||
create_deployment_with_associations(commit_depth: 19)
|
||||
|
||||
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
|
||||
get project_environment_path(project, environment), params: environment_params
|
||||
end
|
||||
|
||||
18.downto(0).each { |n| create_deployment_with_associations(commit_depth: n) }
|
||||
|
||||
# N+1s exist for loading commit emails and users
|
||||
expect do
|
||||
get project_environment_path(project, environment), params: environment_params
|
||||
end.not_to exceed_all_query_limit(control).with_threshold(9)
|
||||
end
|
||||
include_examples 'avoids N+1 queries on environment detail page'
|
||||
end
|
||||
|
||||
def environment_params(opts = {})
|
||||
|
|
|
@ -65,20 +65,3 @@ RSpec.shared_examples 'failed response for #cancel_auto_stop' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'avoids N+1 queries on environment detail page' do
|
||||
render_views
|
||||
|
||||
before do
|
||||
create_deployment_with_associations(sequence: 0)
|
||||
end
|
||||
|
||||
it 'avoids N+1 queries' do
|
||||
control = ActiveRecord::QueryRecorder.new { get :show, params: environment_params }
|
||||
|
||||
create_deployment_with_associations(sequence: 1)
|
||||
create_deployment_with_associations(sequence: 2)
|
||||
|
||||
expect { get :show, params: environment_params }.not_to exceed_query_limit(control.count).with_threshold(34)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'avoids N+1 queries on environment detail page' do
|
||||
it 'avoids N+1 queries', :use_sql_query_cache do
|
||||
create_deployment_with_associations(commit_depth: 19)
|
||||
|
||||
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
|
||||
get project_environment_path(project, environment), params: environment_params
|
||||
end
|
||||
|
||||
18.downto(0).each { |n| create_deployment_with_associations(commit_depth: n) }
|
||||
|
||||
# N+1s exist for loading commit emails and users
|
||||
expect do
|
||||
get project_environment_path(project, environment), params: environment_params
|
||||
end.not_to exceed_all_query_limit(control).with_threshold(9)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue