Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
967b999f2e
commit
3c33a3d566
|
@ -6,7 +6,6 @@ import MarkdownField from '~/vue_shared/components/markdown/field.vue';
|
||||||
import { BACK_URL_PARAM } from '~/releases/constants';
|
import { BACK_URL_PARAM } from '~/releases/constants';
|
||||||
import { getParameterByName } from '~/lib/utils/common_utils';
|
import { getParameterByName } from '~/lib/utils/common_utils';
|
||||||
import AssetLinksForm from './asset_links_form.vue';
|
import AssetLinksForm from './asset_links_form.vue';
|
||||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
|
||||||
import MilestoneCombobox from '~/milestones/project_milestone_combobox.vue';
|
import MilestoneCombobox from '~/milestones/project_milestone_combobox.vue';
|
||||||
import TagField from './tag_field.vue';
|
import TagField from './tag_field.vue';
|
||||||
|
|
||||||
|
@ -22,7 +21,6 @@ export default {
|
||||||
MilestoneCombobox,
|
MilestoneCombobox,
|
||||||
TagField,
|
TagField,
|
||||||
},
|
},
|
||||||
mixins: [glFeatureFlagsMixin()],
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState('detail', [
|
...mapState('detail', [
|
||||||
'isFetchingRelease',
|
'isFetchingRelease',
|
||||||
|
@ -68,9 +66,6 @@ export default {
|
||||||
cancelPath() {
|
cancelPath() {
|
||||||
return getParameterByName(BACK_URL_PARAM) || this.releasesPagePath;
|
return getParameterByName(BACK_URL_PARAM) || this.releasesPagePath;
|
||||||
},
|
},
|
||||||
showAssetLinksForm() {
|
|
||||||
return this.glFeatures.releaseAssetLinkEditing;
|
|
||||||
},
|
|
||||||
saveButtonLabel() {
|
saveButtonLabel() {
|
||||||
return this.isExistingRelease ? __('Save changes') : __('Create release');
|
return this.isExistingRelease ? __('Save changes') : __('Create release');
|
||||||
},
|
},
|
||||||
|
@ -176,7 +171,7 @@ export default {
|
||||||
</div>
|
</div>
|
||||||
</gl-form-group>
|
</gl-form-group>
|
||||||
|
|
||||||
<asset-links-form v-if="showAssetLinksForm" />
|
<asset-links-form />
|
||||||
|
|
||||||
<div class="d-flex pt-3">
|
<div class="d-flex pt-3">
|
||||||
<gl-button
|
<gl-button
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { GlButton } from '@gitlab/ui';
|
||||||
import statusIcon from '../mr_widget_status_icon.vue';
|
import statusIcon from '../mr_widget_status_icon.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MRWidgetArchived',
|
name: 'MRWidgetArchived',
|
||||||
components: {
|
components: {
|
||||||
|
GlButton,
|
||||||
statusIcon,
|
statusIcon,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -12,9 +14,9 @@ export default {
|
||||||
<div class="mr-widget-body media">
|
<div class="mr-widget-body media">
|
||||||
<div class="space-children">
|
<div class="space-children">
|
||||||
<status-icon status="warning" />
|
<status-icon status="warning" />
|
||||||
<button type="button" class="btn btn-success btn-sm" disabled="true">
|
<gl-button category="secondary" variant="success" :disabled="true">
|
||||||
{{ s__('mrWidget|Merge') }}
|
{{ s__('mrWidget|Merge') }}
|
||||||
</button>
|
</gl-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<span class="bold">
|
<span class="bold">
|
||||||
|
|
|
@ -7,7 +7,6 @@ class Projects::ReleasesController < Projects::ApplicationController
|
||||||
before_action :authorize_read_release!
|
before_action :authorize_read_release!
|
||||||
before_action do
|
before_action do
|
||||||
push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true)
|
push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true)
|
||||||
push_frontend_feature_flag(:release_asset_link_editing, project, default_enabled: true)
|
|
||||||
push_frontend_feature_flag(:graphql_release_data, project, default_enabled: true)
|
push_frontend_feature_flag(:graphql_release_data, project, default_enabled: true)
|
||||||
push_frontend_feature_flag(:graphql_milestone_stats, project, default_enabled: true)
|
push_frontend_feature_flag(:graphql_milestone_stats, project, default_enabled: true)
|
||||||
push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: true)
|
push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: true)
|
||||||
|
|
|
@ -78,6 +78,20 @@ class DeployToken < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def group
|
||||||
|
strong_memoize(:group) do
|
||||||
|
groups.first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def accessible_projects
|
||||||
|
if project_type?
|
||||||
|
projects
|
||||||
|
elsif group_type?
|
||||||
|
group.all_projects
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def holder
|
def holder
|
||||||
strong_memoize(:holder) do
|
strong_memoize(:holder) do
|
||||||
if project_type?
|
if project_type?
|
||||||
|
|
|
@ -604,7 +604,7 @@ class Project < ApplicationRecord
|
||||||
return public_to_user unless user
|
return public_to_user unless user
|
||||||
|
|
||||||
if user.is_a?(DeployToken)
|
if user.is_a?(DeployToken)
|
||||||
user.projects
|
user.accessible_projects
|
||||||
else
|
else
|
||||||
where('EXISTS (?) OR projects.visibility_level IN (?)',
|
where('EXISTS (?) OR projects.visibility_level IN (?)',
|
||||||
user.authorizations_for_projects(min_access_level: min_access_level),
|
user.authorizations_for_projects(min_access_level: min_access_level),
|
||||||
|
|
|
@ -4,7 +4,6 @@ module Projects
|
||||||
module ContainerRepository
|
module ContainerRepository
|
||||||
class CleanupTagsService < BaseService
|
class CleanupTagsService < BaseService
|
||||||
def execute(container_repository)
|
def execute(container_repository)
|
||||||
return error('feature disabled') unless can_use?
|
|
||||||
return error('access denied') unless can_destroy?
|
return error('access denied') unless can_destroy?
|
||||||
return error('invalid regex') unless valid_regex?
|
return error('invalid regex') unless valid_regex?
|
||||||
|
|
||||||
|
@ -74,10 +73,6 @@ module Projects
|
||||||
can?(current_user, :destroy_container_image, project)
|
can?(current_user, :destroy_container_image, project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_use?
|
|
||||||
Feature.enabled?(:container_registry_cleanup, project, default_enabled: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
def valid_regex?
|
def valid_regex?
|
||||||
%w(name_regex_delete name_regex name_regex_keep).each do |param_name|
|
%w(name_regex_delete name_regex name_regex_keep).each do |param_name|
|
||||||
regex = params[param_name]
|
regex = params[param_name]
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
title: Fix group deploy tokens to return all projects and work with the Maven group
|
||||||
|
endpoint
|
||||||
|
merge_request: 43628
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -1,7 +0,0 @@
|
||||||
---
|
|
||||||
name: container_registry_cleanup
|
|
||||||
introduced_by_url:
|
|
||||||
rollout_issue_url:
|
|
||||||
group:
|
|
||||||
type: development
|
|
||||||
default_enabled: true
|
|
|
@ -1,7 +0,0 @@
|
||||||
---
|
|
||||||
name: epics_search
|
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42456
|
|
||||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/250317
|
|
||||||
group: group::global search
|
|
||||||
type: development
|
|
||||||
default_enabled: false
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: json_limited_encoder
|
name: json_limited_encoder
|
||||||
introduced_by_url:
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38687
|
||||||
rollout_issue_url:
|
rollout_issue_url:
|
||||||
group:
|
group: group::source code
|
||||||
type: development
|
type: development
|
||||||
default_enabled: false
|
default_enabled: false
|
||||||
|
|
|
@ -184,6 +184,16 @@ The message `Successfully connected` indicates a successful TLS handshake.
|
||||||
If there are problems, the Java TLS library generates errors that you can
|
If there are problems, the Java TLS library generates errors that you can
|
||||||
look up for more detail.
|
look up for more detail.
|
||||||
|
|
||||||
|
##### Scope error when connecting Jira via DVCS
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
The requested scope is invalid, unknown, or malformed.
|
||||||
|
```
|
||||||
|
|
||||||
|
Potential resolutions:
|
||||||
|
|
||||||
|
- Verify the URL includes `scope=api` on the end of the URL.
|
||||||
|
|
||||||
##### Jira error adding account and no repositories listed
|
##### Jira error adding account and no repositories listed
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
|
|
|
@ -38,7 +38,7 @@ To run Secret Detection jobs, by default, you need GitLab Runner with the
|
||||||
If you're using the shared runners on GitLab.com, this is enabled by default.
|
If you're using the shared runners on GitLab.com, this is enabled by default.
|
||||||
|
|
||||||
CAUTION: **Caution:**
|
CAUTION: **Caution:**
|
||||||
Our Secret Detection jobs currently expect a Linux container type. Windows containers are not yet supported.
|
Our Secret Detection jobs expect a Linux container type. Windows containers are not supported.
|
||||||
|
|
||||||
CAUTION: **Caution:**
|
CAUTION: **Caution:**
|
||||||
If you use your own runners, make sure the Docker version installed
|
If you use your own runners, make sure the Docker version installed
|
||||||
|
@ -139,7 +139,7 @@ Secret Detection can be customized by defining available variables:
|
||||||
|-------------------------|---------------|-------------|
|
|-------------------------|---------------|-------------|
|
||||||
| `SECRET_DETECTION_COMMIT_FROM` | - | The commit a Gitleaks scan starts at. |
|
| `SECRET_DETECTION_COMMIT_FROM` | - | The commit a Gitleaks scan starts at. |
|
||||||
| `SECRET_DETECTION_COMMIT_TO` | - | The commit a Gitleaks scan ends at. |
|
| `SECRET_DETECTION_COMMIT_TO` | - | The commit a Gitleaks scan ends at. |
|
||||||
| `SECRET_DETECTION_EXCLUDED_PATHS` | "" | Exclude vulnerabilities from output based on the paths. This is a comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec` ). Parent directories will also match patterns. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225273) in GitLab 13.3. |
|
| `SECRET_DETECTION_EXCLUDED_PATHS` | "" | Exclude vulnerabilities from output based on the paths. This is a comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec` ). Parent directories also match patterns. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225273) in GitLab 13.3. |
|
||||||
| `SECRET_DETECTION_HISTORIC_SCAN` | false | Flag to enable a historic Gitleaks scan. |
|
| `SECRET_DETECTION_HISTORIC_SCAN` | false | Flag to enable a historic Gitleaks scan. |
|
||||||
|
|
||||||
### Logging level
|
### Logging level
|
||||||
|
|
|
@ -223,6 +223,7 @@ backed by the database and allows searching in:
|
||||||
- Merge requests
|
- Merge requests
|
||||||
- Milestones
|
- Milestones
|
||||||
- Users
|
- Users
|
||||||
|
- Epics (Group only)
|
||||||
- Code (Project only)
|
- Code (Project only)
|
||||||
- Comments (Project only)
|
- Comments (Project only)
|
||||||
- Commits (Project only)
|
- Commits (Project only)
|
||||||
|
|
|
@ -20,7 +20,7 @@ describe('Release edit/new component', () => {
|
||||||
let state;
|
let state;
|
||||||
let mock;
|
let mock;
|
||||||
|
|
||||||
const factory = ({ featureFlags = {}, store: storeUpdates = {} } = {}) => {
|
const factory = async ({ featureFlags = {}, store: storeUpdates = {} } = {}) => {
|
||||||
state = {
|
state = {
|
||||||
release,
|
release,
|
||||||
markdownDocsPath: 'path/to/markdown/docs',
|
markdownDocsPath: 'path/to/markdown/docs',
|
||||||
|
@ -68,6 +68,8 @@ describe('Release edit/new component', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
wrapper.element.querySelectorAll('input').forEach(input => jest.spyOn(input, 'focus'));
|
wrapper.element.querySelectorAll('input').forEach(input => jest.spyOn(input, 'focus'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,7 +91,9 @@ describe('Release edit/new component', () => {
|
||||||
const findForm = () => wrapper.find('form');
|
const findForm = () => wrapper.find('form');
|
||||||
|
|
||||||
describe(`basic functionality tests: all tests unrelated to the "${BACK_URL_PARAM}" parameter`, () => {
|
describe(`basic functionality tests: all tests unrelated to the "${BACK_URL_PARAM}" parameter`, () => {
|
||||||
beforeEach(factory);
|
beforeEach(async () => {
|
||||||
|
await factory();
|
||||||
|
});
|
||||||
|
|
||||||
it('calls initializeRelease when the component is created', () => {
|
it('calls initializeRelease when the component is created', () => {
|
||||||
expect(actions.initializeRelease).toHaveBeenCalledTimes(1);
|
expect(actions.initializeRelease).toHaveBeenCalledTimes(1);
|
||||||
|
@ -131,7 +135,9 @@ describe('Release edit/new component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(`when the URL does not contain a "${BACK_URL_PARAM}" parameter`, () => {
|
describe(`when the URL does not contain a "${BACK_URL_PARAM}" parameter`, () => {
|
||||||
beforeEach(factory);
|
beforeEach(async () => {
|
||||||
|
await factory();
|
||||||
|
});
|
||||||
|
|
||||||
it(`renders a "Cancel" button with an href pointing to "${BACK_URL_PARAM}"`, () => {
|
it(`renders a "Cancel" button with an href pointing to "${BACK_URL_PARAM}"`, () => {
|
||||||
const cancelButton = wrapper.find('.js-cancel-button');
|
const cancelButton = wrapper.find('.js-cancel-button');
|
||||||
|
@ -142,12 +148,12 @@ describe('Release edit/new component', () => {
|
||||||
describe(`when the URL contains a "${BACK_URL_PARAM}" parameter`, () => {
|
describe(`when the URL contains a "${BACK_URL_PARAM}" parameter`, () => {
|
||||||
const backUrl = 'https://example.gitlab.com/back/url';
|
const backUrl = 'https://example.gitlab.com/back/url';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
commonUtils.getParameterByName = jest
|
commonUtils.getParameterByName = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(paramToGet => ({ [BACK_URL_PARAM]: backUrl }[paramToGet]));
|
.mockImplementation(paramToGet => ({ [BACK_URL_PARAM]: backUrl }[paramToGet]));
|
||||||
|
|
||||||
factory();
|
await factory();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a "Cancel" button with an href pointing to the main Releases page', () => {
|
it('renders a "Cancel" button with an href pointing to the main Releases page', () => {
|
||||||
|
@ -157,8 +163,8 @@ describe('Release edit/new component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when creating a new release', () => {
|
describe('when creating a new release', () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
factory({
|
await factory({
|
||||||
store: {
|
store: {
|
||||||
modules: {
|
modules: {
|
||||||
detail: {
|
detail: {
|
||||||
|
@ -177,7 +183,9 @@ describe('Release edit/new component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when editing an existing release', () => {
|
describe('when editing an existing release', () => {
|
||||||
beforeEach(factory);
|
beforeEach(async () => {
|
||||||
|
await factory();
|
||||||
|
});
|
||||||
|
|
||||||
it('renders the submit button with the text "Save changes"', () => {
|
it('renders the submit button with the text "Save changes"', () => {
|
||||||
expect(findSubmitButton().text()).toBe('Save changes');
|
expect(findSubmitButton().text()).toBe('Save changes');
|
||||||
|
@ -185,33 +193,17 @@ describe('Release edit/new component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('asset links form', () => {
|
describe('asset links form', () => {
|
||||||
const findAssetLinksForm = () => wrapper.find(AssetLinksForm);
|
beforeEach(factory);
|
||||||
|
|
||||||
describe('when the release_asset_link_editing feature flag is disabled', () => {
|
it('renders the asset links portion of the form', () => {
|
||||||
beforeEach(() => {
|
expect(wrapper.find(AssetLinksForm).exists()).toBe(true);
|
||||||
factory({ featureFlags: { releaseAssetLinkEditing: false } });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not render the asset links portion of the form', () => {
|
|
||||||
expect(findAssetLinksForm().exists()).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when the release_asset_link_editing feature flag is enabled', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
factory({ featureFlags: { releaseAssetLinkEditing: true } });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders the asset links portion of the form', () => {
|
|
||||||
expect(findAssetLinksForm().exists()).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('validation', () => {
|
describe('validation', () => {
|
||||||
describe('when the form is valid', () => {
|
describe('when the form is valid', () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
factory({
|
await factory({
|
||||||
store: {
|
store: {
|
||||||
modules: {
|
modules: {
|
||||||
detail: {
|
detail: {
|
||||||
|
@ -230,8 +222,8 @@ describe('Release edit/new component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when the form is invalid', () => {
|
describe('when the form is invalid', () => {
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
factory({
|
await factory({
|
||||||
store: {
|
store: {
|
||||||
modules: {
|
modules: {
|
||||||
detail: {
|
detail: {
|
||||||
|
|
|
@ -353,4 +353,29 @@ RSpec.describe DeployToken do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#accessible_projects' do
|
||||||
|
subject { deploy_token.accessible_projects }
|
||||||
|
|
||||||
|
context 'when a deploy token is associated to a project' do
|
||||||
|
let_it_be(:deploy_token) { create(:deploy_token, :project) }
|
||||||
|
|
||||||
|
it 'returns only projects directly associated with the token' do
|
||||||
|
expect(deploy_token).to receive(:projects)
|
||||||
|
|
||||||
|
subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a deploy token is associated to a group' do
|
||||||
|
let_it_be(:group) { create(:group) }
|
||||||
|
let_it_be(:deploy_token) { create(:deploy_token, :group, groups: [group]) }
|
||||||
|
|
||||||
|
it 'returns all projects from the group' do
|
||||||
|
expect(group).to receive(:all_projects)
|
||||||
|
|
||||||
|
subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,10 +15,13 @@ RSpec.describe API::MavenPackages do
|
||||||
let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) }
|
let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) }
|
||||||
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
|
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
|
||||||
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
|
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
|
||||||
|
let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
|
||||||
|
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token_for_group, group: group) }
|
||||||
|
|
||||||
let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') }
|
let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') }
|
||||||
let(:headers) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } }
|
let(:headers) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } }
|
||||||
let(:headers_with_token) { headers.merge('Private-Token' => personal_access_token.token) }
|
let(:headers_with_token) { headers.merge('Private-Token' => personal_access_token.token) }
|
||||||
|
let(:group_deploy_token_headers) { { Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => deploy_token_for_group.token } }
|
||||||
|
|
||||||
let(:headers_with_deploy_token) do
|
let(:headers_with_deploy_token) do
|
||||||
headers.merge(
|
headers.merge(
|
||||||
|
@ -342,6 +345,17 @@ RSpec.describe API::MavenPackages do
|
||||||
it_behaves_like 'downloads with a job token'
|
it_behaves_like 'downloads with a job token'
|
||||||
|
|
||||||
it_behaves_like 'downloads with a deploy token'
|
it_behaves_like 'downloads with a deploy token'
|
||||||
|
|
||||||
|
context 'with group deploy token' do
|
||||||
|
subject { download_file_with_token(package_file.file_name, {}, group_deploy_token_headers) }
|
||||||
|
|
||||||
|
it 'returns the file' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
expect(response.media_type).to eq('application/octet-stream')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def download_file(file_name, params = {}, request_headers = headers)
|
def download_file(file_name, params = {}, request_headers = headers)
|
||||||
|
|
|
@ -12,8 +12,6 @@ RSpec.describe Projects::ContainerRepository::CleanupTagsService do
|
||||||
before do
|
before do
|
||||||
project.add_maintainer(user)
|
project.add_maintainer(user)
|
||||||
|
|
||||||
stub_feature_flags(container_registry_cleanup: true)
|
|
||||||
|
|
||||||
stub_container_registry_config(enabled: true)
|
stub_container_registry_config(enabled: true)
|
||||||
|
|
||||||
stub_container_registry_tags(
|
stub_container_registry_tags(
|
||||||
|
|
Loading…
Reference in New Issue