Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-03-29 18:08:06 +00:00
parent 9c28b22cfc
commit 2194dac753
24 changed files with 37 additions and 505 deletions

View File

@ -1,47 +0,0 @@
<script>
import Identicon from '../identicon.vue';
import ProjectAvatarImage from './image.vue';
export default {
name: 'DeprecatedProjectAvatar',
components: {
Identicon,
ProjectAvatarImage,
},
props: {
project: {
type: Object,
required: true,
},
size: {
type: Number,
default: 40,
required: false,
},
},
computed: {
sizeClass() {
return `s${this.size}`;
},
},
};
</script>
<template>
<span :class="sizeClass" class="avatar-container rect-avatar project-avatar">
<project-avatar-image
v-if="project.avatar_url"
:link-href="project.path"
:img-src="project.avatar_url"
:img-alt="project.name"
:img-size="size"
/>
<identicon
v-else
:entity-id="project.id"
:entity-name="project.name"
:size-class="sizeClass"
class="rect-avatar"
/>
</span>
</template>

View File

@ -1,81 +0,0 @@
<script>
/* This is a re-usable vue component for rendering a project avatar that
does not need to link to the project's profile. The image and an optional
tooltip can be configured by props passed to this component.
Sample configuration:
<project-avatar-image
:lazy="true"
:img-src="projectAvatarSrc"
:img-alt="tooltipText"
:tooltip-text="tooltipText"
tooltip-placement="top"
/>
*/
import defaultAvatarUrl from 'images/no_avatar.png';
import { __ } from '~/locale';
import { placeholderImage } from '../../../lazy_loader';
export default {
name: 'ProjectAvatarImage',
props: {
lazy: {
type: Boolean,
required: false,
default: false,
},
imgSrc: {
type: String,
required: false,
default: defaultAvatarUrl,
},
cssClasses: {
type: String,
required: false,
default: '',
},
imgAlt: {
type: String,
required: false,
default: __('project avatar'),
},
size: {
type: Number,
required: false,
default: 20,
},
},
computed: {
// API response sends null when gravatar is disabled and
// we provide an empty string when we use it inside project avatar link.
// In both cases we should render the defaultAvatarUrl
sanitizedSource() {
return this.imgSrc === '' || this.imgSrc === null ? defaultAvatarUrl : this.imgSrc;
},
resultantSrcAttribute() {
return this.lazy ? placeholderImage : this.sanitizedSource;
},
avatarSizeClass() {
return `s${this.size}`;
},
},
};
</script>
<template>
<img
:class="{
lazy: lazy,
[avatarSizeClass]: true,
[cssClasses]: true,
}"
:src="resultantSrcAttribute"
:width="size"
:height="size"
:alt="imgAlt"
:data-src="sanitizedSource"
class="avatar"
/>
</template>

View File

@ -1,35 +0,0 @@
<script>
import { getIdenticonBackgroundClass, getIdenticonTitle } from '~/helpers/avatar_helper';
export default {
props: {
entityId: {
type: [Number, String],
required: true,
},
entityName: {
type: String,
required: true,
},
sizeClass: {
type: String,
required: false,
default: 's40',
},
},
computed: {
identiconBackgroundClass() {
return getIdenticonBackgroundClass(this.entityId);
},
identiconTitle() {
return getIdenticonTitle(this.entityName);
},
},
};
</script>
<template>
<div ref="identicon" :class="[sizeClass, identiconBackgroundClass]" class="avatar identicon">
{{ identiconTitle }}
</div>
</template>

View File

@ -3,7 +3,7 @@ import { GlButton, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import { isString } from 'lodash';
import highlight from '~/lib/utils/highlight';
import { truncateNamespace } from '~/lib/utils/text_utility';
import ProjectAvatar from '~/vue_shared/components/deprecated_project_avatar/default.vue';
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
export default {
name: 'ProjectListItem',
@ -22,6 +22,9 @@ export default {
matcher: { type: String, required: false, default: '' },
},
computed: {
projectAvatarUrl() {
return this.project.avatar_url || this.project.avatarUrl;
},
projectNameWithNamespace() {
return this.project.nameWithNamespace || this.project.name_with_namespace;
},
@ -49,7 +52,11 @@ export default {
class="gl-display-flex gl-align-items-center gl-flex-wrap project-namespace-name-container"
>
<gl-icon v-if="selected" class="js-selected-icon" name="mobile-issue-close" />
<project-avatar class="gl-flex-shrink-0 js-project-avatar" :project="project" :size="32" />
<project-avatar
:project-avatar-url="projectAvatarUrl"
:project-name="projectNameWithNamespace"
class="gl-mr-3"
/>
<div
v-if="truncatedNamespace"
:title="projectNameWithNamespace"

View File

@ -3,6 +3,7 @@
class Projects::StaticSiteEditorController < Projects::ApplicationController
include ExtractsPath
include CreatesCommit
include BlobHelper
layout 'fullscreen'
@ -24,28 +25,7 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
end
def show
service_response = ::StaticSiteEditor::ConfigService.new(
container: project,
current_user: current_user,
params: {
ref: @ref,
path: @path,
return_url: params[:return_url]
}
).execute
if service_response.success?
Gitlab::UsageDataCounters::StaticSiteEditorCounter.increment_views_count
@data = serialize_necessary_payload_values_to_json(service_response.payload)
else
# TODO: For now, if the service returns any error, the user is redirected
# to the root project page with the error message displayed as an alert.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/213285#note_414808004
# for discussion of plans to handle this via a page owned by the Static Site Editor.
flash[:alert] = service_response.message
redirect_to project_path(project)
end
redirect_to ide_edit_path(project, @ref, @path)
end
private

View File

@ -576,7 +576,6 @@ severities
sharded
sharding
shfmt
Shibboleth
Shimo
Shopify
Sidekiq

View File

@ -31,7 +31,6 @@ providers:
- [Salesforce](../../integration/salesforce.md)
- [SAML](../../integration/saml.md)
- [SAML for GitLab.com groups](../../user/group/saml_sso/index.md) **(PREMIUM SAAS)**
- [Shibboleth](../../integration/saml.md)
- [Smartcard](smartcard.md) **(PREMIUM SELF)**
- [Twitter](../../integration/twitter.md)

View File

@ -300,7 +300,7 @@ disable enforcement. For more information, see the documentation on configuring
```toml
listen_addr = '0.0.0.0:8075'
runtime_dir = '/var/opt/gitlab/gitaly'
internal_socket_dir = '/var/opt/gitlab/gitaly'
[logging]
format = 'json'
@ -308,9 +308,6 @@ disable enforcement. For more information, see the documentation on configuring
dir = '/var/log/gitaly'
```
For GitLab 14.9 and earlier, set `internal_socket_dir = '/var/opt/gitlab/gitaly'` instead
of `runtime_dir`.
1. Append the following to `/home/git/gitaly/config.toml` for each respective Gitaly server:
On `gitaly1.internal`:

View File

@ -332,7 +332,7 @@ PUT --form "paused=true" /runners/:runner_id
# --or--
# Deprecated: removal planned in 15.0
# Deprecated: removal planned in 16.0
PUT --form "active=false" /runners/:runner_id
```
@ -346,7 +346,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
# --or--
# Deprecated: removal planned in 15.0
# Deprecated: removal planned in 16.0
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
--form "active=false" "https://gitlab.example.com/api/v4/runners/6"
```

View File

@ -1121,7 +1121,7 @@ host localhost # Give your setup a name (here: override localhost)
hostname 127.0.0.1; # Your server name or IP
```
You also need to change the corresponding options (for example, `ssh_user`, `ssh_host`, `admin_uri`) in the `config\gitlab.yml` file.
You also need to change the corresponding options (for example, `ssh_user`, `ssh_host`, `admin_uri`) in the `config/gitlab.yml` file.
### Additional Markup Styles

View File

@ -24,8 +24,8 @@ GitLab can be configured to authenticate access requests with the following auth
- Integrate with [Kerberos](kerberos.md).
- Enable sign in via [LDAP](../administration/auth/ldap/index.md).
- Enable [OAuth2 provider](oauth_provider.md) application creation.
- Use [OmniAuth](omniauth.md) to enable sign in via Twitter, GitHub, GitLab.com, Google,
Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure, or Authentiq ID.
- Use [OmniAuth](omniauth.md) to enable sign in through Twitter, GitHub, GitLab.com, Google,
Bitbucket, Facebook, SAML, Crowd, Azure, or Authentiq ID.
- Use GitLab as an [OpenID Connect](openid_connect_provider.md) identity provider.
- Authenticate to [Vault](vault.md) through GitLab OpenID Connect.
- Configure GitLab as a [SAML](saml.md) 2.0 Service Provider.

View File

@ -41,7 +41,6 @@ GitLab supports the following OmniAuth providers.
| [OpenID Connect](../administration/auth/oidc.md) | `openid_connect` |
| [Salesforce](salesforce.md) | `salesforce` |
| [SAML](saml.md) | `saml` |
| [Shibboleth](saml.md) | `shibboleth` |
| [Twitter](twitter.md) | `twitter` |
## Configure initial settings
@ -53,7 +52,7 @@ Setting | Description | Default value
---------------------------|-------------|--------------
`allow_single_sign_on` | Enables you to list the providers that automatically create a GitLab account. The provider names are available in the **OmniAuth provider name** column in the [supported providers table](#supported-providers). | The default is `false`. If `false`, users must be created manually, or they can't sign in using OmniAuth.
`auto_link_ldap_user` | If enabled, creates an LDAP identity in GitLab for users that are created through an OmniAuth provider. You can enable this setting if you have the [LDAP (ActiveDirectory)](../administration/auth/ldap/index.md) integration enabled. Requires the `uid` of the user to be the same in both LDAP and the OmniAuth provider. | The default is `false`.
`block_auto_created_users` | If enabled, blocks users that are automatically created from signing in until they are approved by an administrator. | The default is `true`. If you set the value to `false`, make sure you only define providers for `allow_single_sign_on` that you can control, like SAML, Shibboleth, Crowd, or Google. Otherwise, any user on the internet can sign in to GitLab without an administrator's approval.
`block_auto_created_users` | If enabled, blocks users that are automatically created from signing in until they are approved by an administrator. | The default is `true`. If you set the value to `false`, make sure you only define providers for `allow_single_sign_on` that you can control, like SAML, Crowd, or Google. Otherwise, any user on the internet can sign in to GitLab without an administrator's approval.
To change these settings:

View File

@ -91,7 +91,8 @@ To view a list of merge requests that need your attention:
1. On the top bar, select **Merge requests** (**{merge-request}**).
1. Select **Attention requests**.
To request attention from another user:
To request attention from another user, use the `/attention @user`
[quick action](../quick_actions.md) or:
1. Go to the merge request.
1. On the right sidebar, identify the user you want to request attention from.

View File

@ -55,6 +55,7 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/assign me` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Assign yourself. |
| `/assign_reviewer @user1 @user2` or `/reviewer @user1 @user2` or `/request_review @user1 @user2` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Assign one or more users as reviewers. |
| `/assign_reviewer me` or `/reviewer me` or `/request_review me` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Assign yourself as a reviewer. |
| `/attention @user1` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | [Request attention](merge_requests/index.md#request-attention-to-a-merge-request) to a merge request from a user. |
| `/award :emoji:` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Toggle emoji award. |
| `/child_epic <epic>` | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Add child epic to `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7330) in GitLab 12.0). |
| `/clear_health_status` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Clear [health status](issues/managing_issues.md#health-status) ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213814) in GitLab 14.7). |

View File

@ -124,9 +124,9 @@ module Gitlab
config[:storage] = storages
runtime_dir = options[:runtime_dir] || File.join(gitaly_dir, 'run')
FileUtils.mkdir(runtime_dir) unless File.exist?(runtime_dir)
config[:runtime_dir] = runtime_dir
internal_socket_dir = options[:internal_socket_dir] || File.join(gitaly_dir, 'internal_sockets')
FileUtils.mkdir(internal_socket_dir) unless File.exist?(internal_socket_dir)
config[:internal_socket_dir] = internal_socket_dir
config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby
config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }

View File

@ -45052,9 +45052,6 @@ msgstr ""
msgid "project access tokens"
msgstr ""
msgid "project avatar"
msgstr ""
msgid "project bots cannot be added to other groups / projects"
msgstr ""

View File

@ -81,6 +81,7 @@ module QA
return puts "\nNothing to download!" if files_list.empty?
FileUtils.mkdir_p('tmp/')
files_list.each do |file_name|
local_path = "tmp/#{file_name.split('/').last}"
Runtime::Logger.info("Downloading #{file_name} to #{local_path}")

View File

@ -76,12 +76,11 @@ RSpec.describe Projects::StaticSiteEditorController do
get :show, params: default_params
end
it 'increases the views counter' do
expect(Gitlab::UsageDataCounters::StaticSiteEditorCounter).to have_received(:increment_views_count)
end
it 'redirects to the Web IDE' do
get :show, params: default_params
it 'renders the edit page' do
expect(response).to render_template(:show)
expected_path_regex = %r[-/ide/project/#{project.full_path}/edit/master/-/README.md]
expect(response).to redirect_to(expected_path_regex)
end
it 'assigns ref and path variables' do
@ -96,62 +95,6 @@ RSpec.describe Projects::StaticSiteEditorController do
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when invalid config file' do
let(:service_response) { ServiceResponse.error(message: 'invalid') }
it 'redirects to project page and flashes error message' do
expect(response).to redirect_to(project_path(project))
expect(controller).to set_flash[:alert].to('invalid')
end
end
context 'with a service response payload containing multiple data types' do
let(:data) do
{
a_string: 'string',
an_array: [
{
foo: 'bar'
}
],
an_integer: 123,
a_hash: {
a_deeper_hash: {
foo: 'bar'
}
},
a_boolean: true,
a_nil: nil
}
end
let(:assigns_data) { assigns(:data) }
it 'leaves data values which are strings as strings' do
expect(assigns_data[:a_string]).to eq('string')
end
it 'leaves data values which are integers as integers' do
expect(assigns_data[:an_integer]).to eq(123)
end
it 'serializes data values which are booleans to JSON' do
expect(assigns_data[:a_boolean]).to eq('true')
end
it 'serializes data values which are arrays to JSON' do
expect(assigns_data[:an_array]).to eq('[{"foo":"bar"}]')
end
it 'serializes data values which are hashes to JSON' do
expect(assigns_data[:a_hash]).to eq('{"a_deeper_hash":{"foo":"bar"}}')
end
it 'serializes data values which are nil to an empty string' do
expect(assigns_data[:a_nil]).to eq('')
end
end
end
end
end

View File

@ -1,113 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Static Site Editor' do
include ContentSecurityPolicyHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
let(:sse_path) { project_show_sse_path(project, 'master/README.md') }
before_all do
project.add_developer(user)
end
before do
sign_in(user)
end
context "when no config file is present" do
before do
visit sse_path
end
it 'renders SSE page with all generated config values and default config file values' do
node = page.find('#static-site-editor')
# assert generated config values are present
expect(node['data-base-url']).to eq("/#{project.full_path}/-/sse/master%2FREADME.md")
expect(node['data-branch']).to eq('master')
expect(node['data-commit-id']).to match(/\A[0-9a-f]{40}\z/)
expect(node['data-is-supported-content']).to eq('true')
expect(node['data-merge-requests-illustration-path'])
.to match(%r{/assets/illustrations/merge_requests-.*\.svg})
expect(node['data-namespace']).to eq(project.namespace.full_path)
expect(node['data-project']).to eq(project.path)
expect(node['data-project-id']).to eq(project.id.to_s)
# assert default config file values are present
expect(node['data-image-upload-path']).to eq('source/images')
expect(node['data-mounts']).to eq('[{"source":"source","target":""}]')
expect(node['data-static-site-generator']).to eq('middleman')
end
end
context "when a config file is present" do
let(:config_file_yml) do
<<~YAML
image_upload_path: custom-image-upload-path
mounts:
- source: source1
target: ""
- source: source2
target: target2
static_site_generator: middleman
YAML
end
before do
allow_next_instance_of(Repository) do |repository|
allow(repository).to receive(:blob_data_at).and_return(config_file_yml)
end
visit sse_path
end
it 'renders Static Site Editor page values read from config file' do
node = page.find('#static-site-editor')
# assert user-specified config file values are present
expected_mounts = '[{"source":"source1","target":""},{"source":"source2","target":"target2"}]'
expect(node['data-image-upload-path']).to eq('custom-image-upload-path')
expect(node['data-mounts']).to eq(expected_mounts)
expect(node['data-static-site-generator']).to eq('middleman')
end
end
describe 'Static Site Editor Content Security Policy' do
subject { response_headers['Content-Security-Policy'] }
context 'when no global CSP config exists' do
before do
setup_csp_for_controller(Projects::StaticSiteEditorController)
end
it 'does not add CSP directives' do
visit sse_path
is_expected.to be_blank
end
end
context 'when a global CSP config exists' do
let_it_be(:cdn_url) { 'https://some-cdn.test' }
let_it_be(:youtube_url) { 'https://www.youtube.com' }
before do
csp = ActionDispatch::ContentSecurityPolicy.new do |p|
p.frame_src :self, cdn_url
end
setup_existing_csp_for_controller(Projects::StaticSiteEditorController, csp)
end
it 'appends youtube to the CSP frame-src policy' do
visit sse_path
is_expected.to eql("frame-src 'self' #{cdn_url} #{youtube_url}")
end
end
end
end

View File

@ -1,21 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Identicon entity id is a GraphQL id matches snapshot 1`] = `
<div
class="avatar identicon s40 bg2"
>
E
</div>
`;
exports[`Identicon entity id is a number matches snapshot 1`] = `
<div
class="avatar identicon s40 bg2"
>
E
</div>
`;

View File

@ -1,50 +0,0 @@
import { shallowMount } from '@vue/test-utils';
import IdenticonComponent from '~/vue_shared/components/identicon.vue';
describe('Identicon', () => {
let wrapper;
const defaultProps = {
entityId: 1,
entityName: 'entity-name',
sizeClass: 's40',
};
const createComponent = (props = {}) => {
wrapper = shallowMount(IdenticonComponent, {
propsData: {
...defaultProps,
...props,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('entity id is a number', () => {
beforeEach(() => createComponent());
it('matches snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('adds a correct class to identicon', () => {
expect(wrapper.find({ ref: 'identicon' }).classes()).toContain('bg2');
});
});
describe('entity id is a GraphQL id', () => {
beforeEach(() => createComponent({ entityId: 'gid://gitlab/Project/8' }));
it('matches snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('adds a correct class to identicon', () => {
expect(wrapper.find({ ref: 'identicon' }).classes()).toContain('bg2');
});
});
});

View File

@ -1,50 +0,0 @@
import Vue, { nextTick } from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import { projectData } from 'jest/ide/mock_data';
import { TEST_HOST } from 'spec/test_constants';
import { getFirstCharacterCapitalized } from '~/lib/utils/text_utility';
import ProjectAvatarDefault from '~/vue_shared/components/deprecated_project_avatar/default.vue';
describe('ProjectAvatarDefault component', () => {
const Component = Vue.extend(ProjectAvatarDefault);
let vm;
beforeEach(() => {
vm = mountComponent(Component, {
project: projectData,
});
});
afterEach(() => {
vm.$destroy();
});
it('renders identicon if project has no avatar_url', async () => {
const expectedText = getFirstCharacterCapitalized(projectData.name);
vm.project = {
...vm.project,
avatar_url: null,
};
await nextTick();
const identiconEl = vm.$el.querySelector('.identicon');
expect(identiconEl).not.toBe(null);
expect(identiconEl.textContent.trim()).toEqual(expectedText);
});
it('renders avatar image if project has avatar_url', async () => {
const avatarUrl = `${TEST_HOST}/images/home/nasa.svg`;
vm.project = {
...vm.project,
avatar_url: avatarUrl,
};
await nextTick();
expect(vm.$el.querySelector('.avatar')).not.toBeNull();
expect(vm.$el.querySelector('.identicon')).toBeNull();
expect(vm.$el.querySelector('img')).toHaveAttr('src', avatarUrl);
});
});

View File

@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import mockProjects from 'test_fixtures_static/projects.json';
import { trimText } from 'helpers/text_helper';
import ProjectAvatar from '~/vue_shared/components/deprecated_project_avatar/default.vue';
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
import ProjectListItem from '~/vue_shared/components/project_selector/project_list_item.vue';
describe('ProjectListItem component', () => {
@ -52,8 +52,13 @@ describe('ProjectListItem component', () => {
it(`renders the project avatar`, () => {
wrapper = shallowMount(Component, options);
const avatar = wrapper.findComponent(ProjectAvatar);
expect(wrapper.findComponent(ProjectAvatar).exists()).toBe(true);
expect(avatar.exists()).toBe(true);
expect(avatar.props()).toMatchObject({
projectAvatarUrl: '',
projectName: project.name_with_namespace,
});
});
it(`renders a simple namespace name with a trailing slash`, () => {

View File

@ -267,7 +267,7 @@ module GitalySetup
{ 'default' => repos_path },
force: true,
options: {
runtime_dir: File.join(gitaly_dir, "run2"),
internal_socket_dir: File.join(gitaly_dir, "internal_gitaly2"),
gitaly_socket: "gitaly2.socket",
config_filename: "gitaly2.config.toml"
}