Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/serializers/diff_file_entity.rb14
-rw-r--r--changelogs/unreleased/sy-grafana-default-times.yml5
-rw-r--r--doc/api/members.md4
-rw-r--r--doc/development/import_export.md43
-rw-r--r--doc/development/what_requires_downtime.md3
-rw-r--r--doc/user/project/integrations/prometheus.md2
-rw-r--r--doc/user/project/settings/import_export.md33
-rw-r--r--lib/banzai/filter/inline_grafana_metrics_filter.rb33
-rw-r--r--lib/gitlab/import_export/project/tree_restorer.rb2
-rw-r--r--lib/gitlab/import_export/project/tree_saver.rb2
-rw-r--r--lib/gitlab/import_export/relation_rename_service.rb48
-rw-r--r--lib/grafana/time_window.rb130
-rw-r--r--qa/qa/page/project/issue/show.rb2
-rwxr-xr-xscripts/trigger-build18
-rw-r--r--spec/features/merge_request/maintainer_edits_fork_spec.rb2
-rw-r--r--spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb2
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/project.json2
-rw-r--r--spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb47
-rw-r--r--spec/lib/gitlab/import_export/import_test_coverage_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/relation_rename_service_spec.rb122
-rw-r--r--spec/lib/grafana/time_window_spec.rb115
-rw-r--r--spec/support/shared_examples/serializers/diff_file_entity_shared_examples.rb2
22 files changed, 376 insertions, 257 deletions
diff --git a/app/serializers/diff_file_entity.rb b/app/serializers/diff_file_entity.rb
index af7d1172f17..c3826692c52 100644
--- a/app/serializers/diff_file_entity.rb
+++ b/app/serializers/diff_file_entity.rb
@@ -53,7 +53,7 @@ class DiffFileEntity < DiffFileBaseEntity
end
# Used for inline diffs
- expose :highlighted_diff_lines, using: DiffLineEntity, if: -> (diff_file, options) { inline_diff_view?(options) && diff_file.text? } do |diff_file|
+ expose :highlighted_diff_lines, using: DiffLineEntity, if: -> (diff_file, options) { inline_diff_view?(options, diff_file) && diff_file.text? } do |diff_file|
diff_file.diff_lines_for_serializer
end
@@ -62,19 +62,19 @@ class DiffFileEntity < DiffFileBaseEntity
end
# Used for parallel diffs
- expose :parallel_diff_lines, using: DiffLineParallelEntity, if: -> (diff_file, options) { parallel_diff_view?(options) && diff_file.text? }
+ expose :parallel_diff_lines, using: DiffLineParallelEntity, if: -> (diff_file, options) { parallel_diff_view?(options, diff_file) && diff_file.text? }
private
- def parallel_diff_view?(options)
- return true unless Feature.enabled?(:single_mr_diff_view)
+ def parallel_diff_view?(options, diff_file)
+ return true unless Feature.enabled?(:single_mr_diff_view, diff_file.repository.project)
# If we're not rendering inline, we must be rendering parallel
- !inline_diff_view?(options)
+ !inline_diff_view?(options, diff_file)
end
- def inline_diff_view?(options)
- return true unless Feature.enabled?(:single_mr_diff_view)
+ def inline_diff_view?(options, diff_file)
+ return true unless Feature.enabled?(:single_mr_diff_view, diff_file.repository.project)
# If nothing is present, inline will be the default.
options.fetch(:diff_view, :inline).to_sym == :inline
diff --git a/changelogs/unreleased/sy-grafana-default-times.yml b/changelogs/unreleased/sy-grafana-default-times.yml
new file mode 100644
index 00000000000..54b4f76c082
--- /dev/null
+++ b/changelogs/unreleased/sy-grafana-default-times.yml
@@ -0,0 +1,5 @@
+---
+title: Allow default time window on grafana embeds
+merge_request: 21884
+author:
+type: changed
diff --git a/doc/api/members.md b/doc/api/members.md
index 69c52a54a8d..e9131e2d4c3 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -17,6 +17,8 @@ The access levels are defined in the `Gitlab::Access` module. Currently, these l
Gets a list of group or project members viewable by the authenticated user.
Returns only direct members and not inherited members through ancestors groups.
+This function takes pagination parameters `page` and `per_page` to restrict the list of users.
+
```plaintext
GET /groups/:id/members
GET /projects/:id/members
@@ -72,6 +74,8 @@ Gets a list of group or project members viewable by the authenticated user, incl
When a user is a member of the project/group and of one or more ancestor groups the user is returned only once with the project `access_level` (if exists)
or the `access_level` for the user in the first group which they belong to in the project groups ancestors chain.
+This function takes pagination parameters `page` and `per_page` to restrict the list of users.
+
```plaintext
GET /groups/:id/members/all
GET /projects/:id/members/all
diff --git a/doc/development/import_export.md b/doc/development/import_export.md
index 323ed48aaf9..252a57ce857 100644
--- a/doc/development/import_export.md
+++ b/doc/development/import_export.md
@@ -195,16 +195,17 @@ module Gitlab
The [current version history](../user/project/settings/import_export.md) also displays the equivalent GitLab version
and it is useful for knowing which versions won't be compatible between them.
-| GitLab version | Import/Export version |
-| ---------------- | --------------------- |
-| 11.1 to current | 0.2.4 |
-| 10.8 | 0.2.3 |
-| 10.4 | 0.2.2 |
-| ... | ... |
-| 8.10.3 | 0.1.3 |
-| 8.10.0 | 0.1.2 |
-| 8.9.5 | 0.1.1 |
-| 8.9.0 | 0.1.0 |
+| Exporting GitLab version | Importing GitLab version |
+| -------------------------- | -------------------------- |
+| 11.7 to current | 11.7 to current |
+| 11.1 to 11.6 | 11.1 to 11.6 |
+| 10.8 to 11.0 | 10.8 to 11.0 |
+| 10.4 to 10.7 | 10.4 to 10.7 |
+| ... | ... |
+| 8.10.3 to 8.11 | 8.10.3 to 8.11 |
+| 8.10.0 to 8.10.2 | 8.10.0 to 8.10.2 |
+| 8.9.5 to 8.9.11 | 8.9.5 to 8.9.11 |
+| 8.9.0 to 8.9.4 | 8.9.0 to 8.9.4 |
### When to bump the version up
@@ -223,28 +224,6 @@ Every time we bump the version, the integration specs will fail and can be fixed
bundle exec rake gitlab:import_export:bump_version
```
-### Renaming columns or models
-
-This is a relatively common occurrence that will require a version bump.
-
-There is also the _RC problem_ - GitLab.com runs an RC, prior to any customers,
-meaning that we want to bump the version up in the next version (or patch release).
-
-For example:
-
-1. Add rename to `RelationRenameService` in X.Y
-1. Remove it from `RelationRenameService` in X.Y + 1
-1. Bump Import/Export version in X.Y + 1
-
-```ruby
-module Gitlab
- module ImportExport
- class RelationRenameService
- RENAMES = {
- 'pipelines' => 'ci_pipelines' # Added in 11.6, remove in 11.7
- }.freeze
-```
-
## A quick dive into the code
### Import/Export configuration (`import_export.yml`)
diff --git a/doc/development/what_requires_downtime.md b/doc/development/what_requires_downtime.md
index a25d065f735..b7c667d034b 100644
--- a/doc/development/what_requires_downtime.md
+++ b/doc/development/what_requires_downtime.md
@@ -162,6 +162,9 @@ class CleanupUsersUpdatedAtRename < ActiveRecord::Migration[4.2]
end
```
+NOTE: **Note:** If you're renaming a large table, please carefully consider the state when the first migration has run but the second cleanup migration hasn't been run yet.
+With [Canary](https://about.gitlab.com/handbook/engineering/infrastructure/library/canary/) it is possible that the system runs in this state for a significant amount of time.
+
## Changing Column Constraints
Adding or removing a NOT NULL clause (or another constraint) can typically be
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index bbe2f88795e..475eb4a55b9 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -769,7 +769,7 @@ Prerequisites for embedding from a Grafana instance:
1. In the upper-left corner of the page, select a specific value for each variable required for the queries in the chart.
![Select Query Variables](img/select_query_variables_v12_5.png)
1. In Grafana, click on a panel's title, then click **Share** to open the panel's sharing dialog to the **Link** tab.
-1. If your Prometheus queries use Grafana's custom template variables, ensure that "Template variables" and "Current time range" options are toggled to **On**. Of Grafana global template variables, only `$__interval`, `$__from`, and `$__to` are currently supported.
+1. If your Prometheus queries use Grafana's custom template variables, ensure that "Template variables" option is toggled to **On**. Of Grafana global template variables, only `$__interval`, `$__from`, and `$__to` are currently supported. Toggle **On** the "Current time range" option to specify the time range of the chart. Otherwise, the default range will be the last 8 hours.
![Grafana Sharing Dialog](img/grafana_sharing_dialog_v12_5.png)
1. Click **Copy** to copy the URL to the clipboard.
1. In GitLab, paste the URL into a Markdown field and save. The chart will take a few moments to render.
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 1a4023b6ded..d32b4847230 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -42,22 +42,23 @@ Note the following:
The following table lists updates to Import/Export:
-| GitLab version | Import/Export schema version |
-| ---------------- | --------------------- |
-| 11.1 to current | 0.2.4 |
-| 10.8 | 0.2.3 |
-| 10.4 | 0.2.2 |
-| 10.3 | 0.2.1 |
-| 10.0 | 0.2.0 |
-| 9.4.0 | 0.1.8 |
-| 9.2.0 | 0.1.7 |
-| 8.17.0 | 0.1.6 |
-| 8.13.0 | 0.1.5 |
-| 8.12.0 | 0.1.4 |
-| 8.10.3 | 0.1.3 |
-| 8.10.0 | 0.1.2 |
-| 8.9.5 | 0.1.1 |
-| 8.9.0 | 0.1.0 |
+| Exporting GitLab version | Importing GitLab version |
+| -------------------------- | -------------------------- |
+| 11.7 to current | 11.7 to current |
+| 11.1 to 11.6 | 11.1 to 11.6 |
+| 10.8 to 11.0 | 10.8 to 11.0 |
+| 10.4 to 10.7 | 10.4 to 10.7 |
+| 10.3 | 10.3 |
+| 10.0 to 10.2 | 10.0 to 10.2 |
+| 9.4 to 9.6 | 9.4 to 9.6 |
+| 9.2 to 9.3 | 9.2 to 9.3 |
+| 8.17 to 9.1 | 8.17 to 9.1 |
+| 8.13 to 8.16 | 8.13 to 8.16 |
+| 8.12 | 8.12 |
+| 8.10.3 to 8.11 | 8.10.3 to 8.11 |
+| 8.10.0 to 8.10.2 | 8.10.0 to 8.10.2 |
+| 8.9.5 to 8.9.11 | 8.9.5 to 8.9.11 |
+| 8.9.0 to 8.9.4 | 8.9.0 to 8.9.4 |
Projects can be exported and imported only between versions of GitLab with matching Import/Export versions.
diff --git a/lib/banzai/filter/inline_grafana_metrics_filter.rb b/lib/banzai/filter/inline_grafana_metrics_filter.rb
index 69ae747333f..60a16b164af 100644
--- a/lib/banzai/filter/inline_grafana_metrics_filter.rb
+++ b/lib/banzai/filter/inline_grafana_metrics_filter.rb
@@ -13,13 +13,16 @@ module Banzai
super
end
+ # @return [Hash<Symbol, String>] with keys :grafana_url, :start, and :end
def embed_params(node)
query_params = Gitlab::Metrics::Dashboard::Url.parse_query(node['href'])
- return unless [:panelId, :from, :to].all? do |param|
- query_params.include?(param)
- end
- { url: node['href'], start: query_params[:from], end: query_params[:to] }
+ return unless query_params.include?(:panelId)
+
+ time_window = Grafana::TimeWindow.new(query_params[:from], query_params[:to])
+ url = url_with_window(node['href'], query_params, time_window.in_milliseconds)
+
+ { grafana_url: url }.merge(time_window.formatted)
end
# Selects any links with an href contains the configured
@@ -44,18 +47,24 @@ module Banzai
Gitlab::Routing.url_helpers.project_grafana_api_metrics_dashboard_url(
project,
embedded: true,
- grafana_url: params[:url],
- start: format_time(params[:start]),
- end: format_time(params[:end])
+ **params
)
end
- # Formats a timestamp from Grafana for compatibility with
- # parsing in JS via `new Date(timestamp)`
+ # If the provided url is missing time window parameters,
+ # this inserts the default window into the url, allowing
+ # the embed service to correctly format prometheus
+ # queries during embed processing.
#
- # @param time [String] Represents miliseconds since epoch
- def format_time(time)
- Time.at(time.to_i / 1000).utc.strftime('%FT%TZ')
+ # @param url [String]
+ # @param query_params [Hash<Symbol, String>]
+ # @param time_window_params [Hash<Symbol, Integer>]
+ # @return [String]
+ def url_with_window(url, query_params, time_window_params)
+ uri = URI(url)
+ uri.query = time_window_params.merge(query_params).to_query
+
+ uri.to_s
end
# Fetches a dashboard and caches the result for the
diff --git a/lib/gitlab/import_export/project/tree_restorer.rb b/lib/gitlab/import_export/project/tree_restorer.rb
index a5123f16dbc..904cb461ac3 100644
--- a/lib/gitlab/import_export/project/tree_restorer.rb
+++ b/lib/gitlab/import_export/project/tree_restorer.rb
@@ -21,8 +21,6 @@ module Gitlab
@tree_hash = read_tree_hash
@project_members = @tree_hash.delete('project_members')
- RelationRenameService.rename(@tree_hash)
-
if relation_tree_restorer.restore
import_failure_service.with_retry(action: 'set_latest_merge_request_diff_ids!') do
@project.merge_requests.set_latest_merge_request_diff_ids!
diff --git a/lib/gitlab/import_export/project/tree_saver.rb b/lib/gitlab/import_export/project/tree_saver.rb
index 58f33a04851..32b3b518ece 100644
--- a/lib/gitlab/import_export/project/tree_saver.rb
+++ b/lib/gitlab/import_export/project/tree_saver.rb
@@ -35,8 +35,6 @@ module Gitlab
end
project_tree['project_members'] += group_members_array
-
- RelationRenameService.add_new_associations(project_tree)
end
def reader
diff --git a/lib/gitlab/import_export/relation_rename_service.rb b/lib/gitlab/import_export/relation_rename_service.rb
deleted file mode 100644
index 03aaa6aefc3..00000000000
--- a/lib/gitlab/import_export/relation_rename_service.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-# This class is intended to help with relation renames within Gitlab versions
-# and allow compatibility between versions.
-# If you have to change one relationship name that is imported/exported,
-# you should add it to the RENAMES constant indicating the old name and the
-# new one.
-# The behavior of these renamed relationships should be transient and it should
-# only last one release until you completely remove the renaming from the list.
-#
-# When importing, this class will check the hash and:
-# - if only the old relationship name is found, it will rename it with the new one
-# - if only the new relationship name is found, it will do nothing
-# - if it finds both, it will use the new relationship data
-#
-# When exporting, this class will duplicate the keys in the resulting file.
-# This way, if we open the file in an old version of the exporter it will work
-# and also it will with the newer versions.
-module Gitlab
- module ImportExport
- class RelationRenameService
- RENAMES = {
- 'pipelines' => 'ci_pipelines' # Added in 11.6, remove in 11.7
- }.freeze
-
- def self.rename(tree_hash)
- return unless tree_hash&.present?
-
- RENAMES.each do |old_name, new_name|
- old_entry = tree_hash.delete(old_name)
-
- next if tree_hash[new_name]
- next unless old_entry
-
- tree_hash[new_name] = old_entry
- end
- end
-
- def self.add_new_associations(tree_hash)
- RENAMES.each do |old_name, new_name|
- next if tree_hash.key?(old_name)
-
- tree_hash[old_name] = tree_hash[new_name]
- end
- end
- end
- end
-end
diff --git a/lib/grafana/time_window.rb b/lib/grafana/time_window.rb
new file mode 100644
index 00000000000..111e3ab7de2
--- /dev/null
+++ b/lib/grafana/time_window.rb
@@ -0,0 +1,130 @@
+# frozen_string_literal: true
+
+module Grafana
+ # Allows for easy formatting and manipulations of timestamps
+ # coming from a Grafana url
+ class TimeWindow
+ include ::Gitlab::Utils::StrongMemoize
+
+ def initialize(from, to)
+ @from = from
+ @to = to
+ end
+
+ def formatted
+ {
+ start: window[:from].formatted,
+ end: window[:to].formatted
+ }
+ end
+
+ def in_milliseconds
+ window.transform_values(&:to_ms)
+ end
+
+ private
+
+ def window
+ strong_memoize(:window) do
+ specified_window
+ rescue Timestamp::Error
+ default_window
+ end
+ end
+
+ def specified_window
+ RangeWithDefaults.new(
+ from: Timestamp.from_ms_since_epoch(@from),
+ to: Timestamp.from_ms_since_epoch(@to)
+ ).to_hash
+ end
+
+ def default_window
+ RangeWithDefaults.new.to_hash
+ end
+ end
+
+ # For incomplete time ranges, adds default parameters to
+ # achieve a complete range. If both full range is provided,
+ # range will be returned.
+ class RangeWithDefaults
+ DEFAULT_RANGE = 8.hours
+
+ # @param from [Grafana::Timestamp, nil] Start of the expected range
+ # @param to [Grafana::Timestamp, nil] End of the expected range
+ def initialize(from: nil, to: nil)
+ @from = from
+ @to = to
+
+ apply_defaults!
+ end
+
+ def to_hash
+ { from: @from, to: @to }.compact
+ end
+
+ private
+
+ def apply_defaults!
+ @to ||= @from ? relative_end : Timestamp.new(Time.now)
+ @from ||= relative_start
+ end
+
+ def relative_start
+ Timestamp.new(DEFAULT_RANGE.before(@to.time))
+ end
+
+ def relative_end
+ Timestamp.new(DEFAULT_RANGE.since(@from.time))
+ end
+ end
+
+ # Offers a consistent API for timestamps originating from
+ # Grafana or other sources, allowing for formatting of timestamps
+ # as consumed by Grafana-related utilities
+ class Timestamp
+ Error = Class.new(StandardError)
+
+ attr_accessor :time
+
+ # @param timestamp [Time]
+ def initialize(time)
+ @time = time
+ end
+
+ # Formats a timestamp from Grafana for compatibility with
+ # parsing in JS via `new Date(timestamp)`
+ def formatted
+ time.utc.strftime('%FT%TZ')
+ end
+
+ # Converts to milliseconds since epoch
+ def to_ms
+ time.to_i * 1000
+ end
+
+ class << self
+ # @param time [String] Representing milliseconds since epoch.
+ # This is what JS "decided" unix is.
+ def from_ms_since_epoch(time)
+ return if time.nil?
+
+ raise Error.new('Expected milliseconds since epoch') unless ms_since_epoch?(time)
+
+ new(cast_ms_to_time(time))
+ end
+
+ private
+
+ def cast_ms_to_time(time)
+ Time.at(time.to_i / 1000.0)
+ end
+
+ def ms_since_epoch?(time)
+ ms = time.to_i
+
+ ms.to_s == time && ms.bit_length < 64
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index a56083ea25c..8365ecb6348 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -127,7 +127,7 @@ module QA
click_element(:edit_link_labels)
labels.each do |label|
- has_element?(:labels_block, text: label)
+ has_element?(:labels_block, text: label, wait: 0)
end
refresh
diff --git a/scripts/trigger-build b/scripts/trigger-build
index c14a3633075..6359446ecd1 100755
--- a/scripts/trigger-build
+++ b/scripts/trigger-build
@@ -16,6 +16,14 @@ module Trigger
%w[gitlab gitlab-ee].include?(ENV['CI_PROJECT_NAME'])
end
+ def self.non_empty_variable_value(variable)
+ variable_value = ENV[variable]
+
+ return if variable_value.nil? || variable_value.empty?
+
+ variable_value
+ end
+
class Base
def invoke!(post_comment: false, downstream_job_name: nil)
pipeline_variables = variables
@@ -84,14 +92,15 @@ module Trigger
end
def base_variables
- # Use CI_MERGE_REQUEST_SOURCE_BRANCH_SHA for omnibus checkouts due to pipeline for merged results
+ # Use CI_MERGE_REQUEST_SOURCE_BRANCH_SHA for omnibus checkouts due to pipeline for merged results,
+ # and fallback to CI_COMMIT_SHA for the `detached` pipelines.
{
'GITLAB_REF_SLUG' => ENV['CI_COMMIT_TAG'] ? ENV['CI_COMMIT_REF_NAME'] : ENV['CI_COMMIT_REF_SLUG'],
'TRIGGERED_USER' => ENV['TRIGGERED_USER'] || ENV['GITLAB_USER_NAME'],
'TRIGGER_SOURCE' => ENV['CI_JOB_URL'],
'TOP_UPSTREAM_SOURCE_PROJECT' => ENV['CI_PROJECT_PATH'],
'TOP_UPSTREAM_SOURCE_JOB' => ENV['CI_JOB_URL'],
- 'TOP_UPSTREAM_SOURCE_SHA' => ENV['CI_MERGE_REQUEST_SOURCE_BRANCH_SHA'],
+ 'TOP_UPSTREAM_SOURCE_SHA' => Trigger.non_empty_variable_value('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA') || ENV['CI_COMMIT_SHA'],
'TOP_UPSTREAM_SOURCE_REF' => ENV['CI_COMMIT_REF_NAME'],
'TOP_UPSTREAM_MERGE_REQUEST_PROJECT_ID' => ENV['CI_MERGE_REQUEST_PROJECT_ID'],
'TOP_UPSTREAM_MERGE_REQUEST_IID' => ENV['CI_MERGE_REQUEST_IID']
@@ -127,8 +136,9 @@ module Trigger
def extra_variables
# Use CI_MERGE_REQUEST_SOURCE_BRANCH_SHA for omnibus checkouts due to pipeline for merged results
+ # and fallback to CI_COMMIT_SHA for the `detached` pipelines.
{
- 'GITLAB_VERSION' => ENV['CI_MERGE_REQUEST_SOURCE_BRANCH_SHA'],
+ 'GITLAB_VERSION' => Trigger.non_empty_variable_value('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA') || ENV['CI_COMMIT_SHA'],
'ALTERNATIVE_SOURCES' => 'true',
'ee' => Trigger.ee? ? 'true' : 'false',
'QA_BRANCH' => ENV['QA_BRANCH'] || 'master'
@@ -194,7 +204,7 @@ module Trigger
Gitlab.create_commit_comment(
ENV['CI_PROJECT_PATH'],
- ENV['CI_MERGE_REQUEST_SOURCE_BRANCH_SHA'],
+ Trigger.non_empty_variable_value('CI_MERGE_REQUEST_SOURCE_BRANCH_SHA') || ENV['CI_COMMIT_SHA'],
"The [`#{ENV['CI_JOB_NAME']}`](#{ENV['CI_JOB_URL']}) job from pipeline #{ENV['CI_PIPELINE_URL']} triggered #{downstream_pipeline.web_url} downstream.")
rescue Gitlab::Error::Error => error
diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb
index 17ff494a6fa..f1ee6aaa897 100644
--- a/spec/features/merge_request/maintainer_edits_fork_spec.rb
+++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb
@@ -20,7 +20,7 @@ describe 'a maintainer edits files on a source-branch of an MR from a fork', :js
end
before do
- stub_feature_flags(web_ide_default: false, single_mr_diff_view: false, code_navigation: false)
+ stub_feature_flags(web_ide_default: false, single_mr_diff_view: { enabled: false, thing: target_project }, code_navigation: false)
target_project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb b/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
index 92d90926c0a..8633d67f875 100644
--- a/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
+++ b/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
@@ -10,7 +10,7 @@ describe 'Batch diffs', :js do
let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'master', target_branch: 'empty-branch') }
before do
- stub_feature_flags(single_mr_diff_view: true)
+ stub_feature_flags(single_mr_diff_view: { enabled: true, thing: project })
stub_feature_flags(diffs_batch_load: true)
sign_in(project.owner)
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/project.json b/spec/fixtures/lib/gitlab/import_export/complex/project.json
index 4d6211a1251..fae02540868 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/project.json
+++ b/spec/fixtures/lib/gitlab/import_export/complex/project.json
@@ -6318,7 +6318,7 @@
]
}
],
- "pipelines": [
+ "ci_pipelines": [
{
"id": 36,
"project_id": 5,
diff --git a/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb b/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
index 9ac06a90efd..2092b9e9db8 100644
--- a/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
@@ -10,18 +10,20 @@ describe Banzai::Filter::InlineGrafanaMetricsFilter do
let(:input) { %(<a href="#{trigger_url}">example</a>) }
let(:doc) { filter(input) }
+ let(:embed_url) { doc.at_css('.js-render-metrics')['data-dashboard-url'] }
+
let(:dashboard_path) do
'/d/XDaNK6amz/gitlab-omnibus-redis' \
- '?from=1570397739557&to=1570484139557' \
- '&var-instance=All&panelId=14'
+ '?from=1570397739557&panelId=14' \
+ '&to=1570484139557&var-instance=All'
end
let(:trigger_url) { grafana_integration.grafana_url + dashboard_path }
let(:dashboard_url) do
urls.project_grafana_api_metrics_dashboard_url(
project,
- embedded: true,
grafana_url: trigger_url,
+ embedded: true,
start: "2019-10-06T21:35:39Z",
end: "2019-10-07T21:35:39Z"
)
@@ -29,6 +31,10 @@ describe Banzai::Filter::InlineGrafanaMetricsFilter do
it_behaves_like 'a metrics embed filter'
+ around do |example|
+ Timecop.freeze(Time.utc(2019, 3, 17, 13, 10)) { example.run }
+ end
+
context 'when grafana is not configured' do
before do
allow(project).to receive(:grafana_integration).and_return(nil)
@@ -39,7 +45,7 @@ describe Banzai::Filter::InlineGrafanaMetricsFilter do
end
end
- context 'when parameters are missing' do
+ context 'when "panelId" parameter is missing' do
let(:dashboard_path) { '/d/XDaNK6amz/gitlab-omnibus-redis' }
it 'leaves the markdown unchanged' do
@@ -47,6 +53,39 @@ describe Banzai::Filter::InlineGrafanaMetricsFilter do
end
end
+ context 'when time window parameters are missing' do
+ let(:dashboard_path) { '/d/XDaNK6amz/gitlab-omnibus-redis?panelId=16' }
+
+ it 'sets the window to the last 8 hrs' do
+ expect(embed_url).to include(
+ 'from%3D1552799400000', 'to%3D1552828200000',
+ 'start=2019-03-17T05%3A10%3A00Z', 'end=2019-03-17T13%3A10%3A00Z'
+ )
+ end
+ end
+
+ context 'when "to" parameter is missing' do
+ let(:dashboard_path) { '/d/XDaNK6amz/gitlab-omnibus-redis?panelId=16&from=1570397739557' }
+
+ it 'sets "to" to 8 hrs after "from"' do
+ expect(embed_url).to include(
+ 'from%3D1570397739557', 'to%3D1570426539000',
+ 'start=2019-10-06T21%3A35%3A39Z', 'end=2019-10-07T05%3A35%3A39Z'
+ )
+ end
+ end
+
+ context 'when "from" parameter is missing' do
+ let(:dashboard_path) { '/d/XDaNK6amz/gitlab-omnibus-redis?panelId=16&to=1570484139557' }
+
+ it 'sets "from" to 8 hrs before "to"' do
+ expect(embed_url).to include(
+ 'from%3D1570455339000', 'to%3D1570484139557',
+ 'start=2019-10-07T13%3A35%3A39Z', 'end=2019-10-07T21%3A35%3A39Z'
+ )
+ end
+ end
+
private
# Nokogiri escapes the URLs, but we don't care about that
diff --git a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
index 97d5ce07d47..335b0031147 100644
--- a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
+++ b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
@@ -89,8 +89,6 @@ describe 'Test coverage of the Project Import' do
def relations_from_json(json_file)
json = ActiveSupport::JSON.decode(IO.read(json_file))
- Gitlab::ImportExport::RelationRenameService.rename(json)
-
[].tap {|res| gather_relations({ project: json }, res, [])}
.map {|relation_names| relation_names.join('.')}
end
diff --git a/spec/lib/gitlab/import_export/relation_rename_service_spec.rb b/spec/lib/gitlab/import_export/relation_rename_service_spec.rb
deleted file mode 100644
index 2e251154e9f..00000000000
--- a/spec/lib/gitlab/import_export/relation_rename_service_spec.rb
+++ /dev/null
@@ -1,122 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe Gitlab::ImportExport::RelationRenameService do
- include ImportExport::CommonUtil
-
- let(:renames) do
- {
- 'example_relation1' => 'new_example_relation1',
- 'example_relation2' => 'new_example_relation2'
- }
- end
-
- let(:user) { create(:admin) }
- let(:group) { create(:group, :nested) }
- let!(:project) { create(:project, :builds_disabled, :issues_disabled, group: group, name: 'project', path: 'project') }
- let(:shared) { project.import_export_shared }
-
- before do
- stub_const("#{described_class}::RENAMES", renames)
- end
-
- context 'when importing' do
- let(:project_tree_restorer) { Gitlab::ImportExport::Project::TreeRestorer.new(user: user, shared: shared, project: project) }
- let(:file_content) { IO.read(File.join(shared.export_path, 'project.json')) }
- let(:json_file) { ActiveSupport::JSON.decode(file_content) }
-
- before do
- setup_import_export_config('complex')
-
- allow(ActiveSupport::JSON).to receive(:decode).and_call_original
- allow(ActiveSupport::JSON).to receive(:decode).with(file_content).and_return(json_file)
- end
-
- context 'when the file has only old relationship names' do
- # Configuring the json as an old version exported file, with only
- # the previous association with the old name
- before do
- renames.each do |old_name, _|
- json_file[old_name.to_s] = []
- end
- end
-
- it 'renames old relationships to the new name' do
- expect(json_file.keys).to include(*renames.keys)
-
- project_tree_restorer.restore
-
- expect(json_file.keys).to include(*renames.values)
- expect(json_file.keys).not_to include(*renames.keys)
- end
- end
-
- context 'when the file has both the old and new relationships' do
- # Configuring the json as the new version exported file, with both
- # the old association name and the new one
- before do
- renames.each do |old_name, new_name|
- json_file[old_name.to_s] = [1]
- json_file[new_name.to_s] = [2]
- end
- end
-
- it 'uses the new relationships and removes the old ones from the hash' do
- expect(json_file.keys).to include(*renames.keys)
-
- project_tree_restorer.restore
-
- expect(json_file.keys).to include(*renames.values)
- expect(json_file.values_at(*renames.values).flatten.uniq.first).to eq 2
- expect(json_file.keys).not_to include(*renames.keys)
- end
- end
-
- context 'when the file has only new relationship names' do
- # Configuring the json as the future version exported file, with only
- # the new association name
- before do
- renames.each do |_, new_name|
- json_file[new_name.to_s] = []
- end
- end
-
- it 'uses the new relationships' do
- expect(json_file.keys).not_to include(*renames.keys)
-
- project_tree_restorer.restore
-
- expect(json_file.keys).to include(*renames.values)
- end
- end
- end
-
- context 'when exporting' do
- let(:export_content_path) { project_tree_saver.full_path }
- let(:export_content_hash) { ActiveSupport::JSON.decode(File.read(export_content_path)) }
- let(:injected_hash) { renames.values.product([{}]).to_h }
- let(:relation_tree_saver) { Gitlab::ImportExport::RelationTreeSaver.new }
-
- let(:project_tree_saver) do
- Gitlab::ImportExport::Project::TreeSaver.new(
- project: project, current_user: user, shared: shared)
- end
-
- before do
- allow(project_tree_saver).to receive(:tree_saver).and_return(relation_tree_saver)
- end
-
- it 'adds old relationships to the exported file' do
- # we inject relations with new names that should be rewritten
- expect(relation_tree_saver).to receive(:serialize).and_wrap_original do |method, *args|
- method.call(*args).merge(injected_hash)
- end
-
- expect(project_tree_saver.save).to eq(true)
-
- expect(export_content_hash.keys).to include(*renames.keys)
- expect(export_content_hash.keys).to include(*renames.values)
- end
- end
-end
diff --git a/spec/lib/grafana/time_window_spec.rb b/spec/lib/grafana/time_window_spec.rb
new file mode 100644
index 00000000000..e70861658ca
--- /dev/null
+++ b/spec/lib/grafana/time_window_spec.rb
@@ -0,0 +1,115 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Grafana::TimeWindow do
+ let(:from) { '1552799400000' }
+ let(:to) { '1552828200000' }
+
+ around do |example|
+ Timecop.freeze(Time.utc(2019, 3, 17, 13, 10)) { example.run }
+ end
+
+ describe '#formatted' do
+ subject { described_class.new(from, to).formatted }
+
+ it { is_expected.to eq(start: "2019-03-17T05:10:00Z", end: "2019-03-17T13:10:00Z") }
+ end
+
+ describe '#in_milliseconds' do
+ subject { described_class.new(from, to).in_milliseconds }
+
+ it { is_expected.to eq(from: 1552799400000, to: 1552828200000) }
+
+ context 'when non-unix parameters are provided' do
+ let(:to) { Time.now.to_s }
+
+ let(:default_from) { 8.hours.ago.to_i * 1000 }
+ let(:default_to) { Time.now.to_i * 1000 }
+
+ it { is_expected.to eq(from: default_from, to: default_to) }
+ end
+ end
+end
+
+describe Grafana::RangeWithDefaults do
+ let(:from) { Grafana::Timestamp.from_ms_since_epoch('1552799400000') }
+ let(:to) { Grafana::Timestamp.from_ms_since_epoch('1552828200000') }
+
+ around do |example|
+ Timecop.freeze(Time.utc(2019, 3, 17, 13, 10)) { example.run }
+ end
+
+ describe '#to_hash' do
+ subject { described_class.new(from: from, to: to).to_hash }
+
+ it { is_expected.to eq(from: from, to: to) }
+
+ context 'when only "to" is provided' do
+ let(:from) { nil }
+
+ it 'has the expected properties' do
+ expect(subject[:to]).to eq(to)
+ expect(subject[:from].time).to eq(to.time - 8.hours)
+ end
+ end
+
+ context 'when only "from" is provided' do
+ let(:to) { nil }
+
+ it 'has the expected properties' do
+ expect(subject[:to].time).to eq(from.time + 8.hours)
+ expect(subject[:from]).to eq(from)
+ end
+ end
+
+ context 'when no parameters are provided' do
+ let(:to) { nil }
+ let(:from) { nil }
+
+ let(:default_from) { 8.hours.ago }
+ let(:default_to) { Time.now }
+
+ it 'has the expected properties' do
+ expect(subject[:to].time).to eq(default_to)
+ expect(subject[:from].time).to eq(default_from)
+ end
+ end
+ end
+end
+
+describe Grafana::Timestamp do
+ let(:timestamp) { Time.at(1552799400) }
+
+ around do |example|
+ Timecop.freeze(Time.utc(2019, 3, 17, 13, 10)) { example.run }
+ end
+
+ describe '#formatted' do
+ subject { described_class.new(timestamp).formatted }
+
+ it { is_expected.to eq "2019-03-17T05:10:00Z" }
+ end
+
+ describe '#to_ms' do
+ subject { described_class.new(timestamp).to_ms }
+
+ it { is_expected.to eq 1552799400000 }
+ end
+
+ describe '.from_ms_since_epoch' do
+ let(:timestamp) { '1552799400000' }
+
+ subject { described_class.from_ms_since_epoch(timestamp) }
+
+ it { is_expected.to be_a described_class }
+
+ context 'when the input is not a unix-ish timestamp' do
+ let(:timestamp) { Time.now.to_s }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Grafana::Timestamp::Error)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/serializers/diff_file_entity_shared_examples.rb b/spec/support/shared_examples/serializers/diff_file_entity_shared_examples.rb
index db5c4b45b70..b6c4841dbd4 100644
--- a/spec/support/shared_examples/serializers/diff_file_entity_shared_examples.rb
+++ b/spec/support/shared_examples/serializers/diff_file_entity_shared_examples.rb
@@ -60,7 +60,7 @@ RSpec.shared_examples 'diff file entity' do
context 'when the `single_mr_diff_view` feature is disabled' do
before do
- stub_feature_flags(single_mr_diff_view: false)
+ stub_feature_flags(single_mr_diff_view: { enabled: false, thing: project })
end
it 'contains both kinds of diffs' do