Commit 9e7002c9 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-to-ee' into 'master'

CE Upstream - Monday

See merge request !2244
parents de5170d2 fefa5515
...@@ -12,6 +12,12 @@ ...@@ -12,6 +12,12 @@
&.readme-holder { &.readme-holder {
margin: $gl-padding 0; margin: $gl-padding 0;
&.limited-width-container .file-content {
max-width: $limited-layout-width-sm;
margin-left: auto;
margin-right: auto;
}
} }
table { table {
......
...@@ -53,7 +53,7 @@ body { ...@@ -53,7 +53,7 @@ body {
} }
&.limit-container-width-sm { &.limit-container-width-sm {
max-width: 790px; max-width: $limited-layout-width-sm;
} }
} }
......
...@@ -161,6 +161,7 @@ $progress-color: #c0392b; ...@@ -161,6 +161,7 @@ $progress-color: #c0392b;
$header-height: 50px; $header-height: 50px;
$fixed-layout-width: 1280px; $fixed-layout-width: 1280px;
$limited-layout-width: 990px; $limited-layout-width: 990px;
$limited-layout-width-sm: 790px;
$gl-avatar-size: 40px; $gl-avatar-size: 40px;
$error-exclamation-point: $red-500; $error-exclamation-point: $red-500;
$border-radius-default: 3px; $border-radius-default: 3px;
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
.commit-box, .commit-box,
.info-well, .info-well,
.commit-ci-menu, .commit-ci-menu,
.files-changed { .files-changed,
.limited-header-width,
.limited-width-notes {
@extend .fixed-width-container; @extend .fixed-width-container;
} }
......
...@@ -15,7 +15,7 @@ module GroupsHelper ...@@ -15,7 +15,7 @@ module GroupsHelper
@has_group_title = true @has_group_title = true
full_title = '' full_title = ''
group.ancestors.each do |parent| group.ancestors.reverse.each do |parent|
full_title += link_to(simple_sanitize(parent.name), group_path(parent), class: 'group-path hidable') full_title += link_to(simple_sanitize(parent.name), group_path(parent), class: 'group-path hidable')
full_title += '<span class="hidable"> / </span>'.html_safe full_title += '<span class="hidable"> / </span>'.html_safe
end end
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
= icon('caret-down') = icon('caret-down')
.dropdown-menu-nav.dropdown-menu-align-right .dropdown-menu-nav.dropdown-menu-align-right
%ul %ul
- if @group - if @group&.persisted?
- create_group_project = can?(current_user, :create_projects, @group) - create_group_project = can?(current_user, :create_projects, @group)
- create_group_subgroup = can?(current_user, :create_subgroup, @group) - create_group_subgroup = can?(current_user, :create_subgroup, @group)
- if create_group_project || create_group_subgroup - if create_group_project || create_group_subgroup
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
%li.divider %li.divider
%li.dropdown-bold-header GitLab %li.dropdown-bold-header GitLab
- if @project && @project.persisted? - if @project&.persisted?
- create_project_issue = can?(current_user, :create_issue, @project) - create_project_issue = can?(current_user, :create_issue, @project)
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- create_project_snippet = can?(current_user, :create_project_snippet, @project) - create_project_snippet = can?(current_user, :create_project_snippet, @project)
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
= f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' } = f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' }
- if @user.external_email? - if @user.external_email?
= f.text_field :email, required: true, readonly: true, help: 'Your email address was automatically set based on your #{email_provider_label} account.' = f.text_field :email, required: true, readonly: true, help: "Your email address was automatically set based on your #{email_provider_label} account."
- else - else
= f.text_field :email, required: true, value: (@user.email unless @user.temp_oauth_email?), = f.text_field :email, required: true, value: (@user.email unless @user.temp_oauth_email?),
help: user_email_help_text(@user) help: user_email_help_text(@user)
......
- @no_container = true - @no_container = true
- container_class = !fluid_layout && diff_view == :inline ? 'container-limited' : '' - container_class = !fluid_layout && diff_view == :inline ? 'container-limited' : ''
- limited_container_width = fluid_layout || diff_view == :inline ? '' : 'limit-container-width' - limited_container_width = fluid_layout ? '' : 'limit-container-width'
- page_title "#{@commit.title} (#{@commit.short_id})", "Commits" - page_title "#{@commit.title} (#{@commit.short_id})", "Commits"
- page_description @commit.description - page_description @commit.description
= render "projects/commits/head" = render "projects/commits/head"
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
.block-connector .block-connector
= render "projects/diffs/diffs", diffs: @diffs, environment: @environment = render "projects/diffs/diffs", diffs: @diffs, environment: @environment
= render "shared/notes/notes_with_form", :autocomplete => true .limited-width-notes
- if can_collaborate_with_project? = render "shared/notes/notes_with_form", :autocomplete => true
- %w(revert cherry-pick).each do |type| - if can_collaborate_with_project?
= render "projects/commit/change", type: type, commit: @commit, title: @commit.title - %w(revert cherry-pick).each do |type|
= render "projects/commit/change", type: type, commit: @commit, title: @commit.title
- @content_class = "limit-container-width limited-inner-width-container" unless fluid_layout
- page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets" - page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
= render 'shared/snippets/header' = render 'shared/snippets/header'
...@@ -9,4 +10,4 @@ ...@@ -9,4 +10,4 @@
.row-content-block.top-block.content-component-block .row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true = render 'award_emoji/awards_block', awardable: @snippet, inline: true
#notes= render "shared/notes/notes_with_form", :autocomplete => true #notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => true
- if readme.rich_viewer - if readme.rich_viewer
%article.file-holder.readme-holder %article.file-holder.readme-holder{ class: ("limited-width-container" unless fluid_layout) }
.js-file-title.file-title .js-file-title.file-title
= blob_icon readme.mode, readme.name = blob_icon readme.mode, readme.name
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, readme.path)) do = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, readme.path)) do
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
.modal-content .modal-content
.modal-header .modal-header
%button.close{ type: "button", "aria-label": "close", data: { dismiss: "modal" } } %button.close{ type: "button", "aria-label": "close", data: { dismiss: "modal" } }
%span{ "aria-hidden": "true" } } × %span{ "aria-hidden": "true" } ×
%h4#custom-notifications-title.modal-title %h4#custom-notifications-title.modal-title
#{ _('Custom notification events') } #{ _('Custom notification events') }
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
- else - else
= render "snippets/actions" = render "snippets/actions"
.snippet-header .snippet-header.limited-header-width
%h2.snippet-title.prepend-top-0.append-bottom-0 %h2.snippet-title.prepend-top-0.append-bottom-0
= markdown_field(@snippet, :title) = markdown_field(@snippet, :title)
......
- @content_class = "limit-container-width limited-inner-width-container" unless fluid_layout
- page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets" - page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
= render 'shared/snippets/header' = render 'shared/snippets/header'
...@@ -9,4 +10,4 @@ ...@@ -9,4 +10,4 @@
.row-content-block.top-block.content-component-block .row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true = render 'award_emoji/awards_block', awardable: @snippet, inline: true
#notes= render "shared/notes/notes_with_form", :autocomplete => false #notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => false
---
title: Update QA Dockerfile to lock Chrome browser version
merge_request: 12071
author:
---
title: Limit commit & snippets comments width
merge_request:
author:
---
title: Don't match tilde and exclamation mark as part of requirements.txt package
name
merge_request:
author:
---
title: Fix reversed breadcrumb order for nested groups
merge_request: 12322
author:
---
title: Fix 500 when failing to create private group
merge_request: 12394
author:
---
title: Limit the width of the projects README text
merge_request:
author:
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
class SetMissingStageOnCiBuilds < ActiveRecord::Migration class SetMissingStageOnCiBuilds < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up def up
update_column_in_batches(:ci_builds, :stage, :test) do |table, query| update_column_in_batches(:ci_builds, :stage, :test) do |table, query|
query.where(table[:stage].eq(nil)) query.where(table[:stage].eq(nil))
......
...@@ -5,6 +5,8 @@ class DropAndReaddHasExternalWikiInProjects < ActiveRecord::Migration ...@@ -5,6 +5,8 @@ class DropAndReaddHasExternalWikiInProjects < ActiveRecord::Migration
# Set this constant to true if this migration requires downtime. # Set this constant to true if this migration requires downtime.
DOWNTIME = false DOWNTIME = false
disable_ddl_transaction!
def up def up
update_column_in_batches(:projects, :has_external_wiki, nil) do |table, query| update_column_in_batches(:projects, :has_external_wiki, nil) do |table, query|
query.where(table[:has_external_wiki].not_eq(nil)) query.where(table[:has_external_wiki].not_eq(nil))
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
class UpdateMirrorWhenEmptyImportUrlInProjects < ActiveRecord::Migration class UpdateMirrorWhenEmptyImportUrlInProjects < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false DOWNTIME = false
def change def change
......
...@@ -4,6 +4,8 @@ class SetConfidentialIssuesEventsOnWebhooks < ActiveRecord::Migration ...@@ -4,6 +4,8 @@ class SetConfidentialIssuesEventsOnWebhooks < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
disable_ddl_transaction!
def up def up
update_column_in_batches(:web_hooks, :confidential_issues_events, true) do |table, query| update_column_in_batches(:web_hooks, :confidential_issues_events, true) do |table, query|
query.where(table[:issues_events].eq(true)) query.where(table[:issues_events].eq(true))
......
...@@ -5,6 +5,8 @@ class AddTypeToLabels < ActiveRecord::Migration ...@@ -5,6 +5,8 @@ class AddTypeToLabels < ActiveRecord::Migration
DOWNTIME = true DOWNTIME = true
DOWNTIME_REASON = 'Labels will not work as expected until this migration is complete.' DOWNTIME_REASON = 'Labels will not work as expected until this migration is complete.'
disable_ddl_transaction!
def change def change
add_column :labels, :type, :string add_column :labels, :type, :string
......
...@@ -4,6 +4,8 @@ class MakeProjectOwnersMasters < ActiveRecord::Migration ...@@ -4,6 +4,8 @@ class MakeProjectOwnersMasters < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
disable_ddl_transaction!
def up def up
update_column_in_batches(:members, :access_level, 40) do |table, query| update_column_in_batches(:members, :access_level, 40) do |table, query|
query.where(table[:access_level].eq(50).and(table[:source_type].eq('Project'))) query.where(table[:access_level].eq(50).and(table[:source_type].eq('Project')))
......
...@@ -4,6 +4,8 @@ class RenameSlackAndMattermostNotificationServices < ActiveRecord::Migration ...@@ -4,6 +4,8 @@ class RenameSlackAndMattermostNotificationServices < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
disable_ddl_transaction!
def up def up
update_column_in_batches(:services, :type, 'SlackService') do |table, query| update_column_in_batches(:services, :type, 'SlackService') do |table, query|
query.where(table[:type].eq('SlackNotificationService')) query.where(table[:type].eq('SlackNotificationService'))
......
...@@ -19,13 +19,11 @@ class ConvertApplicationSettingsRepositorySizeLimitToBytes < ActiveRecord::Migra ...@@ -19,13 +19,11 @@ class ConvertApplicationSettingsRepositorySizeLimitToBytes < ActiveRecord::Migra
sql_expression = Arel::Nodes::SqlLiteral.new(bigint_string) sql_expression = Arel::Nodes::SqlLiteral.new(bigint_string)
connection.transaction do update_column_in_batches(:application_settings, :repository_size_limit, sql_expression) do |t, query|
update_column_in_batches(:application_settings, :repository_size_limit, sql_expression) do |t, query| query.where(t[:repository_size_limit_mb].not_eq(nil))
query.where(t[:repository_size_limit_mb].not_eq(nil))
end
remove_column :application_settings, :repository_size_limit_mb
end end
remove_column :application_settings, :repository_size_limit_mb
end end
def down def down
...@@ -36,12 +34,10 @@ class ConvertApplicationSettingsRepositorySizeLimitToBytes < ActiveRecord::Migra ...@@ -36,12 +34,10 @@ class ConvertApplicationSettingsRepositorySizeLimitToBytes < ActiveRecord::Migra
sql_expression = Arel::Nodes::SqlLiteral.new('repository_size_limit_bytes / 1024 / 1024') sql_expression = Arel::Nodes::SqlLiteral.new('repository_size_limit_bytes / 1024 / 1024')
connection.transaction do update_column_in_batches(:application_settings, :repository_size_limit, sql_expression) do |t, query|
update_column_in_batches(:application_settings, :repository_size_limit, sql_expression) do |t, query| query.where(t[:repository_size_limit_bytes].not_eq(nil))
query.where(t[:repository_size_limit_bytes].not_eq(nil))
end
remove_column :application_settings, :repository_size_limit_bytes
end end
remove_column :application_settings, :repository_size_limit_bytes
end end
end end
...@@ -19,13 +19,11 @@ class ConvertProjectsRepositorySizeLimitToBytes < ActiveRecord::Migration ...@@ -19,13 +19,11 @@ class ConvertProjectsRepositorySizeLimitToBytes < ActiveRecord::Migration
sql_expression = Arel::Nodes::SqlLiteral.new(bigint_string) sql_expression = Arel::Nodes::SqlLiteral.new(bigint_string)
connection.transaction do update_column_in_batches(:projects, :repository_size_limit, sql_expression) do |t, query|
update_column_in_batches(:projects, :repository_size_limit, sql_expression) do |t, query| query.where(t[:repository_size_limit_mb].not_eq(nil))
query.where(t[:repository_size_limit_mb].not_eq(nil))
end
remove_column :projects, :repository_size_limit_mb
end end
remove_column :projects, :repository_size_limit_mb
end end
def down def down
...@@ -36,12 +34,10 @@ class ConvertProjectsRepositorySizeLimitToBytes < ActiveRecord::Migration ...@@ -36,12 +34,10 @@ class ConvertProjectsRepositorySizeLimitToBytes < ActiveRecord::Migration
sql_expression = Arel::Nodes::SqlLiteral.new('repository_size_limit_bytes / 1024 / 1024') sql_expression = Arel::Nodes::SqlLiteral.new('repository_size_limit_bytes / 1024 / 1024')
connection.transaction do update_column_in_batches(:projects, :repository_size_limit, sql_expression) do |t, query|
update_column_in_batches(:projects, :repository_size_limit, sql_expression) do |t, query| query.where(t[:repository_size_limit_bytes].not_eq(nil))
query.where(t[:repository_size_limit_bytes].not_eq(nil))
end
remove_column :projects, :repository_size_limit_bytes
end end
remove_column :projects, :repository_size_limit_bytes
end end
end end
...@@ -19,13 +19,11 @@ class ConvertNamespacesRepositorySizeLimitToBytes < ActiveRecord::Migration ...@@ -19,13 +19,11 @@ class ConvertNamespacesRepositorySizeLimitToBytes < ActiveRecord::Migration
sql_expression = Arel::Nodes::SqlLiteral.new(bigint_string) sql_expression = Arel::Nodes::SqlLiteral.new(bigint_string)
connection.transaction do update_column_in_batches(:namespaces, :repository_size_limit, sql_expression) do |t, query|
update_column_in_batches(:namespaces, :repository_size_limit, sql_expression) do |t, query| query.where(t[:repository_size_limit_mb].not_eq(nil))
query.where(t[:repository_size_limit_mb].not_eq(nil))
end
remove_column :namespaces, :repository_size_limit_mb
end end
remove_column :namespaces, :repository_size_limit_mb
end end
def down def down
...@@ -36,12 +34,10 @@ class ConvertNamespacesRepositorySizeLimitToBytes < ActiveRecord::Migration ...@@ -36,12 +34,10 @@ class ConvertNamespacesRepositorySizeLimitToBytes < ActiveRecord::Migration
sql_expression = Arel::Nodes::SqlLiteral.new('repository_size_limit_bytes / 1024 / 1024') sql_expression = Arel::Nodes::SqlLiteral.new('repository_size_limit_bytes / 1024 / 1024')
connection.transaction do update_column_in_batches(:namespaces, :repository_size_limit, sql_expression) do |t, query|
update_column_in_batches(:namespaces, :repository_size_limit, sql_expression) do |t, query| query.where(t[:repository_size_limit_bytes].not_eq(nil))
query.where(t[:repository_size_limit_bytes].not_eq(nil))
end
remove_column :namespaces, :repository_size_limit_bytes
end end
remove_column :namespaces, :repository_size_limit_bytes
end end
end end
...@@ -4,6 +4,8 @@ class ResetRelativePositionForIssue < ActiveRecord::Migration ...@@ -4,6 +4,8 @@ class ResetRelativePositionForIssue < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
disable_ddl_transaction!
def up def up
update_column_in_batches(:issues, :relative_position, nil) do |table, query| update_column_in_batches(:issues, :relative_position, nil) do |table, query|
query.where(table[:relative_position].not_eq(nil)) query.where(table[:relative_position].not_eq(nil))
...@@ -11,5 +13,6 @@ class ResetRelativePositionForIssue < ActiveRecord::Migration ...@@ -11,5 +13,6 @@ class ResetRelativePositionForIssue < ActiveRecord::Migration
end end
def down def down
# noop
end end
end end
...@@ -7,6 +7,8 @@ class UpdateUploadPathsToSystem < ActiveRecord::Migration ...@@ -7,6 +7,8 @@ class UpdateUploadPathsToSystem < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
AFFECTED_MODELS = %w(User Project Note Namespace Appearance) AFFECTED_MODELS = %w(User Project Note Namespace Appearance)
disable_ddl_transaction!
def up def up
update_column_in_batches(:uploads, :path, replace_sql(arel_table[:path], base_directory, new_upload_dir)) do |_table, query| update_column_in_batches(:uploads, :path, replace_sql(arel_table[:path], base_directory, new_upload_dir)) do |_table, query|
query.where(uploads_to_switch_to_new_path) query.where(uploads_to_switch_to_new_path)
......
...@@ -7,6 +7,8 @@ class MigrateUserProjectView < ActiveRecord::Migration ...@@ -7,6 +7,8 @@ class MigrateUserProjectView < ActiveRecord::Migration
# Set this constant to true if this migration requires downtime. # Set this constant to true if this migration requires downtime.
DOWNTIME = false DOWNTIME = false
disable_ddl_transaction!
def up def up
update_column_in_batches(:users, :project_view, 2) do |table, query| update_column_in_batches(:users, :project_view, 2) do |table, query|
query.where(table[:project_view].eq(0)) query.where(table[:project_view].eq(0))
......
...@@ -3,6 +3,8 @@ class AddHeadPipelineForEachMergeRequest < ActiveRecord::Migration ...@@ -3,6 +3,8 @@ class AddHeadPipelineForEachMergeRequest < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
disable_ddl_transaction!
def up def up
disable_statement_timeout disable_statement_timeout
......
...@@ -155,7 +155,7 @@ Find more information about different Runners in the ...@@ -155,7 +155,7 @@ Find more information about different Runners in the
[Runners](../runners/README.md) documentation. [Runners](../runners/README.md) documentation.
You can find whether any Runners are assigned to your project by going to You can find whether any Runners are assigned to your project by going to
**Settings ➔ CI/CD Pipelines**. Setting up a Runner is easy and straightforward. The **Settings ➔ Pipelines**. Setting up a Runner is easy and straightforward. The
official Runner supported by GitLab is written in Go and its documentation official Runner supported by GitLab is written in Go and its documentation
can be found at <https://docs.gitlab.com/runner/>. can be found at <https://docs.gitlab.com/runner/>.
...@@ -168,7 +168,7 @@ Follow the links above to set up your own Runner or use a Shared Runner as ...@@ -168,7 +168,7 @@ Follow the links above to set up your own Runner or use a Shared Runner as
described in the next section. described in the next section.
Once the Runner has been set up, you should see it on the Runners page of your Once the Runner has been set up, you should see it on the Runners page of your
project, following **Settings ➔ CI/CD Pipelines**. project, following **Settings ➔ Pipelines**.
![Activated runners](img/runners_activated.png) ![Activated runners](img/runners_activated.png)
...@@ -181,7 +181,7 @@ These are special virtual machines that run on GitLab's infrastructure and can ...@@ -181,7 +181,7 @@ These are special virtual machines that run on GitLab's infrastructure and can
build any project. build any project.
To enable the **Shared Runners** you have to go to your project's To enable the **Shared Runners** you have to go to your project's
**Settings ➔ CI/CD Pipelines** and click **Enable shared runners**. **Settings ➔ Pipelines** and click **Enable shared runners**.
[Read more on Shared Runners](../runners/README.md). [Read more on Shared Runners](../runners/README.md).
......
...@@ -95,15 +95,16 @@ installation (e.g. the number of users, projects, etc). ...@@ -95,15 +95,16 @@ installation (e.g. the number of users, projects, etc).
We currently support the following databases: We currently support the following databases:
- PostgreSQL (highly recommended) - PostgreSQL (highly recommended)
- MySQL/MariaDB (doesn't support all features) - MySQL/MariaDB (strongly discouraged, not all GitLab features are supported, no support for [MySQL/MariaDB GTID](https://mariadb.com/kb/en/mariadb/gtid/))
We **highly recommend** the use of PostgreSQL instead of MySQL/MariaDB as not all We highly recommend the use of PostgreSQL instead of MySQL/MariaDB as not all
features of GitLab work with MySQL/MariaDB: features of GitLab work with MySQL/MariaDB:
1. MySQL support for subgroups was [dropped with GitLab 9.3][post]. 1. MySQL support for subgroups was [dropped with GitLab 9.3][post].
See [issue #30472][30472] for more information. See [issue #30472][30472] for more information.
1. GitLab Geo does [not support MySQL](https://docs.gitlab.com/ee/gitlab-geo/database.html#mysql-replication). 1. GitLab Geo does [not support MySQL](https://docs.gitlab.com/ee/gitlab-geo/database.html#mysql-replication).
1. [Zero downtime migrations][zero] do not work with MySQL 1. [Zero downtime migrations][zero] do not work with MySQL
1. We expect this list to grow over time.
Existing users using GitLab with MySQL/MariaDB are advised to Existing users using GitLab with MySQL/MariaDB are advised to
[migrate to PostgreSQL](../update/mysql_to_postgresql.md) instead. [migrate to PostgreSQL](../update/mysql_to_postgresql.md) instead.
......
# Pipelines settings # Pipelines settings
To reach the pipelines settings navigate to your project's To reach the pipelines settings navigate to your project's
**Settings ➔ CI/CD Pipelines**. **Settings ➔ Pipelines**.
The following settings can be configured per project. The following settings can be configured per project.
......
...@@ -222,6 +222,12 @@ module Gitlab ...@@ -222,6 +222,12 @@ module Gitlab
# #
# rubocop: disable Metrics/AbcSize # rubocop: disable Metrics/AbcSize
def update_column_in_batches(table, column, value) def update_column_in_batches(table, column, value)
if transaction_open?
raise 'update_column_in_batches can not be run inside a transaction, ' \
'you can disable transactions by calling disable_ddl_transaction! ' \
'in the body of your migration class'
end
table = Arel::Table.new(table) table = Arel::Table.new(table)
count_arel = table.project(Arel.star.count.as('count')) count_arel = table.project(Arel.star.count.as('count'))
......
...@@ -6,7 +6,7 @@ module Gitlab ...@@ -6,7 +6,7 @@ module Gitlab
private private
def link_dependencies def link_dependencies
link_regex(/^(?<name>(?![a-z+]+:)[^#.-][^ ><=;\[]+)/) do |name| link_regex(/^(?<name>(?![a-z+]+:)[^#.-][^ ><=~!;\[]+)/) do |name|
"https://pypi.python.org/pypi/#{name}" "https://pypi.python.org/pypi/#{name}"
end end
......
FROM ruby:2.3 FROM ruby:2.3
LABEL maintainer "Grzegorz Bizon <grzegorz@gitlab.com>" LABEL maintainer "Grzegorz Bizon <grzegorz@gitlab.com>"
ENV CHROME_VERSION 59.0.3071.109-1
ENV CHROME_DRIVER_VERSION 2.30
## ##
# Update APT sources and install some dependencies # Update APT sources and install some dependencies
# #
...@@ -8,15 +11,16 @@ RUN sed -i "s/httpredir.debian.org/ftp.us.debian.org/" /etc/apt/sources.list ...@@ -8,15 +11,16 @@ RUN sed -i "s/httpredir.debian.org/ftp.us.debian.org/" /etc/apt/sources.list
RUN apt-get update && apt-get install -y wget git unzip xvfb RUN apt-get update && apt-get install -y wget git unzip xvfb
## ##
# At this point Google Chrome Beta is 59 - first version with headless support # Install Google Chrome version with headless support
# #
RUN wget -q https://dl.google.com/linux/direct/google-chrome-beta_current_amd64.deb RUN curl -sS -L https://dl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN dpkg -i google-chrome-beta_current_amd64.deb; apt-get -fy install RUN echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list
RUN apt-get update -q && DEBIAN_FRONTEND=noninteractive apt-get install -y google-chrome-stable=$CHROME_VERSION
## ##
# Install chromedriver to make it work with Selenium # Install chromedriver to make it work with Selenium
# #
RUN wget -q https://chromedriver.storage.googleapis.com/2.29/chromedriver_linux64.zip RUN wget -q https://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip
RUN unzip chromedriver_linux64.zip -d /usr/local/bin RUN unzip chromedriver_linux64.zip -d /usr/local/bin
RUN apt-get clean RUN apt-get clean
......
...@@ -55,7 +55,7 @@ module QA ...@@ -55,7 +55,7 @@ module QA
Capybara.register_driver :chrome do |app| Capybara.register_driver :chrome do |app|
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome( capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
'chromeOptions' => { 'chromeOptions' => {
'binary' => '/opt/google/chrome-beta/google-chrome-beta', 'binary' => '/usr/bin/google-chrome-stable',
'args' => %w[headless no-sandbox disable-gpu] 'args' => %w[headless no-sandbox disable-gpu]
} }
) )
......
require 'spec_helper' require 'spec_helper'
describe GroupsHelper do describe GroupsHelper do
include ApplicationHelper
let(:group) { create(:group) } let(:group) { create(:group) }
describe 'group_icon' do describe 'group_icon' do
...@@ -100,4 +102,15 @@ describe GroupsHelper do ...@@ -100,4 +102,15 @@ describe GroupsHelper do
end end
end end
end end
describe 'group_title' do
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
let(:deep_nested_group) { create(:group, parent: nested_group) }
let!(:very_deep_nested_group) { create(:group, parent: deep_nested_group) }
it 'outputs the groups in the correct order', :postgresql do
expect(group_title(very_deep_nested_group)).to match(/>#{group.name}<\/a>.*>#{nested_group.name}<\/a>.*>#{deep_nested_group.name}<\/a>/)
end
end
end end
...@@ -262,39 +262,53 @@ describe Gitlab::Database::MigrationHelpers, lib: true do ...@@ -262,39 +262,53 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
end end
describe '#update_column_in_batches' do describe '#update_column_in_batches' do
before do context 'when running outside of a transaction' do
create_list(:empty_project, 5) before do
end expect(model).to receive(:transaction_open?).and_return(false)
it 'updates all the rows in a table' do create_list(:empty_project, 5)
model.update_column_in_batches(:projects, :import_error, 'foo') end
expect(Project.where(import_error: 'foo').count).to eq(5) it 'updates all the rows in a table' do
end model.update_column_in_batches(:projects, :import_error, 'foo')
it 'updates boolean values correctly' do expect(Project.where(import_error: 'foo').count).to eq(5)
model.update_column_in_batches(:projects, :archived, true) end
expect(Project.where(archived: true).count).to eq(5) it 'updates boolean values correctly' do
end model.update_column_in_batches(:projects, :archived, true)
expect(Project.where(archived: true).count).to eq(5)
end
context 'when a block is supplied' do
it 'yields an Arel table and query object to the supplied block' do
first_id = Project.first.id
context 'when a block is supplied' do model.update_column_in_batches(:projects, :archived, true) do |t, query|
it 'yields an Arel table and query object to the supplied block' do query.where(t[:id].eq(first_id))
first_id = Project.first.id end
model.update_column_in_batches(:projects, :archived, true) do |t, query| expect(Project.where(archived: true).count).to eq(1)
query.where(t[:id].eq(first_id))
end end
end
context 'when the value is Arel.sql (Arel::Nodes::SqlLiteral)' do
it 'updates the value as a SQL expression' do
model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1'))
expect(Project.where(archived: true).count).to eq(1) expect(Project.sum(:star_count)).to eq(2 * Project.count)
end
end end
end end
context 'when the value is Arel.sql (Arel::Nodes::SqlLiteral)' do context 'when running inside the transaction' do
it 'updates the value as a SQL expression' do it 'raises RuntimeError' do
model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1')) expect(model).to receive(:transaction_open?).and_return(true)
expect(Project.sum(:star_count)).to eq(2 * Project.count) expect do
model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1'))
end.to raise_error(RuntimeError)
end end
end end
end end
...@@ -303,7 +317,9 @@ describe Gitlab::Database::MigrationHelpers, lib: true do ...@@ -303,7 +317,9 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
context 'outside of a transaction' do context 'outside of a transaction' do
context 'when a column limit is not set' do context 'when a column limit is not set' do
before do before do
expect(model).to receive(:transaction_open?).and_return(false) expect(model).to receive(:transaction_open?)
.and_return(false)
.at_least(:once)
expect(model).to receive(:transaction).and_yield expect(model).to receive(:transaction).and_yield
...@@ -810,7 +826,11 @@ describe Gitlab::Database::MigrationHelpers, lib: true do ...@@ -810,7 +826,11 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
let!(:user) { create(:user, name: 'Kathy Alice Aliceson') } let!(:user) { create(:user, name: 'Kathy Alice Aliceson') }
it 'replaces the correct part of the string' do it 'replaces the correct part of the string' do
model.update_column_in_batches(:users, :name, model.replace_sql(Arel::Table.new(:users)[:name], 'Alice', 'Eve')) allow(model).to receive(:transaction_open?).and_return(false)
query = model.replace_sql(Arel::Table.new(:users)[:name], 'Alice', 'Eve')
model.update_column_in_batches(:users, :name, query)
expect(user.reload.name).to eq('Kathy Eve Aliceson') expect(user.reload.name).to eq('Kathy Eve Aliceson')
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase do describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :truncate do
let(:migration) { FakeRenameReservedPathMigrationV1.new } let(:migration) { FakeRenameReservedPathMigrationV1.new }
let(:subject) { described_class.new(['the-path'], migration) } let(:subject) { described_class.new(['the-path'], migration) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :truncate do
let(:migration) { FakeRenameReservedPathMigrationV1.new } let(:migration) { FakeRenameReservedPathMigrationV1.new }
let(:subject) { described_class.new(['the-path'], migration) } let(:subject) { described_class.new(['the-path'], migration) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects do describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :truncate do
let(:migration) { FakeRenameReservedPathMigrationV1.new } let(:migration) { FakeRenameReservedPathMigrationV1.new }
let(:subject) { described_class.new(['the-path'], migration) } let(:subject) { described_class.new(['the-path'], migration) }
......
...@@ -13,7 +13,7 @@ shared_examples 'renames child namespaces' do |type| ...@@ -13,7 +13,7 @@ shared_examples 'renames child namespaces' do |type|
end end
end end
describe Gitlab::Database::RenameReservedPathsMigration::V1 do describe Gitlab::Database::RenameReservedPathsMigration::V1, :truncate do
let(:subject) { FakeRenameReservedPathMigrationV1.new } let(:subject) { FakeRenameReservedPathMigrationV1.new }
before do before do
......
...@@ -54,6 +54,8 @@ describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do ...@@ -54,6 +54,8 @@ describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do
Sphinx>=1.3 Sphinx>=1.3
docutils>=0.7 docutils>=0.7
markupsafe markupsafe
pytest~=3.0
foop!=3.0
CONTENT CONTENT
end end
...@@ -78,6 +80,8 @@ describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do ...@@ -78,6 +80,8 @@ describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do
expect(subject).to include(link('Sphinx', 'https://pypi.python.org/pypi/Sphinx')) expect(subject).to include(link('Sphinx', 'https://pypi.python.org/pypi/Sphinx'))
expect(subject).to include(link('docutils', 'https://pypi.python.org/pypi/docutils')) expect(subject).to include(link('docutils', 'https://pypi.python.org/pypi/docutils'))
expect(subject).to include(link('markupsafe', 'https://pypi.python.org/pypi/markupsafe')) expect(subject).to include(link('markupsafe', 'https://pypi.python.org/pypi/markupsafe'))
expect(subject).to include(link('pytest', 'https://pypi.python.org/pypi/pytest'))
expect(subject).to include(link('foop', 'https://pypi.python.org/pypi/foop'))
end end
it 'links URLs' do it 'links URLs' do
......
...@@ -21,7 +21,7 @@ describe Gitlab::VisibilityLevel, lib: true do ...@@ -21,7 +21,7 @@ describe Gitlab::VisibilityLevel, lib: true do
describe '.levels_for_user' do describe '.levels_for_user' do
it 'returns all levels for an admin' do it 'returns all levels for an admin' do
user = double(:user, has_full_private_access?: true) user = build(:user, :admin)
expect(described_class.levels_for_user(user)) expect(described_class.levels_for_user(user))
.to eq([Gitlab::VisibilityLevel::PRIVATE, .to eq([Gitlab::VisibilityLevel::PRIVATE,
...@@ -30,7 +30,7 @@ describe Gitlab::VisibilityLevel, lib: true do ...@@ -30,7 +30,7 @@ describe Gitlab::VisibilityLevel, lib: true do
end end
it 'returns INTERNAL and PUBLIC for internal users' do it 'returns INTERNAL and PUBLIC for internal users' do
user = double(:user, has_full_private_access?: false, external?: false) user = build(:user)
expect(described_class.levels_for_user(user)) expect(described_class.levels_for_user(user))
.to eq([Gitlab::VisibilityLevel::INTERNAL, .to eq([Gitlab::VisibilityLevel::INTERNAL,
...@@ -38,7 +38,7 @@ describe Gitlab::VisibilityLevel, lib: true do ...@@ -38,7 +38,7 @@ describe Gitlab::VisibilityLevel, lib: true do
end end
it 'returns PUBLIC for external users' do it 'returns PUBLIC for external users' do
user = double(:user, has_full_private_access?: false, external?: true) user = build(:user, :external)
expect(described_class.levels_for_user(user)) expect(described_class.levels_for_user(user))
.to eq([Gitlab::VisibilityLevel::PUBLIC]) .to eq([Gitlab::VisibilityLevel::PUBLIC])
......
require 'spec_helper' require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20170508170547_add_head_pipeline_for_each_merge_request.rb') require Rails.root.join('db', 'post_migrate', '20170508170547_add_head_pipeline_for_each_merge_request.rb')
describe AddHeadPipelineForEachMergeRequest do describe AddHeadPipelineForEachMergeRequest, :truncate do
let(:migration) { described_class.new } let(:migration) { described_class.new }
let!(:project) { create(:empty_project) } let!(:project) { create(:empty_project) }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'spec_helper' require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20170324160416_migrate_user_activities_to_users_last_activity_on.rb') require Rails.root.join('db', 'post_migrate', '20170324160416_migrate_user_activities_to_users_last_activity_on.rb')
describe MigrateUserActivitiesToUsersLastActivityOn, :redis do describe MigrateUserActivitiesToUsersLastActivityOn, :redis, :truncate do
let(:migration) { described_class.new } let(:migration) { described_class.new }
let!(:user_active_1) { create(:user) } let!(:user_active_1) { create(:user) }
let!(:user_active_2) { create(:user) } let!(:user_active_2) { create(:user) }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'spec_helper' require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20170406142253_migrate_user_project_view.rb') require Rails.root.join('db', 'post_migrate', '20170406142253_migrate_user_project_view.rb')
describe MigrateUserProjectView do describe MigrateUserProjectView, :truncate do
let(:migration) { described_class.new } let(:migration) { described_class.new }
let!(:user) { create(:user) } let!(:user) { create(:user) }
......
...@@ -1869,43 +1869,6 @@ describe User, models: true do ...@@ -1869,43 +1869,6 @@ describe User, models: true do
end end
end end
describe '.ghost' do
it "creates a ghost user if one isn't already present" do
ghost = User.ghost
expect(ghost).to be_ghost
expect(ghost).to be_persisted
end
it "does not create a second ghost user if one is already present" do
expect do
User.ghost
User.ghost
end.to change { User.count }.by(1)
expect(User.ghost).to eq(User.ghost)
end
context "when a regular user exists with the username 'ghost'" do
it "creates a ghost user with a non-conflicting username" do
create(:user, username: 'ghost')
ghost = User.ghost
expect(ghost).to be_persisted
expect(ghost.username).to eq('ghost1')
end
end
context "when a regular user exists with the email 'ghost@example.com'" do
it "creates a ghost user with a non-conflicting email" do
create(:user, email: 'ghost@example.com')
ghost = User.ghost
expect(ghost).to be_persisted
expect(ghost.email).to eq('ghost1@example.com')
end
end
end
describe '.ghost' do describe '.ghost' do
it "creates a ghost user if one isn't already present" do it "creates a ghost user if one isn't already present" do
ghost = User.ghost ghost = User.ghost
......
...@@ -21,24 +21,26 @@ describe 'projects/commit/show.html.haml', :view do ...@@ -21,24 +21,26 @@ describe 'projects/commit/show.html.haml', :view do
context 'inline diff view' do context 'inline diff view' do
before do before do
allow(view).to receive(:diff_view).and_return(:inline) allow(view).to receive(:diff_view).and_return(:inline)
allow(view).to receive(:diff_view).and_return(:inline)
render render
end end
it 'keeps container-limited' do it 'has limited width' do
expect(rendered).not_to have_selector('.limit-container-width') expect(rendered).to have_selector('.limit-container-width')
end end
end end
context 'parallel diff view' do context 'parallel diff view' do
before do before do
allow(view).to receive(:diff_view).and_return(:parallel) allow(view).to receive(:diff_view).and_return(:parallel)
allow(view).to receive(:fluid_layout).and_return(true)
render render
end end
it 'spans full width' do it 'spans full width' do
expect(rendered).to have_selector('.limit-container-width') expect(rendered).not_to have_selector('.limit-container-width')
end end
end end
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