Commit bd497e35 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 0388886f
...@@ -24,9 +24,6 @@ variables: ...@@ -24,9 +24,6 @@ variables:
ES_JAVA_OPTS: "-Xms256m -Xmx256m" ES_JAVA_OPTS: "-Xms256m -Xmx256m"
ELASTIC_URL: "http://elastic:changeme@elasticsearch:9200" ELASTIC_URL: "http://elastic:changeme@elasticsearch:9200"
after_script:
- date
include: include:
- local: .gitlab/ci/cache-repo.gitlab-ci.yml - local: .gitlab/ci/cache-repo.gitlab-ci.yml
- local: .gitlab/ci/cng.gitlab-ci.yml - local: .gitlab/ci/cng.gitlab-ci.yml
......
--- .releases:rules:canonical-dot-com-gitlab-stable-branch-only:
rules:
- if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAME == "gitlab-org/gitlab" && $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable-ee$/'
.releases:rules:canonical-dot-com-security-gitlab-stable-branch-only:
rules:
- if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAME == "gitlab-org/security/gitlab" && $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable-ee$/'
# Syncs any changes pushed to a stable branch to the corresponding # Syncs any changes pushed to a stable branch to the corresponding
# gitlab-foss/CE stable branch. We run this prior to any tests so that random # gitlab-foss/CE stable branch. We run this prior to any tests so that random
...@@ -10,27 +16,21 @@ ...@@ -10,27 +16,21 @@
stage: sync stage: sync
before_script: before_script:
- apk add --no-cache --update curl bash jq - apk add --no-cache --update curl bash jq
after_script: []
script: script:
- bash scripts/sync-stable-branch.sh - bash scripts/sync-stable-branch.sh
only:
variables:
- $CI_SERVER_HOST == "gitlab.com"
sync-stable-branch: sync-stable-branch:
extends: .merge-train-sync extends:
- .releases:rules:canonical-dot-com-gitlab-stable-branch-only
- .merge-train-sync
variables: variables:
SOURCE_PROJECT: gitlab-org/gitlab SOURCE_PROJECT: gitlab-org/gitlab
TARGET_PROJECT: gitlab-org/gitlab-foss TARGET_PROJECT: gitlab-org/gitlab-foss
only:
refs:
- /^[\d-]+-stable-ee$/@gitlab-org/gitlab
sync-security-branch: sync-security-branch:
extends: .merge-train-sync extends:
- .releases:rules:canonical-dot-com-security-gitlab-stable-branch-only
- .merge-train-sync
variables: variables:
SOURCE_PROJECT: gitlab-org/security/gitlab SOURCE_PROJECT: gitlab-org/security/gitlab
TARGET_PROJECT: gitlab-org/security/gitlab-foss TARGET_PROJECT: gitlab-org/security/gitlab-foss
only:
refs:
- /^[\d-]+-stable-ee$/@gitlab-org/security/gitlab
---
title: 'Geo: Fix GeoNode name in geo:update_primary_node_url rake task'
merge_request: 24649
author:
type: fixed
# frozen_string_literal: true
class ReaddTemplateColumnToServices < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
return if column_exists? :services, :template
# The migration to drop the template column never actually shipped
# to production, so we should be okay to re-add it without worrying
# about doing a data migration. If we needed to restore the value
# of `template`, we would look for entries with `project_id IS NULL`.
add_column_with_default :services, :template, :boolean, default: false, allow_null: true
end
def down
# NOP since the column is expected to exist
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_02_11_152410) do ActiveRecord::Schema.define(version: 2020_02_12_052620) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm" enable_extension "pg_trgm"
......
...@@ -205,6 +205,25 @@ secondary domain, like changing Git remotes and API URLs. ...@@ -205,6 +205,25 @@ secondary domain, like changing Git remotes and API URLs.
This command will use the changed `external_url` configuration defined This command will use the changed `external_url` configuration defined
in `/etc/gitlab/gitlab.rb`. in `/etc/gitlab/gitlab.rb`.
1. For GitLab 11.11 through 12.7 only, you may need to update the primary
node's name in the database. This bug has been fixed in GitLab 12.8.
To determine if you need to do this, search for the
`gitlab_rails["geo_node_name"]` setting in your `/etc/gitlab/gitlab.rb`
file. If it is commented out with `#` or not found at all, then you will
need to update the primary node's name in the database. You can search for it
like so:
```shell
grep "geo_node_name" /etc/gitlab/gitlab.rb
```
To update the primary node's name in the database:
```shell
gitlab-rails runner 'Gitlab::Geo.primary_node.update!(name: GeoNode.current_node_name)'
```
1. Verify you can connect to the newly promoted **primary** using its URL. 1. Verify you can connect to the newly promoted **primary** using its URL.
If you updated the DNS records for the primary domain, these changes may If you updated the DNS records for the primary domain, these changes may
not have yet propagated depending on the previous DNS records TTL. not have yet propagated depending on the previous DNS records TTL.
......
...@@ -298,27 +298,12 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag. ...@@ -298,27 +298,12 @@ Here are the steps to gate a new feature in Gitaly behind a feature flag.
### GitLab Rails ### GitLab Rails
1. In GitLab Rails:
1. Add the feature flag to `SERVER_FEATURE_FLAGS` in `lib/feature/gitaly.rb`:
```ruby
SERVER_FEATURE_FLAGS = %w[go-find-all-tags].freeze
```
1. Search for `["gitaly"]["features"]` (currently in `spec/requests/api/internal/base_spec.rb`)
and fix the expected results for the tests by adding the new feature flag into it:
```ruby
expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-get-all-lfs-pointers-go' => 'true', 'gitaly-feature-go-find-all-tags' => 'true')
```
1. Test in a Rails console by setting the feature flag: 1. Test in a Rails console by setting the feature flag:
NOTE: **Note:** NOTE: **Note:**
Pay attention to the name of the flag and the one used in the Rails console. Pay attention to the name of the flag and the one used in the Rails console.
There is a difference between them (dashes replaced by underscores and name There is a difference between them (dashes replaced by underscores and name
prefix is changed). prefix is changed). Make sure to prefix all flags with `gitaly_`.
```ruby ```ruby
Feature.enable('gitaly_go_find_all_tags') Feature.enable('gitaly_go_find_all_tags')
......
...@@ -25,7 +25,7 @@ module Banzai ...@@ -25,7 +25,7 @@ module Banzai
# Regular expression matching metrics urls # Regular expression matching metrics urls
def link_pattern def link_pattern
Gitlab::Metrics::Dashboard::Url.regex Gitlab::Metrics::Dashboard::Url.metrics_regex
end end
private private
......
...@@ -59,7 +59,7 @@ module Banzai ...@@ -59,7 +59,7 @@ module Banzai
embed = Embed.new embed = Embed.new
url = node.attribute('data-dashboard-url').to_s url = node.attribute('data-dashboard-url').to_s
set_path_and_permission(embed, url, URL.regex, :read_environment) set_path_and_permission(embed, url, URL.metrics_regex, :read_environment)
set_path_and_permission(embed, url, URL.grafana_regex, :read_project) unless embed.permission set_path_and_permission(embed, url, URL.grafana_regex, :read_project) unless embed.permission
embeds[node] = embed if embed.permission embeds[node] = embed if embed.permission
......
...@@ -32,6 +32,8 @@ class Feature ...@@ -32,6 +32,8 @@ class Feature
end end
def persisted_names def persisted_names
return [] unless Gitlab::Database.exists?
Gitlab::SafeRequestStore[:flipper_persisted_names] ||= Gitlab::SafeRequestStore[:flipper_persisted_names] ||=
begin begin
# We saw on GitLab.com, this database request was called 2300 # We saw on GitLab.com, this database request was called 2300
......
# frozen_string_literal: true # frozen_string_literal: true
require 'set'
class Feature class Feature
class Gitaly class Gitaly
# Server feature flags should use '_' to separate words. PREFIX = "gitaly_"
SERVER_FEATURE_FLAGS =
%w[
cache_invalidator
inforef_uploadpack_cache
commit_without_batch_check
use_core_delta_islands
use_git_protocol_v2
].freeze
DEFAULT_ON_FLAGS = Set.new([]).freeze
class << self class << self
def enabled?(feature_flag) def enabled?(feature_flag)
return false unless Feature::FlipperFeature.table_exists? return false unless Feature::FlipperFeature.table_exists?
default_on = DEFAULT_ON_FLAGS.include?(feature_flag) Feature.enabled?("#{PREFIX}#{feature_flag}")
Feature.enabled?("gitaly_#{feature_flag}", default_enabled: default_on)
rescue ActiveRecord::NoDatabaseError, PG::ConnectionBad rescue ActiveRecord::NoDatabaseError, PG::ConnectionBad
false false
end end
def server_feature_flags def server_feature_flags
SERVER_FEATURE_FLAGS.map do |f| Feature.persisted_names
["gitaly-feature-#{f.tr('_', '-')}", enabled?(f).to_s] .select { |f| f.start_with?(PREFIX) }
.map do |f|
flag = f.delete_prefix(PREFIX)
["gitaly-feature-#{flag.tr('_', '-')}", enabled?(flag).to_s]
end.to_h end.to_h
end end
end end
......
...@@ -203,36 +203,6 @@ module Gitlab ...@@ -203,36 +203,6 @@ module Gitlab
start_repository: start_repository) start_repository: start_repository)
end end
# DEPRECATED: https://gitlab.com/gitlab-org/gitaly/issues/1628
def user_rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:)
request = Gitaly::UserRebaseRequest.new(
repository: @gitaly_repo,
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
rebase_id: rebase_id.to_s,
branch: encode_binary(branch),
branch_sha: branch_sha,
remote_repository: remote_repository.gitaly_repository,
remote_branch: encode_binary(remote_branch)
)
response = GitalyClient.call(
@repository.storage,
:operation_service,
:user_rebase,
request,
timeout: GitalyClient.long_timeout,
remote_storage: remote_repository.storage
)
if response.pre_receive_error.presence
raise Gitlab::Git::PreReceiveError, response.pre_receive_error
elsif response.git_error.presence
raise Gitlab::Git::Repository::GitError, response.git_error
else
response.rebase_sha
end
end
def rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:, push_options: []) def rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:, push_options: [])
request_enum = QueueEnumerator.new request_enum = QueueEnumerator.new
rebase_sha = nil rebase_sha = nil
......
...@@ -6,41 +6,36 @@ module Gitlab ...@@ -6,41 +6,36 @@ module Gitlab
module Dashboard module Dashboard
class Url class Url
class << self class << self
include Gitlab::Utils::StrongMemoize
# Matches urls for a metrics dashboard. This could be # Matches urls for a metrics dashboard. This could be
# either the /metrics endpoint or the /metrics_dashboard # either the /metrics endpoint or the /metrics_dashboard
# endpoint. # endpoint.
# #
# EX - https://<host>/<namespace>/<project>/environments/<env_id>/metrics # EX - https://<host>/<namespace>/<project>/environments/<env_id>/metrics
def regex def metrics_regex
%r{ strong_memoize(:metrics_regex) do
(?<url> regex_for_project_metrics(
#{gitlab_pattern} %r{
#{project_pattern} /environments
(?:\/\-)? /(?<environment>\d+)
\/environments /metrics
\/(?<environment>\d+) }x
\/metrics
#{query_pattern}
#{anchor_pattern}
) )
}x end
end end
# Matches dashboard urls for a Grafana embed. # Matches dashboard urls for a Grafana embed.
# #
# EX - https://<host>/<namespace>/<project>/grafana/metrics_dashboard # EX - https://<host>/<namespace>/<project>/grafana/metrics_dashboard
def grafana_regex def grafana_regex
%r{ strong_memoize(:grafana_regex) do
(?<url> regex_for_project_metrics(
#{gitlab_pattern} %r{
#{project_pattern} /grafana
(?:\/\-)? /metrics_dashboard
\/grafana }x
\/metrics_dashboard
#{query_pattern}
#{anchor_pattern}
) )
}x end
end end
# Parses query params out from full url string into hash. # Parses query params out from full url string into hash.
...@@ -62,11 +57,24 @@ module Gitlab ...@@ -62,11 +57,24 @@ module Gitlab
private private
def gitlab_pattern def regex_for_project_metrics(path_suffix_pattern)
%r{
(?<url>
#{gitlab_host_pattern}
#{project_path_pattern}
(?:/-)?
#{path_suffix_pattern}
#{query_pattern}
#{anchor_pattern}
)
}x
end
def gitlab_host_pattern
Regexp.escape(Gitlab.config.gitlab.url) Regexp.escape(Gitlab.config.gitlab.url)
end end
def project_pattern def project_path_pattern
"\/#{Project.reference_pattern}" "\/#{Project.reference_pattern}"
end end
...@@ -82,3 +90,5 @@ module Gitlab ...@@ -82,3 +90,5 @@ module Gitlab
end end
end end
end end
Gitlab::Metrics::Dashboard::Url.extend_if_ee('::EE::Gitlab::Metrics::Dashboard::Url')
# frozen_string_literal: true # frozen_string_literal: true
module QA module QA
context 'Verify', :docker, quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/202149' do context 'Verify', :docker, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/issues/202149', type: :flaky } do
describe 'Pipeline creation and processing' do describe 'Pipeline creation and processing' do
let(:executor) { "qa-runner-#{Time.now.to_i}" } let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:max_wait) { 30 } let(:max_wait) { 30 }
......
...@@ -5,10 +5,6 @@ require 'spec_helper' ...@@ -5,10 +5,6 @@ require 'spec_helper'
describe Feature::Gitaly do describe Feature::Gitaly do
let(:feature_flag) { "mep_mep" } let(:feature_flag) { "mep_mep" }
before do
stub_const("#{described_class}::SERVER_FEATURE_FLAGS", [feature_flag])
end
describe ".enabled?" do describe ".enabled?" do
context 'when the gate is closed' do context 'when the gate is closed' do
before do before do
...@@ -28,15 +24,13 @@ describe Feature::Gitaly do ...@@ -28,15 +24,13 @@ describe Feature::Gitaly do
end end
describe ".server_feature_flags" do describe ".server_feature_flags" do
context 'when one flag is disabled' do before do
before do allow(Feature).to receive(:persisted_names).and_return(%w[gitaly_mep_mep foo])
stub_feature_flags(gitaly_mep_mep: false) end
end
subject { described_class.server_feature_flags } subject { described_class.server_feature_flags }
it { is_expected.to be_a(Hash) } it { is_expected.to be_a(Hash) }
it { is_expected.to eq("gitaly-feature-mep-mep" => "false") } it { is_expected.to eq("gitaly-feature-mep-mep" => "true") }
end
end end
end end
...@@ -3,38 +3,6 @@ ...@@ -3,38 +3,6 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Metrics::Dashboard::Url do describe Gitlab::Metrics::Dashboard::Url do
shared_examples_for 'a regex which matches the expected url' do
it { is_expected.to be_a Regexp }
it 'matches a metrics dashboard link with named params' do
expect(subject).to match url
subject.match(url) do |m|
expect(m.named_captures).to eq expected_params
end
end
end
shared_examples_for 'does not match non-matching urls' do
it 'does not match other gitlab urls that contain the term metrics' do
url = Gitlab::Routing.url_helpers.active_common_namespace_project_prometheus_metrics_url('foo', 'bar', :json)
expect(subject).not_to match url
end
it 'does not match other gitlab urls' do
url = Gitlab.config.gitlab.url
expect(subject).not_to match url
end
it 'does not match non-gitlab urls' do
url = 'https://www.super_awesome_site.com/'
expect(subject).not_to match url
end
end
describe '#regex' do describe '#regex' do
let(:url) do let(:url) do
Gitlab::Routing.url_helpers.metrics_namespace_project_environment_url( Gitlab::Routing.url_helpers.metrics_namespace_project_environment_url(
...@@ -59,10 +27,9 @@ describe Gitlab::Metrics::Dashboard::Url do ...@@ -59,10 +27,9 @@ describe Gitlab::Metrics::Dashboard::Url do
} }
end end
subject { described_class.regex } subject { described_class.metrics_regex }
it_behaves_like 'a regex which matches the expected url' it_behaves_like 'regex which matches url when expected'
it_behaves_like 'does not match non-matching urls'
end end
describe '#grafana_regex' do describe '#grafana_regex' do
...@@ -89,15 +56,14 @@ describe Gitlab::Metrics::Dashboard::Url do ...@@ -89,15 +56,14 @@ describe Gitlab::Metrics::Dashboard::Url do
subject { described_class.grafana_regex } subject { described_class.grafana_regex }
it_behaves_like 'a regex which matches the expected url' it_behaves_like 'regex which matches url when expected'
it_behaves_like 'does not match non-matching urls'
end end
describe '#build_dashboard_url' do describe '#build_dashboard_url' do
it 'builds the url for the dashboard endpoint' do it 'builds the url for the dashboard endpoint' do
url = described_class.build_dashboard_url('foo', 'bar', 1) url = described_class.build_dashboard_url('foo', 'bar', 1)
expect(url).to match described_class.regex expect(url).to match described_class.metrics_regex
end end
end end
end end
...@@ -1622,7 +1622,6 @@ describe Repository do ...@@ -1622,7 +1622,6 @@ describe Repository do
it 'executes the new Gitaly RPC' do it 'executes the new Gitaly RPC' do
expect_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rebase) expect_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rebase)
expect_any_instance_of(Gitlab::GitalyClient::OperationService).not_to receive(:user_rebase)
repository.rebase(user, merge_request) repository.rebase(user, merge_request)
end end
......
...@@ -313,6 +313,10 @@ describe API::Internal::Base do ...@@ -313,6 +313,10 @@ describe API::Internal::Base do
end end
context "git pull" do context "git pull" do
before do
allow(Feature).to receive(:persisted_names).and_return(%w[gitaly_mep_mep])
end
it "has the correct payload" do it "has the correct payload" do
pull(key, project) pull(key, project)
...@@ -326,7 +330,7 @@ describe API::Internal::Base do ...@@ -326,7 +330,7 @@ describe API::Internal::Base do
expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path) expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage)) expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage)) expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true', 'gitaly-feature-use-core-delta-islands' => 'true', 'gitaly-feature-use-git-protocol-v2' => 'true') expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-mep-mep' => 'true')
expect(user.reload.last_activity_on).to eql(Date.today) expect(user.reload.last_activity_on).to eql(Date.today)
end end
end end
...@@ -346,7 +350,6 @@ describe API::Internal::Base do ...@@ -346,7 +350,6 @@ describe API::Internal::Base do
expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path) expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage)) expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage)) expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true', 'gitaly-feature-use-core-delta-islands' => 'true', 'gitaly-feature-use-git-protocol-v2' => 'true')
expect(user.reload.last_activity_on).to be_nil expect(user.reload.last_activity_on).to be_nil
end end
end end
...@@ -594,7 +597,6 @@ describe API::Internal::Base do ...@@ -594,7 +597,6 @@ describe API::Internal::Base do
expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path) expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage)) expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage)) expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true', 'gitaly-feature-use-core-delta-islands' => 'true', 'gitaly-feature-use-git-protocol-v2' => 'true')
end end
end end
......
# frozen_string_literal: true
RSpec.shared_examples 'regex which matches url when expected' do
it { is_expected.to be_a Regexp }
it 'matches a metrics dashboard link with named params' do
expect(subject).to match url
subject.match(url) do |m|
expect(m.named_captures).to eq expected_params
end
end
it 'does not match other gitlab urls that contain the term metrics' do
url = Gitlab::Routing.url_helpers.active_common_namespace_project_prometheus_metrics_url('foo', 'bar', :json)
expect(subject).not_to match url
end
it 'does not match other gitlab urls' do
url = Gitlab.config.gitlab.url
expect(subject).not_to match url
end
it 'does not match non-gitlab urls' do
url = 'https://www.super_awesome_site.com/'
expect(subject).not_to match url
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'shared/projects/_list' do
let(:group) { create(:group) }
before do
allow(view).to receive(:projects).and_return(projects)
allow(view).to receive(:project_list_cache_key).and_return('fake_cache_key')
end
context 'with projects' do
let(:projects) { build_stubbed_list(:project, 1) }
it 'renders the list of projects' do
render
projects.each do |project|
expect(rendered).to have_content(project.name)
end
end
end
context 'without projects' do
let(:projects) { [] }
context 'when @contributed_projects is set' do
context 'and is empty' do
before do
@contributed_projects = []
end
it 'renders a no-content message' do
render
expect(rendered).to have_content(s_('UserProfile|This user hasn\'t contributed to any projects'))
end
end
end
context 'when @starred_projects is set' do
context 'and is empty' do
before do
@starred_projects = []
end
it 'renders a no-content message' do
render
expect(rendered).to have_content(s_('UserProfile|This user hasn\'t starred any projects'))
end
end
end
context 'and without a special instance variable' do
context 'for an explore_page' do
before do
allow(view).to receive(:explore_page).and_return(true)
end
it 'renders a no-content message' do
render
expect(rendered).to have_content(s_('UserProfile|Explore public groups to find projects to contribute to.'))
end
end
context 'for a non-explore page' do
it 'renders a no-content message' do
render
expect(rendered).to have_content(s_('UserProfile|This user doesn\'t have any personal projects'))
end
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment