Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8263f6ee31
commit
839c080dd0
|
@ -43,16 +43,21 @@ export default {
|
|||
mixins: [environmentItemMixin],
|
||||
|
||||
props: {
|
||||
canReadEnvironment: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
|
||||
model: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
canReadEnvironment: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
tableData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -447,9 +452,13 @@ export default {
|
|||
class="gl-responsive-table-row"
|
||||
role="row"
|
||||
>
|
||||
<div class="table-section section-wrap section-15 text-truncate" role="gridcell">
|
||||
<div
|
||||
class="table-section section-wrap text-truncate"
|
||||
:class="tableData.name.spacing"
|
||||
role="gridcell"
|
||||
>
|
||||
<div v-if="!model.isFolder" class="table-mobile-header" role="rowheader">
|
||||
{{ s__('Environments|Environment') }}
|
||||
{{ tableData.name.title }}
|
||||
</div>
|
||||
|
||||
<span v-if="shouldRenderDeployBoard" class="deploy-board-icon" @click="toggleDeployBoard">
|
||||
|
@ -489,7 +498,8 @@ export default {
|
|||
</div>
|
||||
|
||||
<div
|
||||
class="table-section section-10 deployment-column d-none d-sm-none d-md-block"
|
||||
class="table-section deployment-column d-none d-sm-none d-md-block"
|
||||
:class="tableData.deploy.spacing"
|
||||
role="gridcell"
|
||||
>
|
||||
<span v-if="shouldRenderDeploymentID" class="text-break-word">
|
||||
|
@ -508,7 +518,11 @@ export default {
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<div class="table-section section-15 d-none d-sm-none d-md-block" role="gridcell">
|
||||
<div
|
||||
class="table-section d-none d-sm-none d-md-block"
|
||||
:class="tableData.build.spacing"
|
||||
role="gridcell"
|
||||
>
|
||||
<a v-if="shouldRenderBuildName" :href="buildPath" class="build-link cgray">
|
||||
<tooltip-on-truncate
|
||||
:title="buildName"
|
||||
|
@ -522,8 +536,14 @@ export default {
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<div v-if="!model.isFolder" class="table-section section-20" role="gridcell">
|
||||
<div role="rowheader" class="table-mobile-header">{{ s__('Environments|Commit') }}</div>
|
||||
<div
|
||||
v-if="!model.isFolder"
|
||||
class="table-section"
|
||||
:class="tableData.commit.spacing"
|
||||
role="gridcell"
|
||||
>
|
||||
<div role="rowheader" class="table-mobile-header">{{ tableData.commit.title }}</div>
|
||||
|
||||
<div v-if="hasLastDeploymentKey" class="js-commit-component table-mobile-content">
|
||||
<commit-component
|
||||
:tag="commitTag"
|
||||
|
@ -539,8 +559,14 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!model.isFolder" class="table-section section-10" role="gridcell">
|
||||
<div role="rowheader" class="table-mobile-header">{{ s__('Environments|Updated') }}</div>
|
||||
<div
|
||||
v-if="!model.isFolder"
|
||||
class="table-section"
|
||||
:class="tableData.date.spacing"
|
||||
role="gridcell"
|
||||
>
|
||||
<div role="rowheader" class="table-mobile-header">{{ tableData.date.title }}</div>
|
||||
|
||||
<span v-if="canShowDate" class="environment-created-date-timeago table-mobile-content">
|
||||
{{ deployedDate }}
|
||||
</span>
|
||||
|
@ -548,7 +574,8 @@ export default {
|
|||
|
||||
<div
|
||||
v-if="!model.isFolder && displayEnvironmentActions"
|
||||
class="table-section section-30 table-button-footer"
|
||||
class="table-section table-button-footer"
|
||||
:class="tableData.actions.spacing"
|
||||
role="gridcell"
|
||||
>
|
||||
<div class="btn-group table-action-buttons" role="group">
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import _ from 'underscore';
|
||||
import { s__ } from '~/locale';
|
||||
import environmentTableMixin from 'ee_else_ce/environments/mixins/environments_table_mixin';
|
||||
import EnvironmentItem from './environment_item.vue';
|
||||
|
||||
|
@ -41,6 +42,34 @@ export default {
|
|||
: env,
|
||||
);
|
||||
},
|
||||
tableData() {
|
||||
return {
|
||||
// percent spacing for cols, should add up to 100
|
||||
name: {
|
||||
title: s__('Environments|Environment'),
|
||||
spacing: 'section-15',
|
||||
},
|
||||
deploy: {
|
||||
title: s__('Environments|Deployment'),
|
||||
spacing: 'section-10',
|
||||
},
|
||||
build: {
|
||||
title: s__('Environments|Job'),
|
||||
spacing: 'section-15',
|
||||
},
|
||||
commit: {
|
||||
title: s__('Environments|Commit'),
|
||||
spacing: 'section-20',
|
||||
},
|
||||
date: {
|
||||
title: s__('Environments|Updated'),
|
||||
spacing: 'section-10',
|
||||
},
|
||||
actions: {
|
||||
spacing: 'section-30',
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
folderUrl(model) {
|
||||
|
@ -79,20 +108,20 @@ export default {
|
|||
<template>
|
||||
<div class="ci-table" role="grid">
|
||||
<div class="gl-responsive-table-row table-row-header" role="row">
|
||||
<div class="table-section section-15 environments-name" role="columnheader">
|
||||
{{ s__('Environments|Environment') }}
|
||||
<div class="table-section" :class="tableData.name.spacing" role="columnheader">
|
||||
{{ tableData.name.title }}
|
||||
</div>
|
||||
<div class="table-section section-10 environments-deploy" role="columnheader">
|
||||
{{ s__('Environments|Deployment') }}
|
||||
<div class="table-section" :class="tableData.deploy.spacing" role="columnheader">
|
||||
{{ tableData.deploy.title }}
|
||||
</div>
|
||||
<div class="table-section section-15 environments-build" role="columnheader">
|
||||
{{ s__('Environments|Job') }}
|
||||
<div class="table-section" :class="tableData.build.spacing" role="columnheader">
|
||||
{{ tableData.build.title }}
|
||||
</div>
|
||||
<div class="table-section section-20 environments-commit" role="columnheader">
|
||||
{{ s__('Environments|Commit') }}
|
||||
<div class="table-section" :class="tableData.commit.spacing" role="columnheader">
|
||||
{{ tableData.commit.title }}
|
||||
</div>
|
||||
<div class="table-section section-10 environments-date" role="columnheader">
|
||||
{{ s__('Environments|Updated') }}
|
||||
<div class="table-section" :class="tableData.date.spacing" role="columnheader">
|
||||
{{ tableData.date.title }}
|
||||
</div>
|
||||
</div>
|
||||
<template v-for="(model, i) in sortedEnvironments" :model="model">
|
||||
|
@ -101,6 +130,7 @@ export default {
|
|||
:key="`environment-item-${i}`"
|
||||
:model="model"
|
||||
:can-read-environment="canReadEnvironment"
|
||||
:table-data="tableData"
|
||||
/>
|
||||
|
||||
<div
|
||||
|
@ -132,6 +162,7 @@ export default {
|
|||
:key="`env-item-${i}-${index}`"
|
||||
:model="children"
|
||||
:can-read-environment="canReadEnvironment"
|
||||
:table-data="tableData"
|
||||
/>
|
||||
|
||||
<div :key="`sub-div-${i}`">
|
||||
|
|
|
@ -15,13 +15,9 @@ class SnippetsController < ApplicationController
|
|||
|
||||
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
|
||||
|
||||
# Allow read snippet
|
||||
before_action :authorize_create_snippet!, only: [:new, :create]
|
||||
before_action :authorize_read_snippet!, only: [:show, :raw]
|
||||
|
||||
# Allow modify snippet
|
||||
before_action :authorize_update_snippet!, only: [:edit, :update]
|
||||
|
||||
# Allow destroy snippet
|
||||
before_action :authorize_admin_snippet!, only: [:destroy]
|
||||
|
||||
skip_before_action :authenticate_user!, only: [:index, :show, :raw]
|
||||
|
@ -140,6 +136,10 @@ class SnippetsController < ApplicationController
|
|||
return render_404 unless can?(current_user, :admin_personal_snippet, @snippet)
|
||||
end
|
||||
|
||||
def authorize_create_snippet!
|
||||
return render_404 unless can?(current_user, :create_personal_snippet)
|
||||
end
|
||||
|
||||
def snippet_params
|
||||
params.require(:personal_snippet).permit(:title, :content, :file_name, :private, :visibility_level, :description)
|
||||
end
|
||||
|
|
|
@ -75,12 +75,15 @@ class GlobalPolicy < BasePolicy
|
|||
|
||||
rule { ~anonymous }.policy do
|
||||
enable :read_instance_metadata
|
||||
enable :create_personal_snippet
|
||||
end
|
||||
|
||||
rule { admin }.policy do
|
||||
enable :read_custom_attribute
|
||||
enable :update_custom_attribute
|
||||
end
|
||||
|
||||
rule { external_user }.prevent :create_personal_snippet
|
||||
end
|
||||
|
||||
GlobalPolicy.prepend_if_ee('EE::GlobalPolicy')
|
||||
|
|
|
@ -17,9 +17,6 @@ class PersonalSnippetPolicy < BasePolicy
|
|||
enable :create_note
|
||||
end
|
||||
|
||||
rule { ~anonymous }.enable :create_personal_snippet
|
||||
rule { external_user }.prevent :create_personal_snippet
|
||||
|
||||
rule { internal_snippet & ~external_user }.policy do
|
||||
enable :read_personal_snippet
|
||||
enable :create_note
|
||||
|
|
|
@ -38,4 +38,5 @@
|
|||
%li= link_to _('New project'), new_project_path, class: 'qa-global-new-project-link'
|
||||
- if current_user.can_create_group?
|
||||
%li= link_to _('New group'), new_group_path
|
||||
%li= link_to _('New snippet'), new_snippet_path, class: 'qa-global-new-snippet-link'
|
||||
- if current_user.can?(:create_personal_snippet)
|
||||
%li= link_to _('New snippet'), new_snippet_path, class: 'qa-global-new-snippet-link'
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
- if can?(current_user, :admin_personal_snippet, @snippet)
|
||||
= link_to snippet_path(@snippet), method: :delete, data: { confirm: _("Are you sure?") }, class: "btn btn-grouped btn-inverted btn-remove", title: _('Delete Snippet') do
|
||||
= _("Delete")
|
||||
= link_to new_snippet_path, class: "btn btn-grouped btn-success btn-inverted", title: _("New snippet") do
|
||||
= _("New snippet")
|
||||
- if can?(current_user, :create_personal_snippet)
|
||||
= link_to new_snippet_path, class: "btn btn-grouped btn-success btn-inverted", title: _("New snippet") do
|
||||
= _("New snippet")
|
||||
- if @snippet.submittable_as_spam_by?(current_user)
|
||||
= link_to _('Submit as spam'), mark_as_spam_snippet_path(@snippet), method: :post, class: 'btn btn-grouped btn-spam', title: _('Submit as spam')
|
||||
.d-block.d-sm-none.dropdown
|
||||
|
@ -17,9 +18,10 @@
|
|||
= icon('caret-down')
|
||||
.dropdown-menu.dropdown-menu-full-width
|
||||
%ul
|
||||
%li
|
||||
= link_to new_snippet_path, title: _("New snippet") do
|
||||
= _("New snippet")
|
||||
- if can?(current_user, :create_personal_snippet)
|
||||
%li
|
||||
= link_to new_snippet_path, title: _("New snippet") do
|
||||
= _("New snippet")
|
||||
- if can?(current_user, :admin_personal_snippet, @snippet)
|
||||
%li
|
||||
= link_to snippet_path(@snippet), method: :delete, data: { confirm: _("Are you sure?") }, title: _('Delete Snippet') do
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add dependency scanning flag for skipping automatic bundler audit update
|
||||
merge_request: 20743
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Ensure to check create_personal_snippet ability
|
||||
merge_request: 20838
|
||||
author:
|
||||
type: fixed
|
|
@ -1,4 +1,4 @@
|
|||
# Custom server-side Git hooks
|
||||
# Custom server-side Git hooks **(CORE ONLY)**
|
||||
|
||||
NOTE: **Note:**
|
||||
Custom Git hooks must be configured on the filesystem of the GitLab
|
||||
|
|
|
@ -334,7 +334,10 @@ When you tail the Gitaly logs on your Gitaly server you should see requests
|
|||
coming in. One sure way to trigger a Gitaly request is to clone a repository
|
||||
from your GitLab server over HTTP.
|
||||
|
||||
DANGER: **Danger:** If you have [custom server-side Git hooks](../custom_hooks.md#custom-server-side-git-hooks) configured, either per repository or globally, you must move these to the Gitaly node. If you have multiple Gitaly nodes, copy your custom hook(s) to all nodes.
|
||||
DANGER: **Danger:**
|
||||
If you have [custom server-side Git hooks](../custom_hooks.md) configured,
|
||||
either per repository or globally, you must move these to the Gitaly node.
|
||||
If you have multiple Gitaly nodes, copy your custom hook(s) to all nodes.
|
||||
|
||||
### Disabling the Gitaly service in a cluster environment
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ Decision on whether backporting a change will be performed is done at the discre
|
|||
|
||||
1. Estimated [severity][severity-labels] of the bug: Highest possible impact to users based on the current definition of severity.
|
||||
|
||||
1. Estimated [priority][priority-labels] of the bug: Immediate impact on all impacted users based on the above estimated severity.
|
||||
1. Estimated [priority][priority-definition] of the bug: Immediate impact on all impacted users based on the above estimated severity.
|
||||
|
||||
1. Potentially incurring data loss and/or security breach.
|
||||
|
||||
|
@ -115,16 +115,24 @@ one major version. For example, it is safe to:
|
|||
- `8.9.0` -> `8.9.7`
|
||||
- `8.9.0` -> `8.9.1`
|
||||
- `8.9.2` -> `8.9.6`
|
||||
- `9.5.5` -> `9.5.9`
|
||||
- `10.6.3` -> `10.6.6`
|
||||
- `11.11.1` -> `11.11.8`
|
||||
- `12.0.4` -> `12.0.9`
|
||||
- Upgrade the minor version:
|
||||
- `8.9.4` -> `8.12.3`
|
||||
- `9.2.3` -> `9.5.5`
|
||||
- `10.6.6` -> `10.8.7`
|
||||
- `11.3.4` -> `11.11.8`
|
||||
|
||||
Upgrading the major version requires more attention.
|
||||
We cannot guarantee that upgrading between major versions will be seamless. As previously mentioned, major versions are reserved for backwards incompatible changes.
|
||||
|
||||
We recommend that you first upgrade to the latest available minor version within
|
||||
your major version. By doing this, you can address any deprecation messages
|
||||
that could change behavior in the next major release.
|
||||
To ensure background migrations are successful, increment by one minor version during the version jump before installing newer releases.
|
||||
|
||||
For example: `11.11.x` -> `12.0.x`
|
||||
|
||||
Please see the table below for some examples:
|
||||
|
||||
|
@ -133,7 +141,7 @@ Please see the table below for some examples:
|
|||
| 9.4.5 | 8.13.4 | `8.13.4` -> `8.17.7` -> `9.4.5` | `8.17.7` is the last version in version `8` |
|
||||
| 10.1.4 | 8.13.4 | `8.13.4 -> 8.17.7 -> 9.5.10 -> 10.1.4` | `8.17.7` is the last version in version `8`, `9.5.10` is the last version in version `9` |
|
||||
| 11.3.4 | 8.13.4 | `8.13.4` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> `11.3.4` | `8.17.7` is the last version in version `8`, `9.5.10` is the last version in version `9`, `10.8.7` is the last version in version `10` |
|
||||
| 12.0.2 | 11.3.4 | `11.3.4` -> `11.11.x` -> `12.0.2` | `11.11.x` is the last version in version `11`
|
||||
| 12.5.8 | 11.3.4 | `11.3.4` -> `11.11.8` -> `12.0.9` -> `12.5.8` | `11.11.8` is the last version in version `11` |
|
||||
|
||||
More information about the release procedures can be found in our
|
||||
[release documentation](https://gitlab.com/gitlab-org/release/docs). You may also want to read our
|
||||
|
@ -143,4 +151,4 @@ More information about the release procedures can be found in our
|
|||
[priority-definition]: ../development/contributing/issue_workflow.md#priority-labels
|
||||
[severity-labels]: ../development/contributing/issue_workflow.html#severity-labels
|
||||
[managing bugs]: https://gitlab.com/gitlab-org/gitlab/blob/master/PROCESS.md#managing-bugs
|
||||
[release/tasks]: https://gitlab.com/gitlab-org/release/tasks/issues
|
||||
[release/tasks]: https://gitlab.com/gitlab-org/release/tasks/issues/new?issuable_template=Backporting-request
|
||||
|
|
|
@ -12,13 +12,7 @@ You can select the tag in the version dropdown in the top left corner of GitLab
|
|||
|
||||
### 0. Backup
|
||||
|
||||
It's useful to make a backup just in case things go south:
|
||||
|
||||
```bash
|
||||
cd /home/git/gitlab
|
||||
|
||||
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
|
||||
```
|
||||
It's useful to make a backup just in case things go south. Depending on the installation method, backup commands vary, see the [backing up and restoring GitLab](../raketasks/backup_restore.md#creating-a-backup-of-the-gitlab-system) documentation.
|
||||
|
||||
### 1. Stop server
|
||||
|
||||
|
|
|
@ -144,6 +144,7 @@ using environment variables.
|
|||
| `PIP_INDEX_URL` | Base URL of Python Package Index (default `https://pypi.org/simple`). |
|
||||
| `PIP_EXTRA_INDEX_URL` | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma separated. |
|
||||
| `MAVEN_CLI_OPTS` | List of command line arguments that will be passed to the maven analyzer during the project's build phase (see example for [using private repos](#using-private-maven-repos)). |
|
||||
| `BUNDLER_AUDIT_UPDATE_DISABLED` | Disable automatic updates for the `bundler-audit` analyzer (default: `"false"`). Useful if you're running Dependency Scanning in an offline, air-gapped environment.|
|
||||
|
||||
### Using private Maven repos
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ get familiar with the package naming convention.
|
|||
|
||||
## Authenticating to the GitLab Conan Repository
|
||||
|
||||
You will need to generate a [personal access token](../../../user/profile/personal_access_tokens.md) for repository authentication.
|
||||
You will need to generate a [personal access token](../../../user/profile/personal_access_tokens.md) with the scope set to `api` for repository authentication.
|
||||
|
||||
Now you can run conan commands using your token.
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ credentials do not work.
|
|||
### Authenticating with a personal access token
|
||||
|
||||
To authenticate with a [personal access token](../../profile/personal_access_tokens.md),
|
||||
add a corresponding section to your
|
||||
set the scope to `api` and add a corresponding section to your
|
||||
[`settings.xml`](https://maven.apache.org/settings.html) file:
|
||||
|
||||
```xml
|
||||
|
|
|
@ -54,7 +54,7 @@ If a project is private or you want to upload an NPM package to GitLab,
|
|||
credentials will need to be provided for authentication. Support is available for [OAuth tokens](../../../api/oauth2.md#resource-owner-password-credentials-flow) or [personal access tokens](../../profile/personal_access_tokens.md).
|
||||
|
||||
CAUTION: **2FA is only supported with personal access tokens:**
|
||||
If you have 2FA enabled, you need to use a [personal access token](../../profile/personal_access_tokens.md) with OAuth headers. Standard OAuth tokens won't be able to authenticate to the GitLab NPM Registry.
|
||||
If you have 2FA enabled, you need to use a [personal access token](../../profile/personal_access_tokens.md) with OAuth headers with the scope set to `api`. Standard OAuth tokens won't be able to authenticate to the GitLab NPM Registry.
|
||||
|
||||
### Authenticating with an OAuth token
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ type: reference, concepts
|
|||
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/merge_requests/17291) from
|
||||
"Cross-project dependencies" to "Merge Requests dependencies" in
|
||||
[GitLab Premium](https://about.gitlab.com/pricing/) 12.4.
|
||||
> - Intra-project MR dependencies were [introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16799)
|
||||
in [GitLab Premium](https://about.gitlab.com/pricing/) 12.4.
|
||||
|
||||
Merge request dependencies allows a required order of merging
|
||||
between merge requests to be expressed. If a merge request "depends on" another,
|
||||
|
@ -20,10 +22,6 @@ only enforced for the dependent merge request. A merge request in a **CORE** or
|
|||
**STARTER** project can be a dependency of a **PREMIUM** merge request, but not
|
||||
vice-versa.
|
||||
|
||||
NOTE: **Note:**
|
||||
A merge request can only depend on merge requests in a different project. Two
|
||||
merge requests in the same project cannot depend on each other.
|
||||
|
||||
## Use cases
|
||||
|
||||
- Ensure changes to a library are merged before changes to a project that
|
||||
|
|
|
@ -52,6 +52,7 @@ dependency_scanning:
|
|||
PIP_INDEX_URL \
|
||||
PIP_EXTRA_INDEX_URL \
|
||||
MAVEN_CLI_OPTS \
|
||||
BUNDLER_AUDIT_UPDATE_DISABLED \
|
||||
) \
|
||||
--volume "$PWD:/code" \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
|
|
|
@ -53,6 +53,16 @@ describe SnippetsController do
|
|||
|
||||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
context 'when user is not allowed to create a personal snippet' do
|
||||
let(:user) { create(:user, :external) }
|
||||
|
||||
it 'responds with status 404' do
|
||||
get :new
|
||||
|
||||
expect(response).to have_gitlab_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not signed in' do
|
||||
|
@ -215,6 +225,20 @@ describe SnippetsController do
|
|||
expect(snippet.description).to eq('Description')
|
||||
end
|
||||
|
||||
context 'when user is not allowed to create a personal snippet' do
|
||||
let(:user) { create(:user, :external) }
|
||||
|
||||
it 'responds with status 404' do
|
||||
aggregate_failures do
|
||||
expect do
|
||||
create_snippet(visibility_level: Snippet::PUBLIC)
|
||||
end.not_to change { Snippet.count }
|
||||
|
||||
expect(response).to have_gitlab_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the snippet description contains a file' do
|
||||
include FileMoverHelpers
|
||||
|
||||
|
|
|
@ -158,4 +158,21 @@ describe 'Snippet', :js do
|
|||
|
||||
subject { visit snippet_path(snippet) }
|
||||
end
|
||||
|
||||
context 'when user cannot create snippets' do
|
||||
let(:user) { create(:user, :external) }
|
||||
let(:snippet) { create(:personal_snippet, :public) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
|
||||
visit snippet_path(snippet)
|
||||
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
it 'does not show the "New Snippet" button' do
|
||||
expect(page).not_to have_link('New snippet')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,32 @@ import { format } from 'timeago.js';
|
|||
import Vue from 'vue';
|
||||
import environmentItemComp from '~/environments/components/environment_item.vue';
|
||||
|
||||
const tableData = {
|
||||
name: {
|
||||
title: 'Environment',
|
||||
spacing: 'section-15',
|
||||
},
|
||||
deploy: {
|
||||
title: 'Deployment',
|
||||
spacing: 'section-10',
|
||||
},
|
||||
build: {
|
||||
title: 'Job',
|
||||
spacing: 'section-15',
|
||||
},
|
||||
commit: {
|
||||
title: 'Commit',
|
||||
spacing: 'section-20',
|
||||
},
|
||||
date: {
|
||||
title: 'Updated',
|
||||
spacing: 'section-10',
|
||||
},
|
||||
actions: {
|
||||
spacing: 'section-25',
|
||||
},
|
||||
};
|
||||
|
||||
describe('Environment item', () => {
|
||||
let EnvironmentItem;
|
||||
|
||||
|
@ -27,6 +53,7 @@ describe('Environment item', () => {
|
|||
propsData: {
|
||||
model: mockItem,
|
||||
canReadEnvironment: true,
|
||||
tableData,
|
||||
},
|
||||
}).$mount();
|
||||
});
|
||||
|
@ -119,6 +146,7 @@ describe('Environment item', () => {
|
|||
propsData: {
|
||||
model: environment,
|
||||
canReadEnvironment: true,
|
||||
tableData,
|
||||
},
|
||||
}).$mount();
|
||||
});
|
||||
|
|
|
@ -306,4 +306,22 @@ describe GlobalPolicy do
|
|||
it { is_expected.not_to be_allowed(:use_slash_commands) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'create_personal_snippet' do
|
||||
context 'when anonymous' do
|
||||
let(:current_user) { nil }
|
||||
|
||||
it { is_expected.not_to be_allowed(:create_personal_snippet) }
|
||||
end
|
||||
|
||||
context 'regular user' do
|
||||
it { is_expected.to be_allowed(:create_personal_snippet) }
|
||||
end
|
||||
|
||||
context 'when external' do
|
||||
let(:current_user) { build(:user, :external) }
|
||||
|
||||
it { is_expected.not_to be_allowed(:create_personal_snippet) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -126,6 +126,16 @@ describe 'layouts/header/_new_dropdown' do
|
|||
|
||||
expect(rendered).to have_link('New snippet', href: new_snippet_path)
|
||||
end
|
||||
|
||||
context 'when the user is not allowed to create snippets' do
|
||||
let(:user) { create(:user, :external)}
|
||||
|
||||
it 'has no "New snippet" link' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_link('New snippet', href: new_snippet_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def stub_current_user(current_user)
|
||||
|
|
Loading…
Reference in New Issue