diff --git a/Gemfile.lock b/Gemfile.lock index bcbf0a1df1f..bca63aff732 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1119,7 +1119,7 @@ GEM rubocop-ast (>= 0.7.1) ruby-fogbugz (0.2.1) crack (~> 0.4) - ruby-magic (0.5.3) + ruby-magic (0.5.4) mini_portile2 (~> 2.6) ruby-prof (1.3.1) ruby-progressbar (1.11.0) diff --git a/app/assets/javascripts/blob/components/blob_header.vue b/app/assets/javascripts/blob/components/blob_header.vue index 4ef984c0da4..c5ab28e6ec5 100644 --- a/app/assets/javascripts/blob/components/blob_header.vue +++ b/app/assets/javascripts/blob/components/blob_header.vue @@ -42,6 +42,11 @@ export default { required: false, default: false, }, + showPath: { + type: Boolean, + required: false, + default: true, + }, }, data() { return { @@ -55,6 +60,9 @@ export default { showDefaultActions() { return !this.hideDefaultActions; }, + isEmpty() { + return this.blob.rawSize === 0; + }, }, watch: { viewer(newVal, oldVal) { @@ -74,7 +82,7 @@ export default {
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 084c962d34c..89b32a61e2e 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -54,14 +54,14 @@ module ProjectsHelper
default_opts = { avatar: true, name: true, title: ":name" }
opts = default_opts.merge(opts)
+ return "(deleted)" unless author
+
data_attrs = {
user_id: author.id,
username: author.username,
name: author.name
}
- return "(deleted)" unless author
-
author_html = []
# Build avatar image tag
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 032959c385e..0883df5ed6b 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -73,7 +73,6 @@ module Ci
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
has_many :variables, class_name: 'Ci::PipelineVariable'
has_many :deployments, through: :builds
- has_many :environments, -> { distinct.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338658') }, through: :deployments
has_many :latest_builds, -> { latest.with_project_and_metadata }, foreign_key: :commit_id, inverse_of: :pipeline, class_name: 'Ci::Build'
has_many :downloadable_artifacts, -> do
not_expired.or(where_exists(::Ci::Pipeline.artifacts_locked.where('ci_pipelines.id = ci_builds.commit_id'))).downloadable.with_job
diff --git a/app/presenters/blob_presenter.rb b/app/presenters/blob_presenter.rb
index 3fb7b1c51ed..efd29b5601b 100644
--- a/app/presenters/blob_presenter.rb
+++ b/app/presenters/blob_presenter.rb
@@ -125,7 +125,7 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
def external_storage_url
return unless static_objects_external_storage_enabled?
- external_storage_url_or_path(url_helpers.project_raw_url(project, ref_qualified_path))
+ external_storage_url_or_path(url_helpers.project_raw_url(project, ref_qualified_path), project)
end
private
diff --git a/app/serializers/test_case_entity.rb b/app/serializers/test_case_entity.rb
index 0e64b843fd3..8a5fadf53a6 100644
--- a/app/serializers/test_case_entity.rb
+++ b/app/serializers/test_case_entity.rb
@@ -4,7 +4,7 @@ class TestCaseEntity < Grape::Entity
include API::Helpers::RelatedResourcesHelpers
expose :status
- expose :name
+ expose :name, default: "(No name)"
expose :classname
expose :file
expose :execution_time
diff --git a/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb b/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
index f5327449242..8452f2a7821 100644
--- a/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
+++ b/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
@@ -20,7 +20,6 @@ module AuthorizedProjectUpdate
urgency :low
queue_namespace :authorized_project_update
- deduplicate :until_executing, including_scheduled: true
data_consistency :delayed
idempotent!
diff --git a/app/workers/expire_job_cache_worker.rb b/app/workers/expire_job_cache_worker.rb
index 49f0222e9c9..eaa8810a78e 100644
--- a/app/workers/expire_job_cache_worker.rb
+++ b/app/workers/expire_job_cache_worker.rb
@@ -10,8 +10,6 @@ class ExpireJobCacheWorker # rubocop:disable Scalability/IdempotentWorker
queue_namespace :pipeline_cache
urgency :high
-
- deduplicate :until_executing, including_scheduled: true
idempotent!
def perform(job_id)
diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md
index 91565b40ee8..3350b0f1169 100644
--- a/doc/user/group/epics/manage_epics.md
+++ b/doc/user/group/epics/manage_epics.md
@@ -164,6 +164,7 @@ than 1000. The cached value is rounded to thousands or millions and updated ever
> - Sorting by epic titles [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/331625) in GitLab 14.1.
> - Searching by milestone and confidentiality [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/268372) in GitLab 14.2 [with a flag](../../../administration/feature_flags.md) named `vue_epics_list`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/276189) in GitLab 14.7.
+> - [Feature flag `vue_epics_list`](https://gitlab.com/gitlab-org/gitlab/-/issues/327320) removed in GitLab 14.8.
You can search for an epic from the list of epics using filtered search bar based on following
parameters:
diff --git a/lib/api/usage_data_non_sql_metrics.rb b/lib/api/usage_data_non_sql_metrics.rb
index d9e0d153e58..36325c3b742 100644
--- a/lib/api/usage_data_non_sql_metrics.rb
+++ b/lib/api/usage_data_non_sql_metrics.rb
@@ -18,7 +18,7 @@ module API
get 'non_sql_metrics' do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/325534')
- data = Gitlab::UsageDataNonSqlMetrics.uncached_data
+ data = Gitlab::UsageDataNonSqlMetrics.data(force_refresh: true)
present data
end
diff --git a/lib/api/usage_data_queries.rb b/lib/api/usage_data_queries.rb
index 22e83fe0294..1ce8feac4ab 100644
--- a/lib/api/usage_data_queries.rb
+++ b/lib/api/usage_data_queries.rb
@@ -18,7 +18,7 @@ module API
get 'queries' do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/325534')
- queries = Gitlab::UsageDataQueries.uncached_data
+ queries = Gitlab::UsageDataQueries.data(force_refresh: true)
present queries
end
diff --git a/lib/gitlab/rack_attack/request.rb b/lib/gitlab/rack_attack/request.rb
index 94ae29af3d0..7c8dc0be1c6 100644
--- a/lib/gitlab/rack_attack/request.rb
+++ b/lib/gitlab/rack_attack/request.rb
@@ -30,15 +30,15 @@ module Gitlab
end
def api_internal_request?
- path =~ %r{^/api/v\d+/internal/}
+ path.match?(%r{^/api/v\d+/internal/})
end
def health_check_request?
- path =~ %r{^/-/(health|liveness|readiness|metrics)}
+ path.match?(%r{^/-/(health|liveness|readiness|metrics)})
end
def container_registry_event?
- path =~ %r{^/api/v\d+/container_registry_event/}
+ path.match?(%r{^/api/v\d+/container_registry_event/})
end
def product_analytics_collector_request?
@@ -54,11 +54,7 @@ module Gitlab
end
def protected_path?
- !protected_path_regex.nil?
- end
-
- def protected_path_regex
- path =~ protected_paths_regex
+ path.match?(protected_paths_regex)
end
def throttle?(throttle, authenticated:)
@@ -178,15 +174,15 @@ module Gitlab
end
def packages_api_path?
- path =~ ::Gitlab::Regex::Packages::API_PATH_REGEX
+ path.match?(::Gitlab::Regex::Packages::API_PATH_REGEX)
end
def git_lfs_path?
- path =~ Gitlab::PathRegex.repository_git_lfs_route_regex
+ path.match?(::Gitlab::PathRegex.repository_git_lfs_route_regex)
end
def files_api_path?
- path =~ FILES_PATH_REGEX
+ path.match?(FILES_PATH_REGEX)
end
def deprecated_api_request?
@@ -195,7 +191,7 @@ module Gitlab
with_projects = params['with_projects']
with_projects = true if with_projects.blank?
- path =~ GROUP_PATH_REGEX && Gitlab::Utils.to_boolean(with_projects)
+ path.match?(GROUP_PATH_REGEX) && Gitlab::Utils.to_boolean(with_projects)
end
end
end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 42e67543342..83c26ee9ade 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -47,14 +47,6 @@ module Gitlab
end
end
- def uncached_data
- clear_memoized
-
- with_finished_at(:recording_ce_finished_at) do
- usage_data_metrics
- end
- end
-
def to_json(force_refresh: false)
data(force_refresh: force_refresh).to_json
end
@@ -697,6 +689,14 @@ module Gitlab
private
+ def uncached_data
+ clear_memoized
+
+ with_finished_at(:recording_ce_finished_at) do
+ usage_data_metrics
+ end
+ end
+
def stage_manage_events(time_period)
if time_period.empty?
Gitlab::Utils::UsageData::FALLBACK
diff --git a/lib/tasks/gitlab/usage_data.rake b/lib/tasks/gitlab/usage_data.rake
index 694c49240ed..dc1d7cf4cdc 100644
--- a/lib/tasks/gitlab/usage_data.rake
+++ b/lib/tasks/gitlab/usage_data.rake
@@ -4,17 +4,17 @@ namespace :gitlab do
namespace :usage_data do
desc 'GitLab | UsageData | Generate raw SQLs for usage ping in YAML'
task dump_sql_in_yaml: :environment do
- puts Gitlab::UsageDataQueries.uncached_data.to_yaml
+ puts Gitlab::UsageDataQueries.data(force_refresh: true).to_yaml
end
desc 'GitLab | UsageData | Generate raw SQLs for usage ping in JSON'
task dump_sql_in_json: :environment do
- puts Gitlab::Json.pretty_generate(Gitlab::UsageDataQueries.uncached_data)
+ puts Gitlab::Json.pretty_generate(Gitlab::UsageDataQueries.data(force_refresh: true))
end
desc 'GitLab | UsageData | Generate usage ping in JSON'
task generate: :environment do
- puts Gitlab::Json.pretty_generate(Gitlab::UsageData.uncached_data)
+ puts Gitlab::Json.pretty_generate(Gitlab::UsageData.data(force: true))
end
desc 'GitLab | UsageData | Generate usage ping and send it to Versions Application'
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d338a879858..46179ff75d0 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -15288,12 +15288,6 @@ msgstr ""
msgid "Filter by"
msgstr ""
-msgid "Filter by %{issuable_type} that are currently closed."
-msgstr ""
-
-msgid "Filter by %{issuable_type} that are currently open."
-msgstr ""
-
msgid "Filter by %{page_context_word} that are currently open."
msgstr ""
@@ -33721,9 +33715,6 @@ msgstr ""
msgid "Something went wrong. Try again later."
msgstr ""
-msgid "Sorry, no epics matched your search"
-msgstr ""
-
msgid "Sorry, no projects matched your search"
msgstr ""
@@ -36587,6 +36578,9 @@ msgstr ""
msgid "This content could not be displayed because %{reason}. You can %{options} instead."
msgstr ""
+msgid "This content could not be displayed because it is stored in LFS. You can %{linkStart}download it%{linkEnd} instead."
+msgstr ""
+
msgid "This credential has expired"
msgstr ""
@@ -37593,9 +37587,6 @@ msgstr ""
msgid "To widen your search, change or remove filters above."
msgstr ""
-msgid "To widen your search, change or remove filters."
-msgstr ""
-
msgid "To-Do List"
msgstr ""
diff --git a/qa/qa/page/component/blob_content.rb b/qa/qa/page/component/blob_content.rb
index 4d36a6dcefe..16a258ff0bc 100644
--- a/qa/qa/page/component/blob_content.rb
+++ b/qa/qa/page/component/blob_content.rb
@@ -22,6 +22,10 @@ module QA
element :copy_contents_button
end
+ base.view 'app/assets/javascripts/vue_shared/components/source_viewer.vue' do
+ element :blob_viewer_file_content
+ end
+
base.view 'app/views/projects/blob/_header_content.html.haml' do
element :file_name_content
end
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
index 0715fa8ba37..dc981ebceab 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
@@ -3,7 +3,11 @@
require_relative 'gitlab_project_migration_common'
module QA
- RSpec.describe 'Manage', :requires_admin do
+ RSpec.describe 'Manage', :requires_admin, quarantine: {
+ only: { subdomain: :staging },
+ type: :investigating,
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/351596'
+ } do
describe 'Gitlab migration' do
include_context 'with gitlab project migration'
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb
index 0abc21531a6..fea68114ae0 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb
@@ -2,12 +2,9 @@
module QA
RSpec.shared_context 'with gitlab project migration', quarantine: {
- only: { job: 'praefect', subdomain: :staging },
+ only: { job: 'praefect' },
type: :investigating,
- issue: [
- 'https://gitlab.com/gitlab-org/gitlab/-/issues/348999',
- 'https://gitlab.com/gitlab-org/gitlab/-/issues/350965'
- ]
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/348999'
} do
let(:source_project_with_readme) { false }
let(:import_wait_duration) { { max_duration: 300, sleep_interval: 2 } }
diff --git a/rubocop/cop/sidekiq_load_balancing/worker_data_consistency_with_deduplication.rb b/rubocop/cop/sidekiq_load_balancing/worker_data_consistency_with_deduplication.rb
deleted file mode 100644
index e8b4b513a23..00000000000
--- a/rubocop/cop/sidekiq_load_balancing/worker_data_consistency_with_deduplication.rb
+++ /dev/null
@@ -1,154 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../code_reuse_helpers'
-
-module RuboCop
- module Cop
- module SidekiqLoadBalancing
- # This cop checks for including_scheduled: true option in idempotent Sidekiq workers that utilize load balancing capabilities.
- #
- # @example
- #
- # # bad
- # class BadWorker
- # include ApplicationWorker
- #
- # data_consistency :delayed
- # idempotent!
- #
- # def perform
- # end
- # end
- #
- # # bad
- # class BadWorker
- # include ApplicationWorker
- #
- # data_consistency :delayed
- #
- # deduplicate :until_executing
- # idempotent!
- #
- # def perform
- # end
- # end
- #
- # # good
- # class GoodWorker
- # include ApplicationWorker
- #
- # data_consistency :delayed
- #
- # deduplicate :until_executing, including_scheduled: true
- # idempotent!
- #
- # def perform
- # end
- # end
- #
- class WorkerDataConsistencyWithDeduplication < RuboCop::Cop::Base
- include CodeReuseHelpers
- extend AutoCorrector
-
- HELP_LINK = 'https://docs.gitlab.com/ee/development/sidekiq_style_guide.html#scheduling-jobs-in-the-future'
- REPLACEMENT = ', including_scheduled: true'
- DEFAULT_STRATEGY = ':until_executing'
-
- MSG = <<~MSG
- Workers that declare either `:sticky` or `:delayed` data consistency become eligible for database load-balancing.
- In both cases, jobs are enqueued with a short delay.
-
- If you do want to deduplicate jobs that utilize load-balancing, you need to specify including_scheduled: true
- argument when defining deduplication strategy.
-
- See #{HELP_LINK} for a more detailed explanation of these settings.
- MSG
-
- def_node_search :application_worker?, <<~PATTERN
- `(send nil? :include (const nil? :ApplicationWorker))
- PATTERN
-
- def_node_search :idempotent_worker?, <<~PATTERN
- `(send nil? :idempotent!)
- PATTERN
-
- def_node_search :data_consistency_defined?, <<~PATTERN
- `(send nil? :data_consistency (sym {:sticky :delayed }))
- PATTERN
-
- def_node_matcher :including_scheduled?, <<~PATTERN
- `(hash <(pair (sym :including_scheduled) (%1)) ...>)
- PATTERN
-
- def_node_matcher :deduplicate_strategy?, <<~PATTERN
- `(send nil? :deduplicate (sym $_) $(...)?)
- PATTERN
-
- def on_class(node)
- return unless in_worker?(node)
- return unless application_worker?(node)
- return unless idempotent_worker?(node)
- return unless data_consistency_defined?(node)
-
- @strategy, options = deduplicate_strategy?(node)
- including_scheduled = false
- if options
- @deduplicate_options = options[0]
- including_scheduled = including_scheduled?(@deduplicate_options, :true) # rubocop:disable Lint/BooleanSymbol
- end
-
- @offense = !(including_scheduled || @strategy == :none)
- end
-
- def on_send(node)
- return unless offense
-
- if node.children[1] == :deduplicate
- add_offense(node.loc.expression) do |corrector|
- autocorrect_deduplicate_strategy(node, corrector)
- end
- elsif node.children[1] == :idempotent! && !strategy
- add_offense(node.loc.expression) do |corrector|
- autocorrect_missing_deduplicate_strategy(node, corrector)
- end
- end
- end
-
- private
-
- attr_reader :offense, :deduplicate_options, :strategy
-
- def autocorrect_deduplicate_with_options(corrector)
- if including_scheduled?(deduplicate_options, :false) # rubocop:disable Lint/BooleanSymbol
- replacement = deduplicate_options.source.sub("including_scheduled: false", "including_scheduled: true")
- corrector.replace(deduplicate_options.loc.expression, replacement)
- else
- corrector.insert_after(deduplicate_options.loc.expression, REPLACEMENT)
- end
- end
-
- def autocorrect_deduplicate_without_options(node, corrector)
- corrector.insert_after(node.loc.expression, REPLACEMENT)
- end
-
- def autocorrect_missing_deduplicate_strategy(node, corrector)
- indent_found = node.source_range.source_line =~ /^( +)/
- # Get indentation size
- whitespaces = Regexp.last_match(1).size if indent_found
- replacement = "deduplicate #{DEFAULT_STRATEGY}#{REPLACEMENT}\n"
- # Add indentation in the end since we are inserting a whole line before idempotent!
- replacement += ' ' * whitespaces.to_i
- corrector.insert_before(node.source_range, replacement)
- end
-
- def autocorrect_deduplicate_strategy(node, corrector)
- if deduplicate_options
- autocorrect_deduplicate_with_options(corrector)
- else
- autocorrect_deduplicate_without_options(node, corrector)
- end
- end
- end
- end
- end
-end
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 988051bca40..c8cbf396098 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -29,117 +29,1014 @@ RSpec.describe 'File blob', :js do
).execute
end
- before do
- stub_feature_flags(refactor_blob_viewer: false) # This stub will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/350455
- end
-
- context 'Ruby file' do
- before do
- visit_blob('files/ruby/popen.rb')
-
- wait_for_requests
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows highlighted Ruby code
- expect(page).to have_css(".js-syntax-highlight")
- expect(page).to have_content("require 'fileutils'")
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
- end
- end
-
- it 'displays file actions on all screen sizes' do
- file_actions_selector = '.file-actions'
-
- resize_screen_sm
- expect(page).to have_selector(file_actions_selector, visible: true)
-
- resize_screen_xs
- expect(page).to have_selector(file_actions_selector, visible: true)
- end
- end
-
- context 'Markdown file' do
- context 'visiting directly' do
+ context 'with refactor_blob_viewer feature flag enabled' do
+ context 'Ruby file' do
before do
- visit_blob('files/markdown/ruby-style-guide.md')
+ visit_blob('files/ruby/popen.rb')
wait_for_requests
end
- it 'displays the blob using the rich viewer' do
+ it 'displays the blob' do
aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+ # shows highlighted Ruby code
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("require 'fileutils'")
- # shows rendered Markdown
- expect(page).to have_link("PEP-8")
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
- # shows a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
-
- # shows a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
# shows a raw button
expect(page).to have_link('Open raw')
end
end
- context 'switching to the simple viewer' do
+ it 'displays file actions on all screen sizes' do
+ file_actions_selector = '.file-actions'
+
+ resize_screen_sm
+ expect(page).to have_selector(file_actions_selector, visible: true)
+
+ resize_screen_xs
+ expect(page).to have_selector(file_actions_selector, visible: true)
+ end
+ end
+
+ context 'Markdown file' do
+ context 'visiting directly' do
before do
- find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
+ visit_blob('files/markdown/ruby-style-guide.md')
wait_for_requests
end
- it 'displays the blob using the simple viewer' do
+ it 'displays the blob using the rich viewer' do
aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
- # shows highlighted Markdown code
- expect(page).to have_css(".js-syntax-highlight")
- expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+ # shows rendered Markdown
+ expect(page).to have_link("PEP-8")
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # shows a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
- context 'switching to the rich viewer again' do
+ context 'switching to the simple viewer' do
before do
- find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
+ find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
wait_for_requests
end
- it 'displays the blob using the rich viewer' do
+ it 'displays the blob using the simple viewer' do
aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows highlighted Markdown code
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
end
end
+
+ context 'switching to the rich viewer again' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
+
+ wait_for_requests
+ end
+
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ end
+ end
+ end
+ end
+ end
+
+ context 'when ref switch' do
+ def switch_ref_to(ref_name)
+ first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
+
+ page.within '.project-refs-form' do
+ click_link ref_name
+ wait_for_requests
+ end
+ end
+
+ it 'displays no highlighted number of different ref' do
+ Files::UpdateService.new(
+ project,
+ project.first_owner,
+ commit_message: 'Update',
+ start_branch: 'feature',
+ branch_name: 'feature',
+ file_path: 'files/js/application.js',
+ file_content: 'new content'
+ ).execute
+
+ project.commit('feature').diffs.diff_files.first
+
+ visit_blob('files/js/application.js', anchor: 'L3')
+ switch_ref_to('feature')
+
+ page.within '.blob-content' do
+ expect(page).not_to have_css('.hll')
+ end
+ end
+
+ context 'successfully change ref of similar name' do
+ before do
+ project.repository.create_branch('dev')
+ project.repository.create_branch('development')
+ end
+
+ it 'switch ref from longer to shorter ref name' do
+ visit_blob('files/js/application.js', ref: 'development')
+ switch_ref_to('dev')
+
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
+ end
+
+ it 'switch ref from shorter to longer ref name' do
+ visit_blob('files/js/application.js', ref: 'dev')
+ switch_ref_to('development')
+
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
+ end
+ end
+
+ it 'successfully changes ref when the ref name matches the project name' do
+ project.repository.create_branch(project.name)
+
+ visit_blob('files/js/application.js', ref: project.name)
+ switch_ref_to('master')
+
+ aggregate_failures do
+ expect(page.find('.file-title-name').text).to eq('application.js')
+ expect(page).not_to have_css('flash-container')
+ end
end
end
end
+ context 'Markdown rendering' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add RedCarpet and CommonMark Markdown ",
+ file_path: 'files/commonmark/file.md',
+ file_content: "1. one\n - sublist\n"
+ ).execute
+ end
+
+ context 'when rendering default markdown' do
+ before do
+ visit_blob('files/commonmark/file.md')
+
+ wait_for_requests
+ end
+
+ it 'renders using CommonMark' do
+ aggregate_failures do
+ expect(page).to have_content("sublist")
+ expect(page).not_to have_xpath("//ol//li//ul")
+ end
+ end
+ end
+ end
+
+ context 'Markdown file (stored in LFS)' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add Markdown in LFS",
+ file_path: 'files/lfs/file.md',
+ file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data
+ ).execute
+ end
+
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
+
+ visit_blob('files/lfs/file.md')
+
+ wait_for_requests
+ end
+
+ it 'displays an error' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).not_to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows an error message
+ expect(page).to have_content('This content could not be displayed because it is stored in LFS. You can download it instead.')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
+
+ context 'when LFS is disabled on the project' do
+ before do
+ visit_blob('files/lfs/file.md')
+
+ wait_for_requests
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows text
+ expect(page).to have_content('size 1575078')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+ end
+ end
+ end
+ end
+
+ context 'PDF file' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add PDF",
+ file_path: 'files/test.pdf',
+ file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data
+ ).execute
+
+ visit_blob('files/test.pdf')
+
+ wait_for_requests
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows rendered PDF
+ expect(page).to have_selector('.js-pdf-viewer')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
+
+ context 'Jupiter Notebook file' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add Jupiter Notebook",
+ file_path: 'files/basic.ipynb',
+ file_content: project.repository.blob_at('add-ipython-files', 'files/ipython/basic.ipynb').data
+ ).execute
+
+ visit_blob('files/basic.ipynb')
+
+ wait_for_requests
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows rendered notebook
+ expect(page).to have_selector('.js-notebook-viewer-mounted')
+
+ # does show a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # show a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+
+ # shows the rendered notebook
+ expect(page).to have_content('test')
+ end
+ end
+ end
+
+ context 'ISO file (stored in LFS)' do
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
+
+ visit_blob('files/lfs/lfs_object.iso')
+
+ wait_for_requests
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows a download link
+ expect(page).to have_link('Download (1.50 MiB)')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
+
+ context 'when LFS is disabled on the project' do
+ before do
+ visit_blob('files/lfs/lfs_object.iso')
+
+ wait_for_requests
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows text
+ expect(page).to have_content('size 1575078')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+ end
+ end
+ end
+ end
+
+ context 'ZIP file' do
+ before do
+ visit_blob('Gemfile.zip')
+
+ wait_for_requests
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows a download link
+ expect(page).to have_link('Download (2.11 KiB)')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
+
+ context 'empty file' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add empty file",
+ file_path: 'files/empty.md',
+ file_content: ''
+ ).execute
+
+ visit_blob('files/empty.md')
+
+ wait_for_requests
+ end
+
+ it 'displays an error' do
+ aggregate_failures do
+ # shows an error message
+ expect(page).to have_content('Empty file')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # does not show a copy button
+ expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # does not show a download or raw button
+ expect(page).not_to have_link('Download')
+ expect(page).not_to have_link('Open raw')
+ end
+ end
+ end
+
+ context 'files with auxiliary viewers' do
+ describe '.gitlab-ci.yml' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab-ci.yml",
+ file_path: '.gitlab-ci.yml',
+ file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ ).execute
+
+ visit_blob('.gitlab-ci.yml')
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that configuration is valid
+ expect(page).to have_content('This GitLab CI configuration is valid.')
+
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
+
+ describe '.gitlab/route-map.yml' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab/route-map.yml",
+ file_path: '.gitlab/route-map.yml',
+ file_content: <<-MAP.strip_heredoc
+ # Team data
+ - source: 'data/team.yml'
+ public: 'team/'
+ MAP
+ ).execute
+
+ visit_blob('.gitlab/route-map.yml')
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that map is valid
+ expect(page).to have_content('This Route Map is valid.')
+
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
+
+ describe '.gitlab/dashboards/custom-dashboard.yml' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab/dashboards/custom-dashboard.yml",
+ file_path: '.gitlab/dashboards/custom-dashboard.yml',
+ file_content: file_content
+ ).execute
+ end
+
+ context 'with metrics_dashboard_exhaustive_validations feature flag off' do
+ before do
+ stub_feature_flags(metrics_dashboard_exhaustive_validations: false)
+ visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ end
+
+ context 'valid dashboard file' do
+ let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is valid
+ expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
+
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
+
+ context 'invalid dashboard file' do
+ let(:file_content) { "dashboard: 'invalid'" }
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is invalid
+ expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
+ expect(page).to have_content("panel_groups: should be an array of panel_groups objects")
+
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
+ end
+
+ context 'with metrics_dashboard_exhaustive_validations feature flag on' do
+ before do
+ stub_feature_flags(metrics_dashboard_exhaustive_validations: true)
+ visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ end
+
+ context 'valid dashboard file' do
+ let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is valid
+ expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
+
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
+
+ context 'invalid dashboard file' do
+ let(:file_content) { "dashboard: 'invalid'" }
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows that dashboard yaml is invalid
+ expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
+ expect(page).to have_content("root is missing required keys: panel_groups")
+
+ # shows a learn more link
+ expect(page).to have_link('Learn more')
+ end
+ end
+ end
+ end
+ end
+
+ context 'LICENSE' do
+ before do
+ visit_blob('LICENSE')
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows license
+ expect(page).to have_content('This project is licensed under the MIT License.')
+
+ # shows a learn more link
+ expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/')
+ end
+ end
+ end
+
+ context '*.gemspec' do
+ before do
+ project.add_maintainer(project.creator)
+
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add activerecord.gemspec",
+ file_path: 'activerecord.gemspec',
+ file_content: <<-SPEC.strip_heredoc
+ Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = "activerecord"
+ end
+ SPEC
+ ).execute
+
+ visit_blob('activerecord.gemspec')
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ # shows names of dependency manager and package
+ expect(page).to have_content('This project manages its dependencies using RubyGems.')
+
+ # shows a learn more link
+ expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
+ end
+ end
+ end
+
+ context 'CONTRIBUTING.md' do
+ before do
+ file_name = 'CONTRIBUTING.md'
+
+ create_file(file_name, '## Contribution guidelines')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.")
+ end
+ end
+ end
+
+ context 'CHANGELOG.md' do
+ before do
+ file_name = 'CHANGELOG.md'
+
+ create_file(file_name, '## Changelog for v1.0.0')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("To find the state of this project's repository at the time of any of these versions, check out the tags.")
+ end
+ end
+ end
+
+ context 'Cargo.toml' do
+ before do
+ file_name = 'Cargo.toml'
+
+ create_file(file_name, '
+ [package]
+ name = "hello_world" # the name of the package
+ version = "0.1.0" # the current version, obeying semver
+ authors = ["Alice ", "Bob "]
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Cargo.")
+ end
+ end
+ end
+
+ context 'Cartfile' do
+ before do
+ file_name = 'Cartfile'
+
+ create_file(file_name, '
+ gitlab "Alamofire/Alamofire" == 4.9.0
+ gitlab "Alamofire/AlamofireImage" ~> 3.4
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Carthage.")
+ end
+ end
+ end
+
+ context 'composer.json' do
+ before do
+ file_name = 'composer.json'
+
+ create_file(file_name, '
+ {
+ "license": "MIT"
+ }
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Composer.")
+ end
+ end
+ end
+
+ context 'Gemfile' do
+ before do
+ file_name = 'Gemfile'
+
+ create_file(file_name, '
+ source "https://rubygems.org"
+
+ # Gems here
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Bundler.")
+ end
+ end
+ end
+
+ context 'Godeps.json' do
+ before do
+ file_name = 'Godeps.json'
+
+ create_file(file_name, '
+ {
+ "GoVersion": "go1.6"
+ }
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using godep.")
+ end
+ end
+ end
+
+ context 'go.mod' do
+ before do
+ file_name = 'go.mod'
+
+ create_file(file_name, '
+ module example.com/mymodule
+
+ go 1.14
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Go Modules.")
+ end
+ end
+ end
+
+ context 'package.json' do
+ before do
+ file_name = 'package.json'
+
+ create_file(file_name, '
+ {
+ "name": "my-awesome-package",
+ "version": "1.0.0"
+ }
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using npm.")
+ end
+ end
+ end
+
+ context 'podfile' do
+ before do
+ file_name = 'podfile'
+
+ create_file(file_name, 'platform :ios, "8.0"')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
+ end
+ end
+
+ context 'test.podspec' do
+ before do
+ file_name = 'test.podspec'
+
+ create_file(file_name, '
+ Pod::Spec.new do |s|
+ s.name = "TensorFlowLiteC"
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
+ end
+ end
+
+ context 'JSON.podspec.json' do
+ before do
+ file_name = 'JSON.podspec.json'
+
+ create_file(file_name, '
+ {
+ "name": "JSON"
+ }
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using CocoaPods.")
+ end
+ end
+ end
+
+ context 'requirements.txt' do
+ before do
+ file_name = 'requirements.txt'
+
+ create_file(file_name, 'Project requirements')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using pip.")
+ end
+ end
+ end
+
+ context 'yarn.lock' do
+ before do
+ file_name = 'yarn.lock'
+
+ create_file(file_name, '
+ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+ # yarn lockfile v1
+ ')
+ visit_blob(file_name)
+ end
+
+ it 'displays an auxiliary viewer' do
+ aggregate_failures do
+ expect(page).to have_content("This project manages its dependencies using Yarn.")
+ end
+ end
+ end
+ end
+
+ context 'realtime pipelines' do
+ before do
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'feature',
+ branch_name: 'feature',
+ commit_message: "Add ruby file",
+ file_path: 'files/ruby/test.rb',
+ file_content: "# Awesome content"
+ ).execute
+
+ create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha)
+ visit_blob('files/ruby/test.rb', ref: 'feature')
+ end
+
+ it 'shows the realtime pipeline status' do
+ page.within('.commit-actions') do
+ expect(page).to have_css('.ci-status-icon')
+ expect(page).to have_css('.ci-status-icon-running')
+ expect(page).to have_css('.js-ci-status-icon-running')
+ end
+ end
+ end
+
+ context 'for subgroups' do
+ let(:group) { create(:group) }
+ let(:subgroup) { create(:group, parent: group) }
+ let(:project) { create(:project, :public, :repository, group: subgroup) }
+
+ it 'renders tree table without errors' do
+ visit_blob('README.md')
+
+ expect(page).to have_selector('.file-content')
+ expect(page).not_to have_selector('.flash-alert')
+ end
+
+ it 'displays a GPG badge' do
+ visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9')
+
+ expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
+ expect(page).to have_selector '.gpg-status-box.invalid'
+ end
+ end
+
+ context 'on signed merge commit' do
+ it 'displays a GPG badge' do
+ visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10')
+
+ expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
+ expect(page).to have_selector '.gpg-status-box.invalid'
+ end
+ end
+
+ context 'when static objects external storage is enabled' do
+ before do
+ stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
+ end
+
+ context 'public project' do
+ before do
+ visit_blob('README.md')
+ end
+
+ it 'shows open raw and download buttons with external storage URL prepended to their href' do
+ path = project_raw_path(project, 'master/README.md')
+ raw_uri = "https://cdn.gitlab.com#{path}"
+ download_uri = "https://cdn.gitlab.com#{path}?inline=false"
+
+ aggregate_failures do
+ expect(page).to have_link 'Open raw', href: raw_uri
+ expect(page).to have_link 'Download', href: download_uri
+ end
+ end
+ end
+ end
+ end
+
+ context 'with refactor_blob_viewer feature flag disabled' do
+ before do
+ stub_feature_flags(refactor_blob_viewer: false)
+ end
+
context 'when ref switch' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351558
+
def switch_ref_to(ref_name)
first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
@@ -149,90 +1046,35 @@ RSpec.describe 'File blob', :js do
end
end
- it 'displays single highlighted line number of different ref' do
- visit_blob('files/js/application.js', anchor: 'L1')
+ context 'when highlighting lines' do
+ it 'displays single highlighted line number of different ref' do
+ visit_blob('files/js/application.js', anchor: 'L1')
- switch_ref_to('feature')
+ switch_ref_to('feature')
- page.within '.blob-content' do
- expect(find_by_id('LC1')[:class]).to include("hll")
- end
- end
-
- it 'displays multiple highlighted line numbers of different ref' do
- visit_blob('files/js/application.js', anchor: 'L1-3')
-
- switch_ref_to('feature')
-
- page.within '.blob-content' do
- expect(find_by_id('LC1')[:class]).to include("hll")
- expect(find_by_id('LC2')[:class]).to include("hll")
- expect(find_by_id('LC3')[:class]).to include("hll")
- end
- end
-
- it 'displays no highlighted number of different ref' do
- Files::UpdateService.new(
- project,
- project.first_owner,
- commit_message: 'Update',
- start_branch: 'feature',
- branch_name: 'feature',
- file_path: 'files/js/application.js',
- file_content: 'new content'
- ).execute
-
- project.commit('feature').diffs.diff_files.first
-
- visit_blob('files/js/application.js', anchor: 'L3')
- switch_ref_to('feature')
-
- page.within '.blob-content' do
- expect(page).not_to have_css('.hll')
- end
- end
-
- context 'successfully change ref of similar name' do
- before do
- project.repository.create_branch('dev')
- project.repository.create_branch('development')
- end
-
- it 'switch ref from longer to shorter ref name' do
- visit_blob('files/js/application.js', ref: 'development')
- switch_ref_to('dev')
-
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
+ page.within '.blob-content' do
+ expect(find_by_id('LC1')[:class]).to include("hll")
end
end
- it 'switch ref from shorter to longer ref name' do
- visit_blob('files/js/application.js', ref: 'dev')
- switch_ref_to('development')
+ it 'displays multiple highlighted line numbers of different ref' do
+ visit_blob('files/js/application.js', anchor: 'L1-3')
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
+ switch_ref_to('feature')
+
+ page.within '.blob-content' do
+ expect(find_by_id('LC1')[:class]).to include("hll")
+ expect(find_by_id('LC2')[:class]).to include("hll")
+ expect(find_by_id('LC3')[:class]).to include("hll")
end
end
end
-
- it 'successfully changes ref when the ref name matches the project name' do
- project.repository.create_branch(project.name)
-
- visit_blob('files/js/application.js', ref: project.name)
- switch_ref_to('master')
-
- aggregate_failures do
- expect(page.find('.file-title-name').text).to eq('application.js')
- expect(page).not_to have_css('flash-container')
- end
- end
end
context 'visiting with a line number anchor' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351558
+
before do
visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
end
@@ -241,7 +1083,7 @@ RSpec.describe 'File blob', :js do
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+ expect(page).not_to have_selector('.blob-viewer[data-type="rich"]')
# highlights the line in question
expect(page).to have_selector('#LC1.hll')
@@ -255,810 +1097,71 @@ RSpec.describe 'File blob', :js do
end
end
end
- end
- context 'Markdown rendering' do
- before do
- project.add_maintainer(project.creator)
+ context 'binary file that appears to be text in the first 1024 bytes' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351559
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add RedCarpet and CommonMark Markdown ",
- file_path: 'files/commonmark/file.md',
- file_content: "1. one\n - sublist\n"
- ).execute
- end
-
- context 'when rendering default markdown' do
before do
- visit_blob('files/commonmark/file.md')
-
- wait_for_requests
+ visit_blob('encoding/binary-1.bin', ref: 'binary-encoding')
end
-
- it 'renders using CommonMark' do
- aggregate_failures do
- expect(page).to have_content("sublist")
- expect(page).not_to have_xpath("//ol//li//ul")
- end
- end
- end
- end
-
- context 'Markdown file (stored in LFS)' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add Markdown in LFS",
- file_path: 'files/lfs/file.md',
- file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data
- ).execute
- end
-
- context 'when LFS is enabled on the project' do
- before do
- allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
- project.update_attribute(:lfs_enabled, true)
-
- visit_blob('files/lfs/file.md')
-
- wait_for_requests
- end
-
- it 'displays an error' do
- aggregate_failures do
- # hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
- expect(page).to have_selector('.blob-viewer[data-type="rich"]')
-
- # shows an error message
- expect(page).to have_content('The rendered file could not be displayed because it is stored in LFS. You can download it instead.')
-
- # shows a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
-
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
-
- # shows a download button
- expect(page).to have_link('Download')
- end
- end
-
- context 'switching to the simple viewer' do
- before do
- find('.js-blob-viewer-switcher .js-blob-viewer-switch-btn[data-viewer=simple]').click
-
- wait_for_requests
- end
-
- it 'displays an error' do
- aggregate_failures do
- # hides the rich viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
-
- # shows an error message
- expect(page).to have_content('The source could not be displayed because it is stored in LFS. You can download it instead.')
-
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
- end
- end
- end
- end
-
- context 'when LFS is disabled on the project' do
- before do
- visit_blob('files/lfs/file.md')
-
- wait_for_requests
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows text
- expect(page).to have_content('size 1575078')
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
- end
- end
- end
- end
-
- context 'PDF file' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add PDF",
- file_path: 'files/test.pdf',
- file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data
- ).execute
-
- visit_blob('files/test.pdf')
-
- wait_for_requests
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows rendered PDF
- expect(page).to have_selector('.js-pdf-viewer')
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
-
- # shows a download button
- expect(page).to have_link('Download')
- end
- end
- end
-
- context 'Jupiter Notebook file' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add Jupiter Notebook",
- file_path: 'files/basic.ipynb',
- file_content: project.repository.blob_at('add-ipython-files', 'files/ipython/basic.ipynb').data
- ).execute
-
- visit_blob('files/basic.ipynb')
-
- wait_for_requests
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows rendered notebook
- expect(page).to have_selector('.js-notebook-viewer-mounted')
-
- # does show a viewer switcher
- expect(page).to have_selector('.js-blob-viewer-switcher')
-
- # show a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
-
- # shows a raw button
- expect(page).to have_link('Open raw')
-
- # shows a download button
- expect(page).to have_link('Download')
-
- # shows the rendered notebook
- expect(page).to have_content('test')
- end
- end
- end
-
- context 'ISO file (stored in LFS)' do
- context 'when LFS is enabled on the project' do
- before do
- allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
- project.update_attribute(:lfs_enabled, true)
-
- visit_blob('files/lfs/lfs_object.iso')
-
- wait_for_requests
- end
-
it 'displays the blob' do
aggregate_failures do
# shows a download link
- expect(page).to have_link('Download (1.5 MB)')
-
+ expect(page).to have_link('Download (23.8 KB)')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
-
- # shows a download button
- expect(page).to have_link('Download')
- end
- end
- end
-
- context 'when LFS is disabled on the project' do
- before do
- visit_blob('files/lfs/lfs_object.iso')
-
- wait_for_requests
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows text
- expect(page).to have_content('size 1575078')
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # shows an enabled copy button
+ # The specs below verify an arguably incorrect result, but since we only
+ # learn that the file is not actually text once the text viewer content
+ # is loaded asynchronously, there is no straightforward way to get these
+ # synchronously loaded elements to display correctly.
+ #
+ # Clicking the copy button will result in nothing being copied.
+ # Clicking the raw button will result in the binary file being downloaded,
+ # as expected.
+ # shows an enabled copy button, incorrectly
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
-
- # shows a raw button
+ # shows a raw button, incorrectly
expect(page).to have_link('Open raw')
end
end
end
- end
- context 'ZIP file' do
- before do
- visit_blob('Gemfile.zip')
+ context 'when static objects external storage is enabled' do
+ # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled
+ # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351555
- wait_for_requests
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows a download link
- expect(page).to have_link('Download (2.11 KB)')
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
-
- # shows a download button
- expect(page).to have_link('Download')
- end
- end
- end
-
- context 'empty file' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add empty file",
- file_path: 'files/empty.md',
- file_content: ''
- ).execute
-
- visit_blob('files/empty.md')
-
- wait_for_requests
- end
-
- it 'displays an error' do
- aggregate_failures do
- # shows an error message
- expect(page).to have_content('Empty file')
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # does not show a copy button
- expect(page).not_to have_selector('.js-copy-blob-source-btn')
-
- # does not show a download or raw button
- expect(page).not_to have_link('Download')
- expect(page).not_to have_link('Open raw')
- end
- end
- end
-
- context 'binary file that appears to be text in the first 1024 bytes' do
- before do
- visit_blob('encoding/binary-1.bin', ref: 'binary-encoding')
- end
-
- it 'displays the blob' do
- aggregate_failures do
- # shows a download link
- expect(page).to have_link('Download (23.8 KB)')
-
- # does not show a viewer switcher
- expect(page).not_to have_selector('.js-blob-viewer-switcher')
-
- # The specs below verify an arguably incorrect result, but since we only
- # learn that the file is not actually text once the text viewer content
- # is loaded asynchronously, there is no straightforward way to get these
- # synchronously loaded elements to display correctly.
- #
- # Clicking the copy button will result in nothing being copied.
- # Clicking the raw button will result in the binary file being downloaded,
- # as expected.
-
- # shows an enabled copy button, incorrectly
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
-
- # shows a raw button, incorrectly
- expect(page).to have_link('Open raw')
- end
- end
- end
-
- context 'files with auxiliary viewers' do
- before do
- stub_feature_flags(refactor_blob_viewer: true)
- end
-
- describe '.gitlab-ci.yml' do
before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab-ci.yml",
- file_path: '.gitlab-ci.yml',
- file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- ).execute
-
- visit_blob('.gitlab-ci.yml')
+ stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
end
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that configuration is valid
- expect(page).to have_content('This GitLab CI configuration is valid.')
+ context 'private project' do
+ let_it_be(:project) { create(:project, :repository, :private) }
+ let_it_be(:user) { create(:user) }
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
- end
- end
-
- describe '.gitlab/route-map.yml' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab/route-map.yml",
- file_path: '.gitlab/route-map.yml',
- file_content: <<-MAP.strip_heredoc
- # Team data
- - source: 'data/team.yml'
- public: 'team/'
- MAP
- ).execute
-
- visit_blob('.gitlab/route-map.yml')
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that map is valid
- expect(page).to have_content('This Route Map is valid.')
-
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
- end
- end
-
- describe '.gitlab/dashboards/custom-dashboard.yml' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab/dashboards/custom-dashboard.yml",
- file_path: '.gitlab/dashboards/custom-dashboard.yml',
- file_content: file_content
- ).execute
- end
-
- context 'with metrics_dashboard_exhaustive_validations feature flag off' do
before do
- stub_feature_flags(metrics_dashboard_exhaustive_validations: false)
- visit_blob('.gitlab/dashboards/custom-dashboard.yml')
+ project.add_developer(user)
+
+ sign_in(user)
+ visit_blob('README.md')
end
- context 'valid dashboard file' do
- let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
+ it 'shows open raw and download buttons with external storage URL prepended and user token appended to their href' do
+ path = project_raw_path(project, 'master/README.md')
+ raw_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}"
+ download_uri = "https://cdn.gitlab.com#{path}?inline=false&token=#{user.static_object_token}"
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is valid
- expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
-
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
- end
- end
-
- context 'invalid dashboard file' do
- let(:file_content) { "dashboard: 'invalid'" }
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is invalid
- expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
- expect(page).to have_content("panel_groups: should be an array of panel_groups objects")
-
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
- end
- end
- end
-
- context 'with metrics_dashboard_exhaustive_validations feature flag on' do
- before do
- stub_feature_flags(metrics_dashboard_exhaustive_validations: true)
- visit_blob('.gitlab/dashboards/custom-dashboard.yml')
- end
-
- context 'valid dashboard file' do
- let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is valid
- expect(page).to have_content('Metrics Dashboard YAML definition is valid.')
-
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
- end
- end
-
- context 'invalid dashboard file' do
- let(:file_content) { "dashboard: 'invalid'" }
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows that dashboard yaml is invalid
- expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
- expect(page).to have_content("root is missing required keys: panel_groups")
-
- # shows a learn more link
- expect(page).to have_link('Learn more')
- end
+ aggregate_failures do
+ expect(page).to have_link 'Open raw', href: raw_uri
+ expect(page).to have_link 'Download', href: download_uri
end
end
end
end
- context 'LICENSE' do
- before do
- visit_blob('LICENSE')
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows license
- expect(page).to have_content('This project is licensed under the MIT License.')
-
- # shows a learn more link
- expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/')
- end
- end
- end
-
- context '*.gemspec' do
- before do
- project.add_maintainer(project.creator)
-
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add activerecord.gemspec",
- file_path: 'activerecord.gemspec',
- file_content: <<-SPEC.strip_heredoc
- Gem::Specification.new do |s|
- s.platform = Gem::Platform::RUBY
- s.name = "activerecord"
- end
- SPEC
- ).execute
-
- visit_blob('activerecord.gemspec')
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- # shows names of dependency manager and package
- expect(page).to have_content('This project manages its dependencies using RubyGems.')
-
- # shows a learn more link
- expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
- end
- end
- end
-
- context 'CONTRIBUTING.md' do
- before do
- file_name = 'CONTRIBUTING.md'
-
- create_file(file_name, '## Contribution guidelines')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.")
- end
- end
- end
-
- context 'CHANGELOG.md' do
- before do
- file_name = 'CHANGELOG.md'
-
- create_file(file_name, '## Changelog for v1.0.0')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("To find the state of this project's repository at the time of any of these versions, check out the tags.")
- end
- end
- end
-
- context 'Cargo.toml' do
- before do
- file_name = 'Cargo.toml'
-
- create_file(file_name, '
- [package]
- name = "hello_world" # the name of the package
- version = "0.1.0" # the current version, obeying semver
- authors = ["Alice ", "Bob "]
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Cargo.")
- end
- end
- end
-
- context 'Cartfile' do
- before do
- file_name = 'Cartfile'
-
- create_file(file_name, '
- gitlab "Alamofire/Alamofire" == 4.9.0
- gitlab "Alamofire/AlamofireImage" ~> 3.4
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Carthage.")
- end
- end
- end
-
- context 'composer.json' do
- before do
- file_name = 'composer.json'
-
- create_file(file_name, '
- {
- "license": "MIT"
- }
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Composer.")
- end
- end
- end
-
- context 'Gemfile' do
- before do
- file_name = 'Gemfile'
-
- create_file(file_name, '
- source "https://rubygems.org"
-
- # Gems here
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Bundler.")
- end
- end
- end
-
- context 'Godeps.json' do
- before do
- file_name = 'Godeps.json'
-
- create_file(file_name, '
- {
- "GoVersion": "go1.6"
- }
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using godep.")
- end
- end
- end
-
- context 'go.mod' do
- before do
- file_name = 'go.mod'
-
- create_file(file_name, '
- module example.com/mymodule
-
- go 1.14
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Go Modules.")
- end
- end
- end
-
- context 'package.json' do
- before do
- file_name = 'package.json'
-
- create_file(file_name, '
- {
- "name": "my-awesome-package",
- "version": "1.0.0"
- }
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using npm.")
- end
- end
- end
-
- context 'podfile' do
- before do
- file_name = 'podfile'
-
- create_file(file_name, 'platform :ios, "8.0"')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
- end
- end
- end
-
- context 'test.podspec' do
- before do
- file_name = 'test.podspec'
-
- create_file(file_name, '
- Pod::Spec.new do |s|
- s.name = "TensorFlowLiteC"
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
- end
- end
- end
-
- context 'JSON.podspec.json' do
- before do
- file_name = 'JSON.podspec.json'
-
- create_file(file_name, '
- {
- "name": "JSON"
- }
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using CocoaPods.")
- end
- end
- end
-
- context 'requirements.txt' do
- before do
- file_name = 'requirements.txt'
-
- create_file(file_name, 'Project requirements')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using pip.")
- end
- end
- end
-
- context 'yarn.lock' do
- before do
- file_name = 'yarn.lock'
-
- create_file(file_name, '
- # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
- # yarn lockfile v1
- ')
- visit_blob(file_name)
- end
-
- it 'displays an auxiliary viewer' do
- aggregate_failures do
- expect(page).to have_content("This project manages its dependencies using Yarn.")
- end
- end
- end
-
- context 'when refactor_blob_viewer is disabled' do
- before do
- stub_feature_flags(refactor_blob_viewer: false)
- end
+ context 'files with auxiliary viewers' do
+ # This context is the same as the other 'files with auxiliary viewers' in this file, we just ensure that the auxiliary viewers still work this the refactor_blob_viewer disabled
+ # It should be safe to remove once we rollout the refactored blob viewer
describe '.gitlab-ci.yml' do
before do
@@ -1554,104 +1657,4 @@ RSpec.describe 'File blob', :js do
end
end
end
-
- context 'realtime pipelines' do
- before do
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'feature',
- branch_name: 'feature',
- commit_message: "Add ruby file",
- file_path: 'files/ruby/test.rb',
- file_content: "# Awesome content"
- ).execute
-
- create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha)
- visit_blob('files/ruby/test.rb', ref: 'feature')
- end
-
- it 'shows the realtime pipeline status' do
- page.within('.commit-actions') do
- expect(page).to have_css('.ci-status-icon')
- expect(page).to have_css('.ci-status-icon-running')
- expect(page).to have_css('.js-ci-status-icon-running')
- end
- end
- end
-
- context 'for subgroups' do
- let(:group) { create(:group) }
- let(:subgroup) { create(:group, parent: group) }
- let(:project) { create(:project, :public, :repository, group: subgroup) }
-
- it 'renders tree table without errors' do
- visit_blob('README.md')
-
- expect(page).to have_selector('.file-content')
- expect(page).not_to have_selector('.flash-alert')
- end
-
- it 'displays a GPG badge' do
- visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9')
-
- expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
- expect(page).to have_selector '.gpg-status-box.invalid'
- end
- end
-
- context 'on signed merge commit' do
- it 'displays a GPG badge' do
- visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10')
-
- expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
- expect(page).to have_selector '.gpg-status-box.invalid'
- end
- end
-
- context 'when static objects external storage is enabled' do
- before do
- stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
- end
-
- context 'private project' do
- let_it_be(:project) { create(:project, :repository, :private) }
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_developer(user)
-
- sign_in(user)
- visit_blob('README.md')
- end
-
- it 'shows open raw and download buttons with external storage URL prepended and user token appended to their href' do
- path = project_raw_path(project, 'master/README.md')
- raw_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}"
- download_uri = "https://cdn.gitlab.com#{path}?inline=false&token=#{user.static_object_token}"
-
- aggregate_failures do
- expect(page).to have_link 'Open raw', href: raw_uri
- expect(page).to have_link 'Download', href: download_uri
- end
- end
- end
-
- context 'public project' do
- before do
- visit_blob('README.md')
- end
-
- it 'shows open raw and download buttons with external storage URL prepended to their href' do
- path = project_raw_path(project, 'master/README.md')
- raw_uri = "https://cdn.gitlab.com#{path}"
- download_uri = "https://cdn.gitlab.com#{path}?inline=false"
-
- aggregate_failures do
- expect(page).to have_link 'Open raw', href: raw_uri
- expect(page).to have_link 'Download', href: download_uri
- end
- end
- end
- end
end
diff --git a/spec/frontend/__helpers__/matchers/to_match_interpolated_text.js b/spec/frontend/__helpers__/matchers/to_match_interpolated_text.js
index 4ce814a01b4..41e69bffd88 100644
--- a/spec/frontend/__helpers__/matchers/to_match_interpolated_text.js
+++ b/spec/frontend/__helpers__/matchers/to_match_interpolated_text.js
@@ -1,4 +1,5 @@
-export const toMatchInterpolatedText = (received, match) => {
+// Custom matchers are object methods and should be traditional functions to be able to access `utils` on `this`
+export function toMatchInterpolatedText(received, match) {
let clearReceived;
let clearMatch;
@@ -15,16 +16,14 @@ export const toMatchInterpolatedText = (received, match) => {
const pass = clearReceived === clearMatch;
const message = pass
? () => `
- \n\n
- Expected: ${this.utils.printExpected(clearReceived)}
- To not equal: ${this.utils.printReceived(clearMatch)}
+ Expected to not be: ${this.utils.printExpected(clearMatch)}
+ Received: ${this.utils.printReceived(clearReceived)}
`
: () =>
`
- \n\n
- Expected: ${this.utils.printExpected(clearReceived)}
- To equal: ${this.utils.printReceived(clearMatch)}
+ Expected to be: ${this.utils.printExpected(clearMatch)}
+ Received: ${this.utils.printReceived(clearReceived)}
`;
return { actual: received, message, pass };
-};
+}
diff --git a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
index 22bec77276b..b3d93906445 100644
--- a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
+++ b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
@@ -13,6 +13,7 @@ exports[`Blob Header Default Actions rendering matches the snapshot 1`] = `