Commit 2127b937 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into 'dm-project-mirror-data-created-updated-at'

# Conflicts:
#   db/schema.rb
parents 90be1585 61bbab8a
...@@ -449,4 +449,4 @@ gem 'lograge', '~> 0.5' ...@@ -449,4 +449,4 @@ gem 'lograge', '~> 0.5'
gem 'grape_logging', '~> 1.7' gem 'grape_logging', '~> 1.7'
# Asset synchronization # Asset synchronization
gem 'asset_sync', '~> 2.2.0' gem 'asset_sync', '~> 2.4'
...@@ -59,7 +59,7 @@ GEM ...@@ -59,7 +59,7 @@ GEM
asciidoctor (1.5.6.2) asciidoctor (1.5.6.2)
asciidoctor-plantuml (0.0.8) asciidoctor-plantuml (0.0.8)
asciidoctor (~> 1.5) asciidoctor (~> 1.5)
asset_sync (2.2.0) asset_sync (2.4.0)
activemodel (>= 4.1.0) activemodel (>= 4.1.0)
fog-core fog-core
mime-types (>= 2.99) mime-types (>= 2.99)
...@@ -218,7 +218,7 @@ GEM ...@@ -218,7 +218,7 @@ GEM
et-orbi (1.0.3) et-orbi (1.0.3)
tzinfo tzinfo
eventmachine (1.0.8) eventmachine (1.0.8)
excon (0.60.0) excon (0.62.0)
execjs (2.6.0) execjs (2.6.0)
expression_parser (0.9.0) expression_parser (0.9.0)
factory_bot (4.8.2) factory_bot (4.8.2)
...@@ -1027,7 +1027,7 @@ DEPENDENCIES ...@@ -1027,7 +1027,7 @@ DEPENDENCIES
asana (~> 0.6.0) asana (~> 0.6.0)
asciidoctor (~> 1.5.6) asciidoctor (~> 1.5.6)
asciidoctor-plantuml (= 0.0.8) asciidoctor-plantuml (= 0.0.8)
asset_sync (~> 2.2.0) asset_sync (~> 2.4)
attr_encrypted (~> 3.1.0) attr_encrypted (~> 3.1.0)
awesome_print (~> 1.2.0) awesome_print (~> 1.2.0)
aws-sdk aws-sdk
......
...@@ -16,8 +16,8 @@ export default { ...@@ -16,8 +16,8 @@ export default {
<icon <icon
name="git-merge" name="git-merge"
v-tooltip v-tooltip
title="__('Part of merge request changes')" :title="__('Part of merge request changes')"
css-classes="ide-file-changed-icon" css-classes="append-right-8"
:size="12" :size="12"
/> />
</template> </template>
...@@ -106,10 +106,6 @@ ...@@ -106,10 +106,6 @@
@include btn-color($red-500, $red-600, $red-600, $red-700, $red-700, $red-800, $white-light); @include btn-color($red-500, $red-600, $red-600, $red-700, $red-700, $red-800, $white-light);
} }
@mixin btn-gray {
@include btn-color($gray-light, $border-gray-normal, $gray-normal, $border-gray-normal, $gray-dark, $border-gray-dark, $gl-text-color);
}
@mixin btn-white { @mixin btn-white {
@include btn-color($white-light, $border-color, $white-normal, $border-white-normal, $white-dark, $border-gray-dark, $gl-text-color); @include btn-color($white-light, $border-color, $white-normal, $border-white-normal, $white-dark, $border-gray-dark, $gl-text-color);
} }
...@@ -183,10 +179,6 @@ ...@@ -183,10 +179,6 @@
} }
} }
&.btn-gray {
@include btn-gray;
}
&.btn-info, &.btn-info,
&.btn-primary, &.btn-primary,
&.btn-register { &.btn-register {
......
...@@ -205,7 +205,6 @@ ...@@ -205,7 +205,6 @@
.project-repo-buttons, .project-repo-buttons,
.group-buttons { .group-buttons {
.btn { .btn {
@include btn-gray;
padding: 3px 10px; padding: 3px 10px;
&:last-child { &:last-child {
...@@ -294,7 +293,7 @@ ...@@ -294,7 +293,7 @@
} }
.count { .count {
@include btn-gray; @include btn-white;
display: inline-block; display: inline-block;
background: $white-light; background: $white-light;
border-radius: 2px; border-radius: 2px;
......
...@@ -63,13 +63,16 @@ module ReactiveCaching ...@@ -63,13 +63,16 @@ module ReactiveCaching
end end
def with_reactive_cache(*args, &blk) def with_reactive_cache(*args, &blk)
within_reactive_cache_lifetime(*args) do bootstrap = !within_reactive_cache_lifetime?(*args)
Rails.cache.write(alive_reactive_cache_key(*args), true, expires_in: self.class.reactive_cache_lifetime)
if bootstrap
ReactiveCachingWorker.perform_async(self.class, id, *args)
nil
else
data = Rails.cache.read(full_reactive_cache_key(*args)) data = Rails.cache.read(full_reactive_cache_key(*args))
yield data if data.present? yield data if data.present?
end end
ensure
Rails.cache.write(alive_reactive_cache_key(*args), true, expires_in: self.class.reactive_cache_lifetime)
ReactiveCachingWorker.perform_async(self.class, id, *args)
end end
def clear_reactive_cache!(*args) def clear_reactive_cache!(*args)
...@@ -78,7 +81,7 @@ module ReactiveCaching ...@@ -78,7 +81,7 @@ module ReactiveCaching
def exclusively_update_reactive_cache!(*args) def exclusively_update_reactive_cache!(*args)
locking_reactive_cache(*args) do locking_reactive_cache(*args) do
within_reactive_cache_lifetime(*args) do if within_reactive_cache_lifetime?(*args)
enqueuing_update(*args) do enqueuing_update(*args) do
key = full_reactive_cache_key(*args) key = full_reactive_cache_key(*args)
new_value = calculate_reactive_cache(*args) new_value = calculate_reactive_cache(*args)
...@@ -111,8 +114,8 @@ module ReactiveCaching ...@@ -111,8 +114,8 @@ module ReactiveCaching
Gitlab::ExclusiveLease.cancel(full_reactive_cache_key(*args), uuid) Gitlab::ExclusiveLease.cancel(full_reactive_cache_key(*args), uuid)
end end
def within_reactive_cache_lifetime(*args) def within_reactive_cache_lifetime?(*args)
yield if Rails.cache.read(alive_reactive_cache_key(*args)) !!Rails.cache.read(alive_reactive_cache_key(*args))
end end
def enqueuing_update(*args) def enqueuing_update(*args)
......
#modal-shortcuts.modal{ tabindex: -1 } #modal-shortcuts.modal{ tabindex: -1 }
.modal-dialog .modal-dialog.modal-lg
.modal-content .modal-content
.modal-header .modal-header
%a.close{ href: "#", "data-dismiss" => "modal" } × %a.close{ href: "#", "data-dismiss" => "modal" } ×
......
...@@ -74,10 +74,10 @@ ...@@ -74,10 +74,10 @@
= lorem = lorem
.cover-controls .cover-controls
= link_to '#', class: 'btn btn-gray' do = link_to '#', class: 'btn btn-default' do
= icon('pencil') = icon('pencil')
&nbsp; &nbsp;
= link_to '#', class: 'btn btn-gray' do = link_to '#', class: 'btn btn-default' do
= icon('rss') = icon('rss')
%h2#lists Lists %h2#lists Lists
...@@ -206,7 +206,6 @@ ...@@ -206,7 +206,6 @@
.example .example
%button.btn.btn-default{ :type => "button" } Default %button.btn.btn-default{ :type => "button" } Default
%button.btn.btn-gray{ :type => "button" } Gray
%button.btn.btn-primary{ :type => "button" } Primary %button.btn.btn-primary{ :type => "button" } Primary
%button.btn.btn-success{ :type => "button" } Success %button.btn.btn-success{ :type => "button" } Success
%button.btn.btn-info{ :type => "button" } Info %button.btn.btn-info{ :type => "button" } Info
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
.cover-block.user-cover-block.top-area .cover-block.user-cover-block.top-area
.cover-controls .cover-controls
- if @user == current_user - if @user == current_user
= link_to profile_path, class: 'btn btn-gray has-tooltip', title: 'Edit profile', 'aria-label': 'Edit profile' do = link_to profile_path, class: 'btn btn-default has-tooltip', title: 'Edit profile', 'aria-label': 'Edit profile' do
= icon('pencil') = icon('pencil')
- elsif current_user - elsif current_user
- if @user.abuse_report - if @user.abuse_report
...@@ -20,13 +20,13 @@ ...@@ -20,13 +20,13 @@
data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } } data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } }
= icon('exclamation-circle') = icon('exclamation-circle')
- else - else
= link_to new_abuse_report_path(user_id: @user.id, ref_url: request.referrer), class: 'btn btn-gray', = link_to new_abuse_report_path(user_id: @user.id, ref_url: request.referrer), class: 'btn',
title: 'Report abuse', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do title: 'Report abuse', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= icon('exclamation-circle') = icon('exclamation-circle')
= link_to user_path(@user, rss_url_options), class: 'btn btn-gray has-tooltip', title: 'Subscribe', 'aria-label': 'Subscribe' do = link_to user_path(@user, rss_url_options), class: 'btn btn-default has-tooltip', title: 'Subscribe', 'aria-label': 'Subscribe' do
= icon('rss') = icon('rss')
- if current_user && current_user.admin? - if current_user && current_user.admin?
= link_to [:admin, @user], class: 'btn btn-gray', title: 'View user in admin area', = link_to [:admin, @user], class: 'btn btn-default', title: 'View user in admin area',
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('users') = icon('users')
......
---
title: Remove gray button styles
merge_request:
author:
type: fixed
---
title: Raise NoRepository error for non-valid repositories when calculating repository
checksum
merge_request: 18594
author:
type: fixed
---
title: Expose runner ip address to runners API
merge_request: 18799
author: Lars Greiss
type: changed
---
title: Add database foreign key constraint between pipelines and build
merge_request: 18822
author:
type: fixed
---
title: Update commit status from external CI services less aggressively
merge_request: 18802
author:
type: fixed
---
title: Fix modal width of shorcuts help page
merge_request: 18766
author: Lars Greiss
type: fixed
class AddPipelineBuildForeignKey < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
execute <<~SQL
DELETE FROM ci_builds WHERE project_id IS NULL OR commit_id IS NULL
SQL
execute <<~SQL
DELETE FROM ci_builds WHERE NOT EXISTS
(SELECT true FROM ci_pipelines WHERE ci_pipelines.id = ci_builds.commit_id)
AND stage_id IS NULL
SQL
add_concurrent_foreign_key(:ci_builds, :ci_pipelines, column: :commit_id)
end
def down
return unless foreign_key_exists?(:ci_builds, :ci_pipelines, column: :commit_id)
remove_foreign_key(:ci_builds, column: :commit_id)
end
end
...@@ -5,9 +5,9 @@ class CreateProjectMirrorData < ActiveRecord::Migration ...@@ -5,9 +5,9 @@ class CreateProjectMirrorData < ActiveRecord::Migration
def up def up
if table_exists?(:project_mirror_data) if table_exists?(:project_mirror_data)
add_column :project_mirror_data, :status, :string add_column :project_mirror_data, :status, :string unless column_exists?(:project_mirror_data, :status)
add_column :project_mirror_data, :jid, :string add_column :project_mirror_data, :jid, :string unless column_exists?(:project_mirror_data, :jid)
add_column :project_mirror_data, :last_error, :text add_column :project_mirror_data, :last_error, :text unless column_exists?(:project_mirror_data, :last_error)
else else
create_table :project_mirror_data do |t| create_table :project_mirror_data do |t|
t.references :project, index: true, foreign_key: { on_delete: :cascade } t.references :project, index: true, foreign_key: { on_delete: :cascade }
......
class MakeRemoteMirrorsDisabledByDefault < ActiveRecord::Migration
DOWNTIME = false
def up
change_column_default :remote_mirrors, :enabled, false
end
def down
change_column_default :remote_mirrors, :enabled, true
end
end
--- ---
comments: false comments: false
description: 'Learn how to use and administer GitLab, the most scalable Git-based fully integrated platform for software development.'
--- ---
# GitLab Documentation # GitLab Documentation
......
# Geo (Geo Replication) **[PREMIUM ONLY]** # Geo (Geo Replication) **[PREMIUM ONLY]**
> **Notes:** > **Notes:**
- Geo is part of [GitLab Premium][ee]. - Geo is part of [GitLab Premium][ee]
- Introduced in GitLab Enterprise Edition 8.9. - Introduced in GitLab Enterprise Edition 8.9
We recommend you use it with at least GitLab Enterprise Edition 10.0 for We recommend you use it with at least GitLab Enterprise Edition 10.0 for
basic Geo features, or latest version for a better experience. basic Geo features, or latest version for a better experience
- You should make sure that all nodes run the same GitLab version. - You should make sure that all nodes run the same GitLab version
- Geo requires PostgreSQL 9.6 and Git 2.9 in addition to GitLab's usual - Geo requires PostgreSQL 9.6 and Git 2.9 in addition to GitLab's usual
[minimum requirements][install-requirements] [minimum requirements][install-requirements]
- Using Geo in combination with High Availability is considered **GA** in GitLab Enterprise Edition 10.4 - Using Geo in combination with High Availability (HA) is considered **Generally Available** (GA) in GitLab Enterprise Edition 10.4
>**Note:** >**Note:**
Geo changes significantly from release to release. Upgrades **are** Geo changes significantly from release to release. Upgrades **are**
...@@ -213,11 +213,9 @@ extra limitations may be in place. ...@@ -213,11 +213,9 @@ extra limitations may be in place.
### Limitations on replication ### Limitations on replication
Only the following items are replicated to the secondary. Any data not on this Only the following items are replicated to the secondary. Data not on this list is unavailable on the secondary. Failing over without manually replicating it will cause the data to be **lost**:
list will not be available on the secondary, and failing over without manually
replicating it will cause the data to be **lost**:
- All database content (e.g., snippets, epics, issues, merge requests, groups, project metadata, etc) - All database content (e.g. snippets, epics, issues, merge requests, groups, project metadata, etc)
- Project repositories - Project repositories
- Project wiki repositories - Project wiki repositories
- User uploads (e.g. attachments to issues, merge requests and epics, avatars, etc) - User uploads (e.g. attachments to issues, merge requests and epics, avatars, etc)
......
---
description: 'Learn how to install, configure, update, and maintain your GitLab instance.'
---
# Administrator documentation **[CORE ONLY]** # Administrator documentation **[CORE ONLY]**
Learn how to administer your GitLab instance (Community Edition and Learn how to administer your GitLab instance (Community Edition and
......
---
description: 'Learn how to administer GitLab Pages.'
---
# GitLab Pages administration # GitLab Pages administration
> **Notes:** > **Notes:**
...@@ -8,8 +12,6 @@ ...@@ -8,8 +12,6 @@
GitLab from source, follow the [Pages source installation document](source.md). GitLab from source, follow the [Pages source installation document](source.md).
- To learn how to use GitLab Pages, read the [user documentation][pages-userguide]. - To learn how to use GitLab Pages, read the [user documentation][pages-userguide].
---
This document describes how to set up the _latest_ GitLab Pages feature. Make This document describes how to set up the _latest_ GitLab Pages feature. Make
sure to read the [changelog](#changelog) if you are upgrading to a new GitLab sure to read the [changelog](#changelog) if you are upgrading to a new GitLab
version as it may include new features and changes needed to be made in your version as it may include new features and changes needed to be made in your
...@@ -24,8 +26,6 @@ SNI and exposes pages using HTTP2 by default. ...@@ -24,8 +26,6 @@ SNI and exposes pages using HTTP2 by default.
You are encouraged to read its [README][pages-readme] to fully understand how You are encouraged to read its [README][pages-readme] to fully understand how
it works. it works.
---
In the case of [custom domains](#custom-domains) (but not In the case of [custom domains](#custom-domains) (but not
[wildcard domains](#wildcard-domains)), the Pages daemon needs to listen on [wildcard domains](#wildcard-domains)), the Pages daemon needs to listen on
ports `80` and/or `443`. For that reason, there is some flexibility in the way ports `80` and/or `443`. For that reason, there is some flexibility in the way
......
--- ---
comments: false comments: false
description: "Learn how to use GitLab CI/CD, the GitLab built-in Continuous Integration, Continuous Deployment, and Continuous Delivery toolset to build, test, and deploy your application."
--- ---
# GitLab Continuous Integration (GitLab CI/CD) # GitLab Continuous Integration (GitLab CI/CD)
......
--- ---
comments: false comments: false
description: 'Learn how to contribute to GitLab.'
--- ---
# GitLab development guides # GitLab development guides
...@@ -18,6 +19,7 @@ comments: false ...@@ -18,6 +19,7 @@ comments: false
- [Code review guidelines](code_review.md) for reviewing code and having code reviewed. - [Code review guidelines](code_review.md) for reviewing code and having code reviewed.
- [Automatic CE->EE merge](automatic_ce_ee_merge.md) - [Automatic CE->EE merge](automatic_ce_ee_merge.md)
- [Guidelines for implementing Enterprise Edition features](ee_features.md) - [Guidelines for implementing Enterprise Edition features](ee_features.md)
- [Security process for developers](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#security-releases-critical-non-critical-as-a-developer)
## UX and frontend guides ## UX and frontend guides
......
---
description: 'Writing styles, markup, formatting, and reusing regular expressions throughout the GitLab Documentation.'
---
# Documentation style guidelines # Documentation style guidelines
The documentation style guide defines the markup structure used in The documentation style guide defines the markup structure used in
......
---
description: Learn how to contribute to GitLab Documentation.
---
# GitLab Documentation guidelines # GitLab Documentation guidelines
- **General Documentation**: written by the [developers responsible by creating features](#contributing-to-docs). Should be submitted in the same merge request containing code. Feature proposals (by GitLab contributors) should also be accompanied by its respective documentation. They can be later improved by PMs and Technical Writers. - **General Documentation**: written by the [developers responsible by creating features](#contributing-to-docs). Should be submitted in the same merge request containing code. Feature proposals (by GitLab contributors) should also be accompanied by its respective documentation. They can be later improved by PMs and Technical Writers.
......
--- ---
comments: false comments: false
description: Read through the GitLab installation methods.
--- ---
# Installation **[CORE ONLY]** # Installation **[CORE ONLY]**
......
---
description: 'Learn how to spin up a
pre-configured GitLab VM on Microsoft Azure and have your very own private GitLab instance up and running in around 30 minutes.'
---
# Install GitLab on Microsoft Azure # Install GitLab on Microsoft Azure
> _This article was originally written by Dave Wentzel and [published on the GitLab Blog][Original-Blog-Post]._ > _This article was originally written by Dave Wentzel and [published on the GitLab Blog][Original-Blog-Post]._
......
---
description: 'Learn how to install a GitLab instance on Google Cloud Platform.'
---
# Installing GitLab on Google Cloud Platform # Installing GitLab on Google Cloud Platform
![GCP landing page](img/gcp_landing.png) ![GCP landing page](img/gcp_landing.png)
......
---
description: 'Read through the different methods to deploy GitLab on Kubernetes.'
---
# Installing GitLab on Kubernetes # Installing GitLab on Kubernetes
> **Note**: These charts have been tested on Google Kubernetes Engine and Azure Container Service. Other Kubernetes installations may work as well, if not please [open an issue](https://gitlab.com/charts/charts.gitlab.io/issues). > **Note**: These charts have been tested on Google Kubernetes Engine and Azure Container Service. Other Kubernetes installations may work as well, if not please [open an issue](https://gitlab.com/charts/charts.gitlab.io/issues).
The easiest method to deploy GitLab on [Kubernetes](https://kubernetes.io/) is The easiest method to deploy GitLab on [Kubernetes](https://kubernetes.io/) is
...@@ -16,6 +21,7 @@ should be deployed, upgraded, and configured. ...@@ -16,6 +21,7 @@ should be deployed, upgraded, and configured.
* [Community Contributed Charts](#community-contributed-charts): Community contributed charts, deprecated by the official GitLab chart. * [Community Contributed Charts](#community-contributed-charts): Community contributed charts, deprecated by the official GitLab chart.
## GitLab-Omnibus Chart (Recommended) ## GitLab-Omnibus Chart (Recommended)
> **Note**: This chart is in beta while [additional features](https://gitlab.com/charts/charts.gitlab.io/issues/68) are being added. > **Note**: This chart is in beta while [additional features](https://gitlab.com/charts/charts.gitlab.io/issues/68) are being added.
This chart is the best available way to operate GitLab on Kubernetes. It deploys and configures nearly all features of GitLab, including: a [Runner](https://docs.gitlab.com/runner/), [Container Registry](../../user/project/container_registry.html#gitlab-container-registry), [Mattermost](https://docs.gitlab.com/omnibus/gitlab-mattermost/), [automatic SSL](https://github.com/kubernetes/charts/tree/master/stable/kube-lego), and a [load balancer](https://github.com/kubernetes/ingress/tree/master/controllers/nginx). It is based on our [GitLab Omnibus Docker Images](https://docs.gitlab.com/omnibus/docker/README.html). This chart is the best available way to operate GitLab on Kubernetes. It deploys and configures nearly all features of GitLab, including: a [Runner](https://docs.gitlab.com/runner/), [Container Registry](../../user/project/container_registry.html#gitlab-container-registry), [Mattermost](https://docs.gitlab.com/omnibus/gitlab-mattermost/), [automatic SSL](https://github.com/kubernetes/charts/tree/master/stable/kube-lego), and a [load balancer](https://github.com/kubernetes/ingress/tree/master/controllers/nginx). It is based on our [GitLab Omnibus Docker Images](https://docs.gitlab.com/omnibus/docker/README.html).
......
...@@ -4,6 +4,7 @@ author_gitlab: SeanPackham ...@@ -4,6 +4,7 @@ author_gitlab: SeanPackham
level: beginner level: beginner
article_type: user guide article_type: user guide
date: 2017-05-15 date: 2017-05-15
description: 'This article describes how to install Git on macOS, Ubuntu Linux and Windows.'
--- ---
# Installing Git # Installing Git
......
---
description: 'Read through the GitLab User documentation to learn how to use, configure, and customize GitLab and GitLab.com to your own needs.'
---
# User documentation # User documentation
Welcome to GitLab! We're glad to have you here! Welcome to GitLab! We're glad to have you here!
......
---
description: 'Understand and explore the user permission levels in GitLab, and what features each of them grants you access to.'
---
# Permissions # Permissions
Users have different abilities depending on the access level they have in a Users have different abilities depending on the access level they have in a
......
---
description: 'Learn how to use GitLab Pages to deploy a static website at no additional cost.'
---
# GitLab Pages # GitLab Pages
With GitLab Pages it's easy to publish your project website. GitLab Pages is a hosting service for static websites, at no additional cost. With GitLab Pages it's easy to publish your project website. GitLab Pages is a hosting service for static websites, at no additional cost.
......
...@@ -10,6 +10,10 @@ module EE ...@@ -10,6 +10,10 @@ module EE
burndown&.valid? && !burndown&.empty? burndown&.valid? && !burndown&.empty?
end end
def show_burndown_charts_promotion?(milestone)
milestone.is_a?(EE::Milestone) && !milestone.supports_burndown_charts? && show_promotions?
end
def show_burndown_placeholder?(milestone, warning) def show_burndown_placeholder?(milestone, warning)
return false if cookies['hide_burndown_message'].present? return false if cookies['hide_burndown_message'].present?
return false unless milestone.supports_burndown_charts? return false unless milestone.supports_burndown_charts?
......
- callout_id = 'promote_burndown_charts_dismissed' - callout_id = 'promote_burndown_charts_dismissed'
- if !milestone.supports_burndown_charts? && show_promotions? && show_callout?(callout_id) - if show_burndown_charts_promotion?(milestone) && show_callout?(callout_id)
.user-callout.promotion-callout#promote_burndown_charts{ data: { uid: callout_id } } .user-callout.promotion-callout#promote_burndown_charts{ data: { uid: callout_id } }
.bordered-box.content-block .bordered-box.content-block
%button.btn.btn-default.close.js-close-callout{ type: 'button', 'aria-label' => 'Dismiss burndown charts promotion' } %button.btn.btn-default.close.js-close-callout{ type: 'button', 'aria-label' => 'Dismiss burndown charts promotion' }
......
---
title: Stop presenting burndown charts promotion for grouped by title milestones
merge_request:
author:
type: fixed
# See http://doc.gitlab.com/ce/development/migration_style_guide.html # See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab. # for more information on how to write migrations for GitLab.
class MakeRemoteMirrorsDisabledByDefault < ActiveRecord::Migration class MakeRemoteMirrorsDisabledByDefaultEE < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
# When using the methods "add_concurrent_index" or "add_column_with_default" # When using the methods "add_concurrent_index" or "add_column_with_default"
......
...@@ -9,10 +9,10 @@ class CreateProjectMirrorDataEE < ActiveRecord::Migration ...@@ -9,10 +9,10 @@ class CreateProjectMirrorDataEE < ActiveRecord::Migration
# When moving from CE to EE, project_mirror_data may already exist, but will # When moving from CE to EE, project_mirror_data may already exist, but will
# not have all the required columns. # not have all the required columns.
if table_exists?(:project_mirror_data) if table_exists?(:project_mirror_data)
add_column_with_default :project_mirror_data, :retry_count, :integer, default: 0, allow_null: false add_column_with_default :project_mirror_data, :retry_count, :integer, default: 0, allow_null: false unless column_exists?(:project_mirror_data, :retry_count)
add_column :project_mirror_data, :last_update_started_at, :datetime_with_timezone add_column :project_mirror_data, :last_update_started_at, :datetime_with_timezone unless column_exists?(:project_mirror_data, :last_update_started_at)
add_column :project_mirror_data, :last_update_scheduled_at, :datetime_with_timezone add_column :project_mirror_data, :last_update_scheduled_at, :datetime_with_timezone unless column_exists?(:project_mirror_data, :last_update_scheduled_at)
add_column :project_mirror_data, :next_execution_timestamp, :datetime_with_timezone add_column :project_mirror_data, :next_execution_timestamp, :datetime_with_timezone unless column_exists?(:project_mirror_data, :next_execution_timestamp)
else else
execute <<-SQL execute <<-SQL
CREATE TABLE project_mirror_data CREATE TABLE project_mirror_data
......
...@@ -10,8 +10,8 @@ class AddMissingColumnsToProjectMirrorData < ActiveRecord::Migration ...@@ -10,8 +10,8 @@ class AddMissingColumnsToProjectMirrorData < ActiveRecord::Migration
disable_ddl_transaction! disable_ddl_transaction!
def up def up
add_column :project_mirror_data, :last_update_at, :datetime_with_timezone add_column :project_mirror_data, :last_update_at, :datetime_with_timezone unless column_exists?(:project_mirror_data, :last_update_at)
add_column :project_mirror_data, :last_successful_update_at, :datetime_with_timezone add_column :project_mirror_data, :last_successful_update_at, :datetime_with_timezone unless column_exists?(:project_mirror_data, :last_successful_update_at)
end end
def down def down
......
require 'spec_helper'
feature 'Burndown charts' do
let(:current_user) { create(:user) }
let(:milestone) do
create(:milestone, project: project,
group: group,
start_date: Date.current,
due_date: Date.tomorrow)
end
before do
sign_in(current_user)
end
describe 'for project milestones' do
let(:group) { nil }
let(:project) { create(:project) }
before do
project.add_master(current_user)
end
it 'presents burndown charts when available' do
stub_licensed_features(burndown_charts: true)
visit project_milestone_path(milestone.project, milestone)
expect(page).to have_css('.burndown-chart')
expect(page).to have_content('Burndown chart')
end
it 'presents burndown charts promotion correctly' do
stub_licensed_features(burndown_charts: false)
allow(License).to receive(:current) { nil }
visit project_milestone_path(milestone.project, milestone)
expect(page).not_to have_css('.burndown-chart')
expect(page).to have_content('Improve milestones with Burndown Charts')
end
end
describe 'for group milestones' do
let(:group) { create(:group) }
let(:project) { nil }
before do
group.add_master(current_user)
end
it 'presents burndown charts when available' do
stub_licensed_features(group_burndown_charts: true)
visit group_milestone_path(milestone.group, milestone)
expect(page).to have_css('div.burndown-chart')
expect(page).to have_content('Burndown chart')
end
it 'presents burndown charts promotion correctly' do
stub_licensed_features(group_burndown_charts: false)
allow(License).to receive(:current) { nil }
visit group_milestone_path(milestone.group, milestone)
expect(page).not_to have_css('.burndown-chart')
expect(page).to have_content('Improve milestones with Burndown Charts')
end
end
describe 'grouped by title milestones' do
let(:group) { nil }
let(:project) { create(:project) }
before do
project.add_master(current_user)
end
it 'does not present burndown chart or promotion' do
allow(License).to receive(:current) { nil }
allow(Gitlab::CurrentSettings).to receive(:should_check_namespace_plan?) { true }
visit dashboard_milestone_path(milestone.safe_title, title: milestone.title)
expect(page).to have_content('manage issues from multiple projects in the same milestone.')
expect(page).not_to have_css('.burndown-chart')
expect(page).not_to have_content('Improve milestones with Burndown Charts')
end
end
end
...@@ -995,6 +995,7 @@ module API ...@@ -995,6 +995,7 @@ module API
class Runner < Grape::Entity class Runner < Grape::Entity
expose :id expose :id
expose :description expose :description
expose :ip_address
expose :active expose :active
expose :is_shared expose :is_shared
expose :name expose :name
......
...@@ -1601,7 +1601,7 @@ module Gitlab ...@@ -1601,7 +1601,7 @@ module Gitlab
def checksum def checksum
gitaly_migrate(:calculate_checksum, gitaly_migrate(:calculate_checksum,
status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_repository_client.calculate_checksum gitaly_repository_client.calculate_checksum
else else
......
...@@ -292,6 +292,8 @@ module Gitlab ...@@ -292,6 +292,8 @@ module Gitlab
request = Gitaly::CalculateChecksumRequest.new(repository: @gitaly_repo) request = Gitaly::CalculateChecksumRequest.new(repository: @gitaly_repo)
response = GitalyClient.call(@storage, :repository_service, :calculate_checksum, request) response = GitalyClient.call(@storage, :repository_service, :calculate_checksum, request)
response.checksum.presence response.checksum.presence
rescue GRPC::DataLoss => e
raise Gitlab::Git::Repository::InvalidRepository.new(e)
end end
def raw_changes_between(from, to) def raw_changes_between(from, to)
......
...@@ -292,7 +292,7 @@ describe ProjectsHelper do ...@@ -292,7 +292,7 @@ describe ProjectsHelper do
end end
it 'removes the repo path' do it 'removes the repo path' do
repo = "#{storage_path}/namespace/test.git" repo = File.join(storage_path, 'namespace/test.git')
import_error = "Could not clone #{repo}\n" import_error = "Could not clone #{repo}\n"
expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git') expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git')
......
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180420010016_add_pipeline_build_foreign_key.rb')
describe AddPipelineBuildForeignKey, :migration do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
let(:builds) { table(:ci_builds) }
before do
namespaces.create(id: 10, name: 'gitlab-org', path: 'gitlab-org')
projects.create!(id: 11, namespace_id: 10, name: 'gitlab', path: 'gitlab')
pipelines.create!(id: 12, project_id: 11, ref: 'master', sha: 'adf43c3a')
builds.create!(id: 101, commit_id: 12, project_id: 11)
builds.create!(id: 102, commit_id: 222, project_id: 11)
builds.create!(id: 103, commit_id: 333, project_id: 11)
builds.create!(id: 104, commit_id: 12, project_id: 11)
builds.create!(id: 106, commit_id: nil, project_id: 11)
builds.create!(id: 107, commit_id: 12, project_id: nil)
end
it 'adds foreign key after removing orphans' do
expect(builds.all.count).to eq 6
expect(foreign_key_exists?(:ci_builds, :ci_pipelines, column: :commit_id)).to be_falsey
migrate!
expect(builds.all.pluck(:id)).to eq [101, 104]
expect(foreign_key_exists?(:ci_builds, :ci_pipelines, column: :commit_id)).to be_truthy
end
end
...@@ -198,7 +198,7 @@ describe Ci::Runner do ...@@ -198,7 +198,7 @@ describe Ci::Runner do
end end
describe '#assign_to' do describe '#assign_to' do
let!(:project) { FactoryBot.create :project } let!(:project) { FactoryBot.create(:project) }
let!(:shared_runner) { FactoryBot.create(:ci_runner, :shared) } let!(:shared_runner) { FactoryBot.create(:ci_runner, :shared) }
before do before do
......
...@@ -29,12 +29,6 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do ...@@ -29,12 +29,6 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
end end
end end
let(:now) { Time.now.utc }
around do |example|
Timecop.freeze(now) { example.run }
end
let(:calculation) { -> { 2 + 2 } } let(:calculation) { -> { 2 + 2 } }
let(:cache_key) { "foo:666" } let(:cache_key) { "foo:666" }
let(:instance) { CacheTest.new(666, &calculation) } let(:instance) { CacheTest.new(666, &calculation) }
...@@ -49,13 +43,15 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do ...@@ -49,13 +43,15 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
context 'when cache is empty' do context 'when cache is empty' do
it { is_expected.to be_nil } it { is_expected.to be_nil }
it 'queues a background worker' do it 'enqueues a background worker to bootstrap the cache' do
expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666) expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666)
go! go!
end end
it 'updates the cache lifespan' do it 'updates the cache lifespan' do
expect(reactive_cache_alive?(instance)).to be_falsy
go! go!
expect(reactive_cache_alive?(instance)).to be_truthy expect(reactive_cache_alive?(instance)).to be_truthy
...@@ -69,6 +65,18 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do ...@@ -69,6 +65,18 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
it { is_expected.to eq(2) } it { is_expected.to eq(2) }
it 'does not enqueue a background worker' do
expect(ReactiveCachingWorker).not_to receive(:perform_async)
go!
end
it 'updates the cache lifespan' do
expect(Rails.cache).to receive(:write).with(alive_reactive_cache_key(instance), true, expires_in: anything)
go!
end
context 'and expired' do context 'and expired' do
before do before do
invalidate_reactive_cache(instance) invalidate_reactive_cache(instance)
......
...@@ -344,12 +344,12 @@ describe Project do ...@@ -344,12 +344,12 @@ describe Project do
describe 'project token' do describe 'project token' do
it 'sets an random token if none provided' do it 'sets an random token if none provided' do
project = FactoryBot.create :project, runners_token: '' project = FactoryBot.create(:project, runners_token: '')
expect(project.runners_token).not_to eq('') expect(project.runners_token).not_to eq('')
end end
it 'does not set an random token if one provided' do it 'does not set an random token if one provided' do
project = FactoryBot.create :project, runners_token: 'my-token' project = FactoryBot.create(:project, runners_token: 'my-token')
expect(project.runners_token).to eq('my-token') expect(project.runners_token).to eq('my-token')
end end
end end
...@@ -682,7 +682,7 @@ describe Project do ...@@ -682,7 +682,7 @@ describe Project do
describe '#to_param' do describe '#to_param' do
context 'with namespace' do context 'with namespace' do
before do before do
@group = create :group, name: 'gitlab' @group = create(:group, name: 'gitlab')
@project = create(:project, name: 'gitlabhq', namespace: @group) @project = create(:project, name: 'gitlabhq', namespace: @group)
end end
...@@ -995,8 +995,8 @@ describe Project do ...@@ -995,8 +995,8 @@ describe Project do
describe '#star_count' do describe '#star_count' do
it 'counts stars from multiple users' do it 'counts stars from multiple users' do
user1 = create :user user1 = create(:user)
user2 = create :user user2 = create(:user)
project = create(:project, :public) project = create(:project, :public)
expect(project.star_count).to eq(0) expect(project.star_count).to eq(0)
...@@ -1018,7 +1018,7 @@ describe Project do ...@@ -1018,7 +1018,7 @@ describe Project do
end end
it 'counts stars on the right project' do it 'counts stars on the right project' do
user = create :user user = create(:user)
project1 = create(:project, :public) project1 = create(:project, :public)
project2 = create(:project, :public) project2 = create(:project, :public)
...@@ -1277,9 +1277,9 @@ describe Project do ...@@ -1277,9 +1277,9 @@ describe Project do
describe '#any_runners?' do describe '#any_runners?' do
context 'shared runners' do context 'shared runners' do
let(:project) { create :project, shared_runners_enabled: shared_runners_enabled } let(:project) { create(:project, shared_runners_enabled: shared_runners_enabled) }
let(:specific_runner) { create :ci_runner } let(:specific_runner) { create(:ci_runner) }
let(:shared_runner) { create :ci_runner, :shared } let(:shared_runner) { create(:ci_runner, :shared) }
context 'for shared runners disabled' do context 'for shared runners disabled' do
let(:shared_runners_enabled) { false } let(:shared_runners_enabled) { false }
...@@ -1337,9 +1337,9 @@ describe Project do ...@@ -1337,9 +1337,9 @@ describe Project do
end end
context 'group runners' do context 'group runners' do
let(:project) { create :project, group_runners_enabled: group_runners_enabled } let(:project) { create(:project, group_runners_enabled: group_runners_enabled) }
let(:group) { create :group, projects: [project] } let(:group) { create(:group, projects: [project]) }
let(:group_runner) { create :ci_runner, groups: [group] } let(:group_runner) { create(:ci_runner, groups: [group]) }
context 'for group runners disabled' do context 'for group runners disabled' do
let(:group_runners_enabled) { false } let(:group_runners_enabled) { false }
...@@ -1421,7 +1421,7 @@ describe Project do ...@@ -1421,7 +1421,7 @@ describe Project do
end end
describe '#pages_deployed?' do describe '#pages_deployed?' do
let(:project) { create :project } let(:project) { create(:project) }
subject { project.pages_deployed? } subject { project.pages_deployed? }
...@@ -1439,8 +1439,8 @@ describe Project do ...@@ -1439,8 +1439,8 @@ describe Project do
end end
describe '#pages_url' do describe '#pages_url' do
let(:group) { create :group, name: group_name } let(:group) { create(:group, name: group_name) }
let(:project) { create :project, namespace: group, name: project_name } let(:project) { create(:project, namespace: group, name: project_name) }
let(:domain) { 'Example.com' } let(:domain) { 'Example.com' }
subject { project.pages_url } subject { project.pages_url }
...@@ -1466,8 +1466,8 @@ describe Project do ...@@ -1466,8 +1466,8 @@ describe Project do
end end
describe '#pages_group_url' do describe '#pages_group_url' do
let(:group) { create :group, name: group_name } let(:group) { create(:group, name: group_name) }
let(:project) { create :project, namespace: group, name: project_name } let(:project) { create(:project, namespace: group, name: project_name) }
let(:domain) { 'Example.com' } let(:domain) { 'Example.com' }
let(:port) { 1234 } let(:port) { 1234 }
...@@ -1584,8 +1584,8 @@ describe Project do ...@@ -1584,8 +1584,8 @@ describe Project do
let(:private_group) { create(:group, visibility_level: 0) } let(:private_group) { create(:group, visibility_level: 0) }
let(:internal_group) { create(:group, visibility_level: 10) } let(:internal_group) { create(:group, visibility_level: 10) }
let(:private_project) { create :project, :private, group: private_group } let(:private_project) { create(:project, :private, group: private_group) }
let(:internal_project) { create :project, :internal, group: internal_group } let(:internal_project) { create(:project, :internal, group: internal_group) }
context 'when group is private project can not be internal' do context 'when group is private project can not be internal' do
it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey } it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey }
...@@ -2074,8 +2074,6 @@ describe Project do ...@@ -2074,8 +2074,6 @@ describe Project do
update_remote_mirrors update_remote_mirrors
end end
# TODO: study if remote_mirror_available_overridden is still a necessary attribute considering that
# it is no longer under any license
it 'does nothing when remote mirror is disabled globally and not overridden' do it 'does nothing when remote mirror is disabled globally and not overridden' do
stub_application_setting(mirror_available: false) stub_application_setting(mirror_available: false)
project.remote_mirror_available_overridden = false project.remote_mirror_available_overridden = false
...@@ -2815,8 +2813,8 @@ describe Project do ...@@ -2815,8 +2813,8 @@ describe Project do
end end
describe '#pages_url' do describe '#pages_url' do
let(:group) { create :group, name: 'Group' } let(:group) { create(:group, name: 'Group') }
let(:nested_group) { create :group, parent: group } let(:nested_group) { create(:group, parent: group) }
let(:domain) { 'Example.com' } let(:domain) { 'Example.com' }
subject { project.pages_url } subject { project.pages_url }
...@@ -2827,7 +2825,7 @@ describe Project do ...@@ -2827,7 +2825,7 @@ describe Project do
end end
context 'top-level group' do context 'top-level group' do
let(:project) { create :project, namespace: group, name: project_name } let(:project) { create(:project, namespace: group, name: project_name) }
context 'group page' do context 'group page' do
let(:project_name) { 'group.example.com' } let(:project_name) { 'group.example.com' }
...@@ -2843,7 +2841,7 @@ describe Project do ...@@ -2843,7 +2841,7 @@ describe Project do
end end
context 'nested group' do context 'nested group' do
let(:project) { create :project, namespace: nested_group, name: project_name } let(:project) { create(:project, namespace: nested_group, name: project_name) }
let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" } let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" }
context 'group page' do context 'group page' do
...@@ -2861,7 +2859,7 @@ describe Project do ...@@ -2861,7 +2859,7 @@ describe Project do
end end
describe '#http_url_to_repo' do describe '#http_url_to_repo' do
let(:project) { create :project } let(:project) { create(:project) }
it 'returns the url to the repo without a username' do it 'returns the url to the repo without a username' do
expect(project.http_url_to_repo).to eq("#{project.web_url}.git") expect(project.http_url_to_repo).to eq("#{project.web_url}.git")
......
...@@ -46,6 +46,7 @@ describe API::Runners do ...@@ -46,6 +46,7 @@ describe API::Runners do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response[0]).to have_key('ip_address')
expect(descriptions).to contain_exactly( expect(descriptions).to contain_exactly(
'Project runner', 'Two projects runner' 'Project runner', 'Two projects runner'
) )
...@@ -59,6 +60,7 @@ describe API::Runners do ...@@ -59,6 +60,7 @@ describe API::Runners do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response[0]).to have_key('ip_address')
expect(shared).to be_falsey expect(shared).to be_falsey
end end
...@@ -87,6 +89,7 @@ describe API::Runners do ...@@ -87,6 +89,7 @@ describe API::Runners do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response[0]).to have_key('ip_address')
expect(shared).to be_truthy expect(shared).to be_truthy
end end
end end
...@@ -106,6 +109,7 @@ describe API::Runners do ...@@ -106,6 +109,7 @@ describe API::Runners do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response[0]).to have_key('ip_address')
expect(shared).to be_falsey expect(shared).to be_falsey
end end
...@@ -515,6 +519,7 @@ describe API::Runners do ...@@ -515,6 +519,7 @@ describe API::Runners do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response[0]).to have_key('ip_address')
expect(shared).to be_truthy expect(shared).to be_truthy
end end
end end
......
...@@ -30,6 +30,16 @@ module MigrationsHelpers ...@@ -30,6 +30,16 @@ module MigrationsHelpers
end end
end end
def foreign_key_exists?(source, target = nil, column: nil)
ActiveRecord::Base.connection.foreign_keys(source).any? do |key|
if column
key.options[:column].to_s == column.to_s
else
key.to_table.to_s == target.to_s
end
end
end
def reset_column_in_all_models def reset_column_in_all_models
clear_schema_cache! clear_schema_cache!
......
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