Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-10-07 03:08:19 +00:00
parent 967b999f2e
commit 3c33a3d566
17 changed files with 104 additions and 67 deletions

View File

@ -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

View File

@ -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">

View File

@ -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)

View File

@ -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?

View File

@ -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),

View File

@ -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]

View File

@ -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

View File

@ -1,7 +0,0 @@
---
name: container_registry_cleanup
introduced_by_url:
rollout_issue_url:
group:
type: development
default_enabled: true

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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: {

View File

@ -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

View File

@ -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)

View File

@ -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(