Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
9c28b22cfc
commit
2194dac753
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -3,7 +3,7 @@ import { GlButton, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
|
||||||
import { isString } from 'lodash';
|
import { isString } from 'lodash';
|
||||||
import highlight from '~/lib/utils/highlight';
|
import highlight from '~/lib/utils/highlight';
|
||||||
import { truncateNamespace } from '~/lib/utils/text_utility';
|
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 {
|
export default {
|
||||||
name: 'ProjectListItem',
|
name: 'ProjectListItem',
|
||||||
|
@ -22,6 +22,9 @@ export default {
|
||||||
matcher: { type: String, required: false, default: '' },
|
matcher: { type: String, required: false, default: '' },
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
projectAvatarUrl() {
|
||||||
|
return this.project.avatar_url || this.project.avatarUrl;
|
||||||
|
},
|
||||||
projectNameWithNamespace() {
|
projectNameWithNamespace() {
|
||||||
return this.project.nameWithNamespace || this.project.name_with_namespace;
|
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"
|
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" />
|
<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
|
<div
|
||||||
v-if="truncatedNamespace"
|
v-if="truncatedNamespace"
|
||||||
:title="projectNameWithNamespace"
|
:title="projectNameWithNamespace"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
class Projects::StaticSiteEditorController < Projects::ApplicationController
|
class Projects::StaticSiteEditorController < Projects::ApplicationController
|
||||||
include ExtractsPath
|
include ExtractsPath
|
||||||
include CreatesCommit
|
include CreatesCommit
|
||||||
|
include BlobHelper
|
||||||
|
|
||||||
layout 'fullscreen'
|
layout 'fullscreen'
|
||||||
|
|
||||||
|
@ -24,28 +25,7 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
service_response = ::StaticSiteEditor::ConfigService.new(
|
redirect_to ide_edit_path(project, @ref, @path)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -576,7 +576,6 @@ severities
|
||||||
sharded
|
sharded
|
||||||
sharding
|
sharding
|
||||||
shfmt
|
shfmt
|
||||||
Shibboleth
|
|
||||||
Shimo
|
Shimo
|
||||||
Shopify
|
Shopify
|
||||||
Sidekiq
|
Sidekiq
|
||||||
|
|
|
@ -31,7 +31,6 @@ providers:
|
||||||
- [Salesforce](../../integration/salesforce.md)
|
- [Salesforce](../../integration/salesforce.md)
|
||||||
- [SAML](../../integration/saml.md)
|
- [SAML](../../integration/saml.md)
|
||||||
- [SAML for GitLab.com groups](../../user/group/saml_sso/index.md) **(PREMIUM SAAS)**
|
- [SAML for GitLab.com groups](../../user/group/saml_sso/index.md) **(PREMIUM SAAS)**
|
||||||
- [Shibboleth](../../integration/saml.md)
|
|
||||||
- [Smartcard](smartcard.md) **(PREMIUM SELF)**
|
- [Smartcard](smartcard.md) **(PREMIUM SELF)**
|
||||||
- [Twitter](../../integration/twitter.md)
|
- [Twitter](../../integration/twitter.md)
|
||||||
|
|
||||||
|
|
|
@ -300,7 +300,7 @@ disable enforcement. For more information, see the documentation on configuring
|
||||||
```toml
|
```toml
|
||||||
listen_addr = '0.0.0.0:8075'
|
listen_addr = '0.0.0.0:8075'
|
||||||
|
|
||||||
runtime_dir = '/var/opt/gitlab/gitaly'
|
internal_socket_dir = '/var/opt/gitlab/gitaly'
|
||||||
|
|
||||||
[logging]
|
[logging]
|
||||||
format = 'json'
|
format = 'json'
|
||||||
|
@ -308,9 +308,6 @@ disable enforcement. For more information, see the documentation on configuring
|
||||||
dir = '/var/log/gitaly'
|
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:
|
1. Append the following to `/home/git/gitaly/config.toml` for each respective Gitaly server:
|
||||||
|
|
||||||
On `gitaly1.internal`:
|
On `gitaly1.internal`:
|
||||||
|
|
|
@ -332,7 +332,7 @@ PUT --form "paused=true" /runners/:runner_id
|
||||||
|
|
||||||
# --or--
|
# --or--
|
||||||
|
|
||||||
# Deprecated: removal planned in 15.0
|
# Deprecated: removal planned in 16.0
|
||||||
PUT --form "active=false" /runners/:runner_id
|
PUT --form "active=false" /runners/:runner_id
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||||
|
|
||||||
# --or--
|
# --or--
|
||||||
|
|
||||||
# Deprecated: removal planned in 15.0
|
# Deprecated: removal planned in 16.0
|
||||||
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
|
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||||
--form "active=false" "https://gitlab.example.com/api/v4/runners/6"
|
--form "active=false" "https://gitlab.example.com/api/v4/runners/6"
|
||||||
```
|
```
|
||||||
|
|
|
@ -1121,7 +1121,7 @@ host localhost # Give your setup a name (here: override localhost)
|
||||||
hostname 127.0.0.1; # Your server name or IP
|
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
|
### Additional Markup Styles
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ GitLab can be configured to authenticate access requests with the following auth
|
||||||
- Integrate with [Kerberos](kerberos.md).
|
- Integrate with [Kerberos](kerberos.md).
|
||||||
- Enable sign in via [LDAP](../administration/auth/ldap/index.md).
|
- Enable sign in via [LDAP](../administration/auth/ldap/index.md).
|
||||||
- Enable [OAuth2 provider](oauth_provider.md) application creation.
|
- Enable [OAuth2 provider](oauth_provider.md) application creation.
|
||||||
- Use [OmniAuth](omniauth.md) to enable sign in via Twitter, GitHub, GitLab.com, Google,
|
- Use [OmniAuth](omniauth.md) to enable sign in through Twitter, GitHub, GitLab.com, Google,
|
||||||
Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure, or Authentiq ID.
|
Bitbucket, Facebook, SAML, Crowd, Azure, or Authentiq ID.
|
||||||
- Use GitLab as an [OpenID Connect](openid_connect_provider.md) identity provider.
|
- Use GitLab as an [OpenID Connect](openid_connect_provider.md) identity provider.
|
||||||
- Authenticate to [Vault](vault.md) through GitLab OpenID Connect.
|
- Authenticate to [Vault](vault.md) through GitLab OpenID Connect.
|
||||||
- Configure GitLab as a [SAML](saml.md) 2.0 Service Provider.
|
- Configure GitLab as a [SAML](saml.md) 2.0 Service Provider.
|
||||||
|
|
|
@ -41,7 +41,6 @@ GitLab supports the following OmniAuth providers.
|
||||||
| [OpenID Connect](../administration/auth/oidc.md) | `openid_connect` |
|
| [OpenID Connect](../administration/auth/oidc.md) | `openid_connect` |
|
||||||
| [Salesforce](salesforce.md) | `salesforce` |
|
| [Salesforce](salesforce.md) | `salesforce` |
|
||||||
| [SAML](saml.md) | `saml` |
|
| [SAML](saml.md) | `saml` |
|
||||||
| [Shibboleth](saml.md) | `shibboleth` |
|
|
||||||
| [Twitter](twitter.md) | `twitter` |
|
| [Twitter](twitter.md) | `twitter` |
|
||||||
|
|
||||||
## Configure initial settings
|
## 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.
|
`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`.
|
`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:
|
To change these settings:
|
||||||
|
|
||||||
|
|
|
@ -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. On the top bar, select **Merge requests** (**{merge-request}**).
|
||||||
1. Select **Attention requests**.
|
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. Go to the merge request.
|
||||||
1. On the right sidebar, identify the user you want to request attention from.
|
1. On the right sidebar, identify the user you want to request attention from.
|
||||||
|
|
|
@ -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 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 @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. |
|
| `/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. |
|
| `/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). |
|
| `/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). |
|
| `/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). |
|
||||||
|
|
|
@ -124,9 +124,9 @@ module Gitlab
|
||||||
|
|
||||||
config[:storage] = storages
|
config[:storage] = storages
|
||||||
|
|
||||||
runtime_dir = options[:runtime_dir] || File.join(gitaly_dir, 'run')
|
internal_socket_dir = options[:internal_socket_dir] || File.join(gitaly_dir, 'internal_sockets')
|
||||||
FileUtils.mkdir(runtime_dir) unless File.exist?(runtime_dir)
|
FileUtils.mkdir(internal_socket_dir) unless File.exist?(internal_socket_dir)
|
||||||
config[:runtime_dir] = runtime_dir
|
config[:internal_socket_dir] = internal_socket_dir
|
||||||
|
|
||||||
config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby
|
config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby
|
||||||
config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }
|
config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }
|
||||||
|
|
|
@ -45052,9 +45052,6 @@ msgstr ""
|
||||||
msgid "project access tokens"
|
msgid "project access tokens"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "project avatar"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "project bots cannot be added to other groups / projects"
|
msgid "project bots cannot be added to other groups / projects"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ module QA
|
||||||
|
|
||||||
return puts "\nNothing to download!" if files_list.empty?
|
return puts "\nNothing to download!" if files_list.empty?
|
||||||
|
|
||||||
|
FileUtils.mkdir_p('tmp/')
|
||||||
files_list.each do |file_name|
|
files_list.each do |file_name|
|
||||||
local_path = "tmp/#{file_name.split('/').last}"
|
local_path = "tmp/#{file_name.split('/').last}"
|
||||||
Runtime::Logger.info("Downloading #{file_name} to #{local_path}")
|
Runtime::Logger.info("Downloading #{file_name} to #{local_path}")
|
||||||
|
|
|
@ -76,12 +76,11 @@ RSpec.describe Projects::StaticSiteEditorController do
|
||||||
get :show, params: default_params
|
get :show, params: default_params
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'increases the views counter' do
|
it 'redirects to the Web IDE' do
|
||||||
expect(Gitlab::UsageDataCounters::StaticSiteEditorCounter).to have_received(:increment_views_count)
|
get :show, params: default_params
|
||||||
end
|
|
||||||
|
|
||||||
it 'renders the edit page' do
|
expected_path_regex = %r[-/ide/project/#{project.full_path}/edit/master/-/README.md]
|
||||||
expect(response).to render_template(:show)
|
expect(response).to redirect_to(expected_path_regex)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'assigns ref and path variables' do
|
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)
|
expect(response).to have_gitlab_http_status(:not_found)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
|
|
@ -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>
|
|
||||||
`;
|
|
|
@ -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');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import mockProjects from 'test_fixtures_static/projects.json';
|
import mockProjects from 'test_fixtures_static/projects.json';
|
||||||
import { trimText } from 'helpers/text_helper';
|
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';
|
import ProjectListItem from '~/vue_shared/components/project_selector/project_list_item.vue';
|
||||||
|
|
||||||
describe('ProjectListItem component', () => {
|
describe('ProjectListItem component', () => {
|
||||||
|
@ -52,8 +52,13 @@ describe('ProjectListItem component', () => {
|
||||||
|
|
||||||
it(`renders the project avatar`, () => {
|
it(`renders the project avatar`, () => {
|
||||||
wrapper = shallowMount(Component, options);
|
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`, () => {
|
it(`renders a simple namespace name with a trailing slash`, () => {
|
||||||
|
|
|
@ -267,7 +267,7 @@ module GitalySetup
|
||||||
{ 'default' => repos_path },
|
{ 'default' => repos_path },
|
||||||
force: true,
|
force: true,
|
||||||
options: {
|
options: {
|
||||||
runtime_dir: File.join(gitaly_dir, "run2"),
|
internal_socket_dir: File.join(gitaly_dir, "internal_gitaly2"),
|
||||||
gitaly_socket: "gitaly2.socket",
|
gitaly_socket: "gitaly2.socket",
|
||||||
config_filename: "gitaly2.config.toml"
|
config_filename: "gitaly2.config.toml"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue