Commit e76f12f7 authored by Adam Hegyi's avatar Adam Hegyi

Merge branch 'master' into...

Merge branch 'master' into '63406-selecting-a-line-in-ci-job-trace-using-triple-click-selects-the-previous-line-also'

# Conflicts:
#   spec/lib/gitlab/ci/ansi2html_spec.rb
parents 86c08225 7fa94651
...@@ -8,8 +8,7 @@ class Projects::TagsController < Projects::ApplicationController ...@@ -8,8 +8,7 @@ class Projects::TagsController < Projects::ApplicationController
# Authorize # Authorize
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :authorize_download_code! before_action :authorize_download_code!
before_action :authorize_push_code!, only: [:new, :create] before_action :authorize_admin_tag!, only: [:new, :create, :destroy]
before_action :authorize_admin_project!, only: [:destroy]
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def index def index
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Clusters module Clusters
module Applications module Applications
class Knative < ApplicationRecord class Knative < ApplicationRecord
VERSION = '0.5.0'.freeze VERSION = '0.6.0'.freeze
REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze
METRICS_CONFIG = 'https://storage.googleapis.com/triggermesh-charts/istio-metrics.yaml'.freeze METRICS_CONFIG = 'https://storage.googleapis.com/triggermesh-charts/istio-metrics.yaml'.freeze
FETCH_IP_ADDRESS_DELAY = 30.seconds FETCH_IP_ADDRESS_DELAY = 30.seconds
......
...@@ -297,6 +297,7 @@ class ProjectPolicy < BasePolicy ...@@ -297,6 +297,7 @@ class ProjectPolicy < BasePolicy
end end
rule { (mirror_available & can?(:admin_project)) | admin }.enable :admin_remote_mirror rule { (mirror_available & can?(:admin_project)) | admin }.enable :admin_remote_mirror
rule { can?(:push_code) }.enable :admin_tag
rule { archived }.policy do rule { archived }.policy do
prevent :push_code prevent :push_code
......
# frozen_string_literal: true
module Git
class WikiPushService < ::BaseService
def execute
# This is used in EE
end
end
end
...@@ -26,10 +26,8 @@ ...@@ -26,10 +26,8 @@
.row-fixed-content.controls.flex-row .row-fixed-content.controls.flex-row
= render 'projects/buttons/download', project: @project, ref: tag.name, pipeline: @tags_pipelines[tag.name] = render 'projects/buttons/download', project: @project, ref: tag.name, pipeline: @tags_pipelines[tag.name]
- if can?(current_user, :push_code, @project) - if can?(current_user, :admin_tag, @project)
= link_to edit_project_tag_release_path(@project, tag.name), class: 'btn btn-edit has-tooltip', title: s_('TagsPage|Edit release notes'), data: { container: "body" } do = link_to edit_project_tag_release_path(@project, tag.name), class: 'btn btn-edit has-tooltip', title: s_('TagsPage|Edit release notes'), data: { container: "body" } do
= icon("pencil") = icon("pencil")
= link_to project_tag_path(@project, tag.name), class: "btn btn-remove remove-row has-tooltip prepend-left-10 #{protected_tag?(@project, tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), method: :delete, data: { confirm: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: tag.name }, container: 'body' }, remote: true do
- if can?(current_user, :admin_project, @project) = icon("trash-o")
= link_to project_tag_path(@project, tag.name), class: "btn btn-remove remove-row has-tooltip prepend-left-10 #{protected_tag?(@project, tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), method: :delete, data: { confirm: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: tag.name }, container: 'body' }, remote: true do
= icon("trash-o")
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
- tags_sort_options_hash.each do |value, title| - tags_sort_options_hash.each do |value, title|
%li %li
= link_to title, filter_tags_path(sort: value), class: ("is-active" if @sort == value) = link_to title, filter_tags_path(sort: value), class: ("is-active" if @sort == value)
- if can?(current_user, :push_code, @project) - if can?(current_user, :admin_tag, @project)
= link_to new_project_tag_path(@project), class: 'btn btn-success new-tag-btn' do = link_to new_project_tag_path(@project), class: 'btn btn-success new-tag-btn' do
= s_('TagsPage|New tag') = s_('TagsPage|New tag')
= link_to project_tags_path(@project, rss_url_options), title: _("Tags feed"), class: 'btn d-none d-sm-inline-block has-tooltip' do = link_to project_tags_path(@project, rss_url_options), title: _("Tags feed"), class: 'btn d-none d-sm-inline-block has-tooltip' do
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
= s_("TagsPage|Can't find HEAD commit for this tag") = s_("TagsPage|Can't find HEAD commit for this tag")
.nav-controls .nav-controls
- if can?(current_user, :push_code, @project) - if can?(current_user, :admin_tag, @project)
= link_to edit_project_tag_release_path(@project, @tag.name), class: 'btn btn-edit controls-item has-tooltip', title: s_('TagsPage|Edit release notes') do = link_to edit_project_tag_release_path(@project, @tag.name), class: 'btn btn-edit controls-item has-tooltip', title: s_('TagsPage|Edit release notes') do
= icon("pencil") = icon("pencil")
= link_to project_tree_path(@project, @tag.name), class: 'btn controls-item has-tooltip', title: s_('TagsPage|Browse files') do = link_to project_tree_path(@project, @tag.name), class: 'btn controls-item has-tooltip', title: s_('TagsPage|Browse files') do
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
= icon('history') = icon('history')
.btn-container.controls-item .btn-container.controls-item
= render 'projects/buttons/download', project: @project, ref: @tag.name = render 'projects/buttons/download', project: @project, ref: @tag.name
- if can?(current_user, :push_code, @project) && can?(current_user, :admin_project, @project) - if can?(current_user, :admin_tag, @project)
.btn-container.controls-item-full .btn-container.controls-item-full
= link_to project_tag_path(@project, @tag.name), class: "btn btn-remove remove-row has-tooltip #{protected_tag?(@project, @tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), method: :delete, data: { confirm: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: @tag.name } } do = link_to project_tag_path(@project, @tag.name), class: "btn btn-remove remove-row has-tooltip #{protected_tag?(@project, @tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), method: :delete, data: { confirm: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: @tag.name } } do
%i.fa.fa-trash-o %i.fa.fa-trash-o
......
...@@ -30,15 +30,17 @@ class PostReceive ...@@ -30,15 +30,17 @@ class PostReceive
private private
def identify_user(post_received)
post_received.identify.tap do |user|
log("Triggered hook for non-existing user \"#{post_received.identifier}\"") unless user
end
end
def process_project_changes(post_received) def process_project_changes(post_received)
changes = [] changes = []
refs = Set.new refs = Set.new
@user = post_received.identify user = identify_user(post_received)
return false unless user
unless @user
log("Triggered hook for non-existing user \"#{post_received.identifier}\"")
return false
end
post_received.enum_for(:changes_refs).with_index do |(oldrev, newrev, ref), index| post_received.enum_for(:changes_refs).with_index do |(oldrev, newrev, ref), index|
service_klass = service_klass =
...@@ -51,7 +53,7 @@ class PostReceive ...@@ -51,7 +53,7 @@ class PostReceive
if service_klass if service_klass
service_klass.new( service_klass.new(
post_received.project, post_received.project,
@user, user,
oldrev: oldrev, oldrev: oldrev,
newrev: newrev, newrev: newrev,
ref: ref, ref: ref,
...@@ -64,7 +66,7 @@ class PostReceive ...@@ -64,7 +66,7 @@ class PostReceive
refs << ref refs << ref
end end
after_project_changes_hooks(post_received, @user, refs.to_a, changes) after_project_changes_hooks(post_received, user, refs.to_a, changes)
end end
def after_project_changes_hooks(post_received, user, refs, changes) def after_project_changes_hooks(post_received, user, refs, changes)
...@@ -76,6 +78,11 @@ class PostReceive ...@@ -76,6 +78,11 @@ class PostReceive
post_received.project.touch(:last_activity_at, :last_repository_updated_at) post_received.project.touch(:last_activity_at, :last_repository_updated_at)
post_received.project.wiki.repository.expire_statistics_caches post_received.project.wiki.repository.expire_statistics_caches
ProjectCacheWorker.perform_async(post_received.project.id, [], [:wiki_size]) ProjectCacheWorker.perform_async(post_received.project.id, [], [:wiki_size])
user = identify_user(post_received)
return false unless user
::Git::WikiPushService.new(post_received.project, user, changes: post_received.enum_for(:changes_refs)).execute
end end
def log(message) def log(message)
......
---
title: Fix Container Scanning job timeout when using the kubernetes executor
merge_request: 29706
author:
type: fixed
---
title: Allow developers to delete tags
merge_request: 29668
author:
type: changed
---
title: Add token_encrypted column to operations_feature_flags_clients table
merge_request:
author:
type: other
---
title: Indent collapsible sections
merge_request: 29804
author:
type: other
---
title: Knative version bump 0.5 -> 0.6
merge_request: 28798
author: Chris Baumbauer
type: changed
# frozen_string_literal: true
class AddWikiColumnsToIndexStatus < ActiveRecord::Migration[5.1]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :index_statuses, :last_wiki_commit, :binary
add_column :index_statuses, :wiki_indexed_at, :datetime_with_timezone
end
end
...@@ -1572,6 +1572,8 @@ ActiveRecord::Schema.define(version: 20190613030606) do ...@@ -1572,6 +1572,8 @@ ActiveRecord::Schema.define(version: 20190613030606) do
t.string "last_commit" t.string "last_commit"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.binary "last_wiki_commit"
t.datetime_with_timezone "wiki_indexed_at"
t.index ["project_id"], name: "index_index_statuses_on_project_id", unique: true, using: :btree t.index ["project_id"], name: "index_index_statuses_on_project_id", unique: true, using: :btree
end end
......
...@@ -149,7 +149,7 @@ Component statuses are linked to configuration documentation for each component. ...@@ -149,7 +149,7 @@ Component statuses are linked to configuration documentation for each component.
| [PgBouncer Exporter](#pgbouncer-exporter) | Prometheus endpoint with PgBouncer metrics | [][pgbouncer-exporter-omnibus] | [][pgbouncer-exporter-charts] | [][pgbouncer-exporter-charts] | [](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE | | [PgBouncer Exporter](#pgbouncer-exporter) | Prometheus endpoint with PgBouncer metrics | [][pgbouncer-exporter-omnibus] | [][pgbouncer-exporter-charts] | [][pgbouncer-exporter-charts] | [](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
| [GitLab Monitor](#gitlab-monitor) | Generates a variety of GitLab metrics | [][gitlab-monitor-omnibus] | [][gitab-monitor-charts] | [][gitab-monitor-charts] | [](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE | | [GitLab Monitor](#gitlab-monitor) | Generates a variety of GitLab metrics | [][gitlab-monitor-omnibus] | [][gitab-monitor-charts] | [][gitab-monitor-charts] | [](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
| [Node Exporter](#node-exporter) | Prometheus endpoint with system metrics | [][node-exporter-omnibus] | [][node-exporter-charts] | [][node-exporter-charts] | [](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE | | [Node Exporter](#node-exporter) | Prometheus endpoint with system metrics | [][node-exporter-omnibus] | [][node-exporter-charts] | [][node-exporter-charts] | [](https://about.gitlab.com/handbook/engineering/monitoring/) | ❌ | ❌ | CE & EE |
| [Mattermost](#mattermost) | Open-source Slack alternative | [][mattermost-omnibus] | [][mattermost-charts] | [][mattermost-charts] | [](../user/project/integrations/mattermost_slash_commands.md#manual-configuration), [](../user/project/integrations/mattermost.html) | ❌ | ❌ | CE & EE | | [Mattermost](#mattermost) | Open-source Slack alternative | [][mattermost-omnibus] | [][mattermost-charts] | [][mattermost-charts] | [](../user/project/integrations/mattermost.md) | ❌ | ❌ | CE & EE |
| [MinIO](#minio) | Object storage service | [][minio-omnibus] | [][minio-charts] | [][minio-charts] | [](https://about.gitlab.com/handbook/engineering/infrastructure/production-architecture/#storage-architecture) | ❌ | [][minio-gdk] | CE & EE | | [MinIO](#minio) | Object storage service | [][minio-omnibus] | [][minio-charts] | [][minio-charts] | [](https://about.gitlab.com/handbook/engineering/infrastructure/production-architecture/#storage-architecture) | ❌ | [][minio-gdk] | CE & EE |
| [Runner](#gitlab-runner) | Executes GitLab CI jobs | [][runner-omnibus] | [][runner-charts] | [][runner-charts] | [](../user/gitlab_com/index.md#shared-runners) | [][runner-source] | [][runner-gdk] | CE & EE | | [Runner](#gitlab-runner) | Executes GitLab CI jobs | [][runner-omnibus] | [][runner-charts] | [][runner-charts] | [](../user/gitlab_com/index.md#shared-runners) | [][runner-source] | [][runner-gdk] | CE & EE |
| [Database Migrations](#database-migrations) | Database migrations | [][database-migrations-omnibus] | [][database-migrations-charts] | [][database-migrations-charts] | ✅ | [][database-migrations-source] | ✅ | CE & EE | | [Database Migrations](#database-migrations) | Database migrations | [][database-migrations-omnibus] | [][database-migrations-charts] | [][database-migrations-charts] | ✅ | [][database-migrations-source] | ✅ | CE & EE |
......
...@@ -77,6 +77,9 @@ Or: ...@@ -77,6 +77,9 @@ Or:
hello = _("Hello world!") hello = _("Hello world!")
``` ```
NOTE: **Note:** Messages in the API (`lib/api/` or `app/graphql`) do
not need to be externalised.
### HAML files ### HAML files
Given the following content in HAML: Given the following content in HAML:
......
...@@ -4,6 +4,10 @@ comments: false ...@@ -4,6 +4,10 @@ comments: false
# Upgrading Community Edition and Enterprise Edition from source # Upgrading Community Edition and Enterprise Edition from source
NOTE: **Note:**
Users wishing to upgrade to 12.0.0 will have to take some extra steps. See the
version specific upgrade instructions for 12.0.0 for more details.
Make sure you view this update guide from the branch (version) of GitLab you Make sure you view this update guide from the branch (version) of GitLab you
would like to install (e.g., `11.8`. You can select the version in the version would like to install (e.g., `11.8`. You can select the version in the version
dropdown at the top left corner of GitLab (below the menu bar). dropdown at the top left corner of GitLab (below the menu bar).
...@@ -404,6 +408,20 @@ Example: ...@@ -404,6 +408,20 @@ Example:
Additional instructions here. Additional instructions here.
--> -->
### 12.0.0
In 12.0.0 we made various database related changes. These changes require that
users first upgrade to the latest 11.11 patch release. Once upgraded to 11.11.x,
users can upgrade to 12.x. Failure to do so may result in database migrations
not being applied, which could lead to application errors.
Example 1: you are currently using GitLab 11.11.3, which is the latest patch
release for 11.11.x. You can upgrade as usual to 12.0.0, 12.1.0, etc.
Example 2: you are currently using a version of GitLab 10.x. To upgrade, first
upgrade to 11.11.3. Once upgraded to 11.11.3 you can safely upgrade to 12.0.0
or future versions.
## Things went south? Revert to previous version ## Things went south? Revert to previous version
### 1. Revert the code to the previous version ### 1. Revert the code to the previous version
......
...@@ -89,10 +89,8 @@ are enabled. ...@@ -89,10 +89,8 @@ are enabled.
![Project admin info](img/admin_project_quota_view.png) ![Project admin info](img/admin_project_quota_view.png)
When the pipeline minutes quota for a group is set to a value different than 0, You can see an overview of the pipeline minutes quota of all projects of
the **Pipelines quota** page is available to the group page settings list. a group in the **Usage Quotas** page available to the group page settings list.
You can see there an overview of the pipeline minutes quota of all projects of
the group.
![Group pipelines quota](img/group_pipelines_quota.png) ![Group pipelines quota](img/group_pipelines_quota.png)
......
...@@ -381,6 +381,14 @@ Define project templates at a group level by setting a group as the template sou ...@@ -381,6 +381,14 @@ Define project templates at a group level by setting a group as the template sou
for the group. **[STARTER ONLY]** for the group. **[STARTER ONLY]**
- **Pipelines quota**: Keep track of the [pipeline quota](../admin_area/settings/continuous_integration.md) for the group. - **Pipelines quota**: Keep track of the [pipeline quota](../admin_area/settings/continuous_integration.md) for the group.
#### Storage usage quota **[STARTER]**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/13294) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.0.
A group owner can check the aggregated storage usage for all the project in a group, sub-groups included, in the **Storage** tab of the **Usage Quotas** page available to the group page settings list.
![Group storage usage quota](img/group_storage_usage_quota.png)
## User contribution analysis **[STARTER]** ## User contribution analysis **[STARTER]**
With [GitLab Contribution Analytics](contribution_analytics/index.md), With [GitLab Contribution Analytics](contribution_analytics/index.md),
......
...@@ -95,6 +95,7 @@ The following table depicts the various user permission levels in a project. ...@@ -95,6 +95,7 @@ The following table depicts the various user permission levels in a project.
| Dismiss vulnerability **[ULTIMATE]** | | | ✓ | ✓ | ✓ | | Dismiss vulnerability **[ULTIMATE]** | | | ✓ | ✓ | ✓ |
| Apply code change suggestions | | | ✓ | ✓ | ✓ | | Apply code change suggestions | | | ✓ | ✓ | ✓ |
| Create and edit wiki pages | | | ✓ | ✓ | ✓ | | Create and edit wiki pages | | | ✓ | ✓ | ✓ |
| Rewrite/remove Git tags | | | ✓ | ✓ | ✓ |
| Use environment terminals | | | | ✓ | ✓ | | Use environment terminals | | | | ✓ | ✓ |
| Run Web IDE's Interactive Web Terminals **[ULTIMATE ONLY]** | | | | ✓ | ✓ | | Run Web IDE's Interactive Web Terminals **[ULTIMATE ONLY]** | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ | | Add new team members | | | | ✓ | ✓ |
...@@ -102,7 +103,6 @@ The following table depicts the various user permission levels in a project. ...@@ -102,7 +103,6 @@ The following table depicts the various user permission levels in a project.
| Push to protected branches | | | | ✓ | ✓ | | Push to protected branches | | | | ✓ | ✓ |
| Turn on/off protected branch push for devs | | | | ✓ | ✓ | | Turn on/off protected branch push for devs | | | | ✓ | ✓ |
| Enable/disable tag protections | | | | ✓ | ✓ | | Enable/disable tag protections | | | | ✓ | ✓ |
| Rewrite/remove Git tags | | | | ✓ | ✓ |
| Edit project | | | | ✓ | ✓ | | Edit project | | | | ✓ | ✓ |
| Add deploy keys to project | | | | ✓ | ✓ | | Add deploy keys to project | | | | ✓ | ✓ |
| Configure project hooks | | | | ✓ | ✓ | | Configure project hooks | | | | ✓ | ✓ |
......
# File Locking **[PREMIUM]** # File Locking **[PREMIUM]**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/440) in [GitLab Premium](https://about.gitlab.com/pricing/) 8.9. > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/440) in [GitLab Premium](https://about.gitlab.com/pricing/) 8.9.
> - This feature needs to have a license with the "File Lock" option enabled.
> - If you are using Premium but you don't see the "Lock" button, ask your GitLab administrator.
File Locking helps you avoid merge conflicts and better manage your binary files. File Locking helps you avoid merge conflicts and better manage your binary files.
Lock any file or directory, make your changes, and then unlock it so another Lock any file or directory, make your changes, and then unlock it so another
...@@ -30,12 +28,51 @@ The file locking feature is useful in situations when: ...@@ -30,12 +28,51 @@ The file locking feature is useful in situations when:
Locked directories are locked recursively, which means that everything that Locked directories are locked recursively, which means that everything that
lies under them is also locked. lies under them is also locked.
## Locking a file or a directory
NOTE: **Note:**
Locking only works for the default branch you have set in the project's settings
(usually `master`).
To lock a file:
1. Navigate to your project's **Repository > Files**.
1. Pick the file you want to lock.
1. Click the "Lock" button.
![Locking file](img/file_lock.png)
To lock an entire directory, look for the "Lock" link next to "History".
After you lock a file or directory, it will appear as locked in the repository
view.
![Repository view](img/file_lock_repository_view.png)
Once locked, any merge request to the default branch will fail
to merge until the file becomes unlocked.
## Unlocking a file or a directory
To unlock a file or a directory, follow the same procedure as when you locked
them. For a detailed view of every existing lock, see the next section on
"Viewing and managing existing locks".
You can unlock a file that yourself or someone else previously locked as long
as you have Maintainer or above [permissions](../permissions.md) to the project.
## Viewing and managing existing locks
To view or manage every existing lock, navigate to the
**Project > Repository > Locked Files** area. There, you can view all existing
locks and [remove the ones you have permission for](#permissions-on-file-locking).
## Permissions on file locking ## Permissions on file locking
The user that locks a file or directory **is the only one** that can edit and The user that locks a file or directory **is the only one** that can edit and
push their changes back to the repository where the locked objects are located. push their changes back to the repository where the locked objects are located.
Locks can be created by any person who has [push access](../../user/permissions.md) to the repository; i.e., Locks can be created by any person who has [push access](../permissions.md) to the repository; i.e.,
Developer and higher level, and can be removed solely by their author and any Developer and higher level, and can be removed solely by their author and any
user with Maintainer permissions and above. user with Maintainer permissions and above.
...@@ -61,41 +98,3 @@ accepts a merge request, an error message will appear stating that the file ...@@ -61,41 +98,3 @@ accepts a merge request, an error message will appear stating that the file
is locked. is locked.
![Merge request error message](img/file_lock_merge_request_error_message.png) ![Merge request error message](img/file_lock_merge_request_error_message.png)
## Locking a file or a directory
>**Note:**
Locking only works for the default branch you have set in the project's settings
(usually `master`).
To lock a file, navigate to the repository tree under the **Repository > Files** tab,
pick the file you want to lock and hit the "Lock" button.
![Locking file](img/file_lock.png)
---
To lock an entire directory, look for the "Lock" link next to "History".
![Locking directory](img/file_lock_folders.png)
---
After you lock a file or directory, it will appear as locked in the repository
view.
![Repository view](img/file_lock_repository_view.png)
## Unlocking a file or a directory
To unlock a file or a directory, follow the same procedure as when you locked
them. For a detailed view of every existing lock, see the next section on
"Viewing and managing existing locks".
## Viewing and managing existing locks
To view or manage every existing lock, navigate to the
**Project > Repository > Locked Files** area. There, you can view all existing
locks and [remove the ones you have permission for](#permissions-on-file-locking).
![Locked Files](img/file_lock_list.png)
doc/user/project/img/file_lock.png

26.3 KB | W: | H:

doc/user/project/img/file_lock.png

45.2 KB | W: | H:

doc/user/project/img/file_lock.png
doc/user/project/img/file_lock.png
doc/user/project/img/file_lock.png
doc/user/project/img/file_lock.png
  • 2-up
  • Swipe
  • Onion skin
# Mattermost Notifications Service # Mattermost Notifications Service
The Mattermost Notifications Service allows your GitLab project to send events (e.g., `issue created`) to your existing Mattermost team as notifications. This requires configurations in both Mattermost and GitLab.
You can also use Mattermost slash commands to control GitLab inside Mattermost. This is the separately configured [Mattermost slash commands](mattermost_slash_commands.md).
## On Mattermost ## On Mattermost
To enable Mattermost integration you must create an incoming webhook integration: To enable Mattermost integration you must create an incoming webhook integration:
......
...@@ -6,6 +6,9 @@ Mattermost commands give users an extra interface to perform common operations ...@@ -6,6 +6,9 @@ Mattermost commands give users an extra interface to perform common operations
from the chat environment. This allows one to, for example, create an issue as from the chat environment. This allows one to, for example, create an issue as
soon as the idea was discussed in Mattermost. soon as the idea was discussed in Mattermost.
GitLab can also send events (e.g., `issue created`) to Mattermost as notifications.
This is the separately configured [Mattermost Notifications Service](mattermost.md).
## Prerequisites ## Prerequisites
Mattermost 3.4 and up is required. Mattermost 3.4 and up is required.
......
...@@ -149,6 +149,12 @@ The plain text title and description of the issue fill the top center of the iss ...@@ -149,6 +149,12 @@ The plain text title and description of the issue fill the top center of the iss
The description fully supports [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm), The description fully supports [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm),
allowing many formatting options. allowing many formatting options.
##### 16.1 Zoom Call Links
Including a link to a Zoom call in the description of an issue will result in a "Join Zoom meeting" button at the top of the issue, just under the header. To remove the button, edit the description and remove the Zoom call link.
![Link Zoom Call in Issue](img/link_zoom_call_in_issue.png)
#### 17. Mentions #### 17. Mentions
You can mention a user or a group present in your GitLab instance with `@username` or You can mention a user or a group present in your GitLab instance with `@username` or
......
...@@ -235,6 +235,10 @@ module API ...@@ -235,6 +235,10 @@ module API
authorize! :push_code, user_project authorize! :push_code, user_project
end end
def authorize_admin_tag
authorize! :admin_tag, user_project
end
def authorize_admin_project def authorize_admin_project
authorize! :admin_project, user_project authorize! :admin_project, user_project
end end
......
...@@ -55,7 +55,7 @@ module API ...@@ -55,7 +55,7 @@ module API
optional :release_description, type: String, desc: 'Specifying release notes stored in the GitLab database (deprecated in GitLab 11.7)' optional :release_description, type: String, desc: 'Specifying release notes stored in the GitLab database (deprecated in GitLab 11.7)'
end end
post ':id/repository/tags' do post ':id/repository/tags' do
authorize_push_project authorize_admin_tag
result = ::Tags::CreateService.new(user_project, current_user) result = ::Tags::CreateService.new(user_project, current_user)
.execute(params[:tag_name], params[:ref], params[:message]) .execute(params[:tag_name], params[:ref], params[:message])
...@@ -87,7 +87,7 @@ module API ...@@ -87,7 +87,7 @@ module API
requires :tag_name, type: String, desc: 'The name of the tag' requires :tag_name, type: String, desc: 'The name of the tag'
end end
delete ':id/repository/tags/:tag_name', requirements: TAG_ENDPOINT_REQUIREMENTS do delete ':id/repository/tags/:tag_name', requirements: TAG_ENDPOINT_REQUIREMENTS do
authorize_push_project authorize_admin_tag
tag = user_project.repository.find_tag(params[:tag_name]) tag = user_project.repository.find_tag(params[:tag_name])
not_found!('Tag') unless tag not_found!('Tag') unless tag
......
...@@ -19,7 +19,7 @@ module Gitlab ...@@ -19,7 +19,7 @@ module Gitlab
return unless tag_name return unless tag_name
logger.log_timed(LOG_MESSAGES[:tag_checks]) do logger.log_timed(LOG_MESSAGES[:tag_checks]) do
if tag_exists? && user_access.cannot_do_action?(:admin_project) if tag_exists? && user_access.cannot_do_action?(:admin_tag)
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:change_existing_tags] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:change_existing_tags]
end end
end end
......
...@@ -312,7 +312,7 @@ module Gitlab ...@@ -312,7 +312,7 @@ module Gitlab
if @sections.any? if @sections.any?
css_classes << "section" css_classes << "section"
css_classes << "js-section-header" if @lineno_in_section == 0 css_classes << "js-section-header section-header" if @lineno_in_section == 0
css_classes += sections.map { |section| "js-s-#{section}" } css_classes += sections.map { |section| "js-s-#{section}" }
end end
......
...@@ -30,7 +30,7 @@ container_scanning: ...@@ -30,7 +30,7 @@ container_scanning:
services: services:
- docker:stable-dind - docker:stable-dind
script: script:
- if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then { export DOCKER_SERVICE="localhost" ; export DOCKER_HOST="tcp://${DOCKER_SERVICE}:2375" ; } fi - if [[ -n "$KUBERNETES_PORT" ]]; then { export DOCKER_SERVICE="localhost" ; export DOCKER_HOST="tcp://${DOCKER_SERVICE}:2375" ; } fi
- | - |
if [[ -n "$CI_REGISTRY_USER" ]]; then if [[ -n "$CI_REGISTRY_USER" ]]; then
echo "Logging to GitLab Container Registry with CI credentials..." echo "Logging to GitLab Container Registry with CI credentials..."
......
...@@ -45,7 +45,7 @@ module Gitlab ...@@ -45,7 +45,7 @@ module Gitlab
if protected?(ProtectedTag, project, ref) if protected?(ProtectedTag, project, ref)
protected_tag_accessible_to?(ref, action: :create) protected_tag_accessible_to?(ref, action: :create)
else else
user.can?(:push_code, project) user.can?(:admin_tag, project)
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
module QA module QA
# Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/94 context 'Create' do
context 'Create', :quarantine do
describe 'Merge request creation from fork' do describe 'Merge request creation from fork' do
it 'user forks a project, submits a merge request and maintainer merges it' do it 'user forks a project, submits a merge request and maintainer merges it' do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
......
# frozen_string_literal: true # frozen_string_literal: true
module QA module QA
# Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/93 context 'Create' do
context 'Create', :quarantine do
describe 'Merge request squashing' do describe 'Merge request squashing' do
it 'user squashes commits while merging' do it 'user squashes commits while merging' do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
......
# frozen_string_literal: true # frozen_string_literal: true
module QA module QA
# Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/62 context 'Create' do
context 'Create', :quarantine do
describe 'Create, list, and delete branches via web' do describe 'Create, list, and delete branches via web' do
master_branch = 'master' master_branch = 'master'
second_branch = 'second-branch' second_branch = 'second-branch'
......
require 'spec_helper' require 'spec_helper'
describe 'Maintainer creates tag' do describe 'Developer creates tag' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository, namespace: user.namespace) } let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: group) }
before do before do
project.add_maintainer(user) project.add_developer(user)
sign_in(user) sign_in(user)
end end
......
require 'spec_helper' require 'spec_helper'
describe 'Maintainer deletes tag' do describe 'Developer deletes tag' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository, namespace: user.namespace) } let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: group) }
before do before do
project.add_maintainer(user) project.add_developer(user)
sign_in(user) sign_in(user)
visit project_tags_path(project) visit project_tags_path(project)
end end
......
require 'spec_helper' require 'spec_helper'
describe 'Maintainer updates tag' do describe 'Developer updates tag' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository, namespace: user.namespace) } let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: group) }
before do before do
project.add_maintainer(user) project.add_developer(user)
sign_in(user) sign_in(user)
visit project_tags_path(project) visit project_tags_path(project)
end end
......
require 'spec_helper' require 'spec_helper'
describe 'Maintainer views tags' do describe 'Developer views tags' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:group) { create(:group) }
before do before do
project.add_maintainer(user) project.add_maintainer(user)
...@@ -9,7 +10,7 @@ describe 'Maintainer views tags' do ...@@ -9,7 +10,7 @@ describe 'Maintainer views tags' do
end end
context 'when project has no tags' do context 'when project has no tags' do
let(:project) { create(:project_empty_repo) } let(:project) { create(:project_empty_repo, namespace: group) }
before do before do
visit project_path(project) visit project_path(project)
...@@ -25,7 +26,7 @@ describe 'Maintainer views tags' do ...@@ -25,7 +26,7 @@ describe 'Maintainer views tags' do
end end
context 'when project has tags' do context 'when project has tags' do
let(:project) { create(:project, :repository, namespace: user.namespace) } let(:project) { create(:project, :repository, namespace: group) }
let(:repository) { project.repository } let(:repository) { project.repository }
before do before do
......
...@@ -8,9 +8,8 @@ describe Gitlab::Checks::TagCheck do ...@@ -8,9 +8,8 @@ describe Gitlab::Checks::TagCheck do
describe '#validate!' do describe '#validate!' do
let(:ref) { 'refs/tags/v1.0.0' } let(:ref) { 'refs/tags/v1.0.0' }
it 'raises an error' do it 'raises an error when user does not have access' do
allow(user_access).to receive(:can_do_action?).with(:push_code).and_return(true) allow(user_access).to receive(:can_do_action?).with(:admin_tag).and_return(false)
expect(user_access).to receive(:can_do_action?).with(:admin_project).and_return(false)
expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to change existing tags on this project.') expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to change existing tags on this project.')
end end
......
...@@ -231,8 +231,8 @@ describe Gitlab::Ci::Ansi2html do ...@@ -231,8 +231,8 @@ describe Gitlab::Ci::Ansi2html do
it 'prints light red' do it 'prints light red' do
text = "#{section_start}\e[91mHello\e[0m\n#{section_end}" text = "#{section_start}\e[91mHello\e[0m\n#{section_end}"
header = %{<span class="term-fg-l-red section js-section-header js-s-#{class_name(section_name)}">Hello</span>} header = %{<span class="term-fg-l-red section js-section-header section-header js-s-#{class_name(section_name)}">Hello</span>}
line_break = %{<span class="section js-section-header js-s-#{class_name(section_name)}"></span><br/>} line_break = %{<span class="section js-section-header section-header js-s-#{class_name(section_name)}"></span><br/>}
line = %{<span class="section line s_#{class_name(section_name)}"></span>} line = %{<span class="section line s_#{class_name(section_name)}"></span>}
empty_line = %{<span class="section js-s-#{class_name(section_name)}"></span>} empty_line = %{<span class="section js-s-#{class_name(section_name)}"></span>}
html = "#{section_start_html}#{header}#{line_break}#{line}#{empty_line}#{section_end_html}" html = "#{section_start_html}#{header}#{line_break}#{line}#{empty_line}#{section_end_html}"
......
...@@ -831,7 +831,7 @@ describe Gitlab::GitAccess do ...@@ -831,7 +831,7 @@ describe Gitlab::GitAccess do
push_master: true, push_master: true,
push_protected_branch: false, push_protected_branch: false,
push_remove_protected_branch: false, push_remove_protected_branch: false,
push_tag: false, push_tag: true,
push_new_tag: true, push_new_tag: true,
push_all: false, push_all: false,
merge_into_protected_branch: false merge_into_protected_branch: false
......
...@@ -129,7 +129,7 @@ describe Ci::PipelineSchedule do ...@@ -129,7 +129,7 @@ describe Ci::PipelineSchedule do
let(:pipeline_schedule) { create(:ci_pipeline_schedule, :every_minute) } let(:pipeline_schedule) { create(:ci_pipeline_schedule, :every_minute) }
it "updates next_run_at to the sidekiq worker's execution time" do it "updates next_run_at to the sidekiq worker's execution time" do
Timecop.freeze do Timecop.freeze(2019, 06, 19, 12, 00) do
expect(pipeline_schedule.next_run_at).to eq(cron_worker_next_run_at) expect(pipeline_schedule.next_run_at).to eq(cron_worker_next_run_at)
end end
end end
......
...@@ -112,7 +112,7 @@ describe Clusters::Applications::Knative do ...@@ -112,7 +112,7 @@ describe Clusters::Applications::Knative do
subject { knative.install_command } subject { knative.install_command }
it 'is initialized with latest version' do it 'is initialized with latest version' do
expect(subject.version).to eq('0.5.0') expect(subject.version).to eq('0.6.0')
end end
it_behaves_like 'a command' it_behaves_like 'a command'
......
...@@ -36,7 +36,7 @@ describe ProjectPolicy do ...@@ -36,7 +36,7 @@ describe ProjectPolicy do
let(:developer_permissions) do let(:developer_permissions) do
%i[ %i[
admin_milestone admin_merge_request update_merge_request create_commit_status admin_tag admin_milestone admin_merge_request update_merge_request create_commit_status
update_commit_status create_build update_build create_pipeline update_commit_status create_build update_build create_pipeline
update_pipeline create_merge_request_from create_wiki push_code update_pipeline create_merge_request_from create_wiki push_code
resolve_note create_container_image update_container_image destroy_container_image resolve_note create_container_image update_container_image destroy_container_image
......
...@@ -10,7 +10,7 @@ describe API::Tags do ...@@ -10,7 +10,7 @@ describe API::Tags do
let(:current_user) { nil } let(:current_user) { nil }
before do before do
project.add_maintainer(user) project.add_developer(user)
end end
describe 'GET /projects/:id/repository/tags' do describe 'GET /projects/:id/repository/tags' do
......
...@@ -17,6 +17,7 @@ RSpec.shared_examples 'archived project policies' do ...@@ -17,6 +17,7 @@ RSpec.shared_examples 'archived project policies' do
upload_file upload_file
resolve_note resolve_note
award_emoji award_emoji
admin_tag
] ]
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment