Commit bd8fb566 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 561e1b47
......@@ -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
......
---
title: Allow default time window on grafana embeds
merge_request: 21884
author:
type: changed
......@@ -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
......
......@@ -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`)
......
......@@ -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
......
......@@ -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.
......
......@@ -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.
......
......@@ -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
......
......@@ -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!
......
......@@ -35,8 +35,6 @@ module Gitlab
end
project_tree['project_members'] += group_members_array
RelationRenameService.add_new_associations(project_tree)
end
def reader
......
# 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
# 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
......@@ -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
......
......@@ -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
......
......@@ -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)
......
......@@ -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)
......
......@@ -6318,7 +6318,7 @@
]
}
],
"pipelines": [
"ci_pipelines": [
{
"id": 36,
"project_id": 5,
......
......@@ -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
......
......@@ -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
......
# 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
# 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
......@@ -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
......
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