Commit 579a7f8d authored by Steve Azzopardi's avatar Steve Azzopardi

Merge branch 'ce-to-ee-2018-11-22' into 'master'

CE upstream - 2018-11-22 14:21 UTC

See merge request gitlab-org/gitlab-ee!8557
parents bbc1a7c9 55dd4c4a
......@@ -84,7 +84,7 @@ export default class AjaxVariableList {
.catch(() => {
loadingIcon.classList.toggle('hide', true);
this.variableList.toggleEnableRow(true);
Flash(s__('CiVariable|Error occured while saving variables'));
Flash(s__('CiVariable|Error occurred while saving variables'));
});
}
......
......@@ -82,7 +82,7 @@ export const getFileData = (
.catch(() => {
commit(types.TOGGLE_LOADING, { entry: file });
dispatch('setErrorMessage', {
text: __('An error occured whilst loading the file.'),
text: __('An error occurred whilst loading the file.'),
action: payload =>
dispatch('getFileData', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
......@@ -124,7 +124,7 @@ export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) =
})
.catch(() => {
dispatch('setErrorMessage', {
text: __('An error occured whilst loading the file content.'),
text: __('An error occurred whilst loading the file content.'),
action: payload =>
dispatch('getRawFileData', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
......
......@@ -25,7 +25,7 @@ export const getMergeRequestData = (
})
.catch(() => {
dispatch('setErrorMessage', {
text: __('An error occured whilst loading the merge request.'),
text: __('An error occurred whilst loading the merge request.'),
action: payload =>
dispatch('getMergeRequestData', payload).then(() =>
dispatch('setErrorMessage', null),
......@@ -58,7 +58,7 @@ export const getMergeRequestChanges = (
})
.catch(() => {
dispatch('setErrorMessage', {
text: __('An error occured whilst loading the merge request changes.'),
text: __('An error occurred whilst loading the merge request changes.'),
action: payload =>
dispatch('getMergeRequestChanges', payload).then(() =>
dispatch('setErrorMessage', null),
......@@ -92,7 +92,7 @@ export const getMergeRequestVersions = (
})
.catch(() => {
dispatch('setErrorMessage', {
text: __('An error occured whilst loading the merge request version data.'),
text: __('An error occurred whilst loading the merge request version data.'),
action: payload =>
dispatch('getMergeRequestVersions', payload).then(() =>
dispatch('setErrorMessage', null),
......
......@@ -103,7 +103,7 @@ export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch)
})
.catch(() => {
dispatch('setErrorMessage', {
text: __('An error occured creating the new branch.'),
text: __('An error occurred creating the new branch.'),
action: payload => dispatch('createNewBranchFromDefault', payload),
actionText: __('Please try again'),
actionPayload: branch,
......
......@@ -76,7 +76,7 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
dispatch('showBranchNotFoundError', branchId);
} else {
dispatch('setErrorMessage', {
text: __('An error occured whilst loading all the files.'),
text: __('An error occurred whilst loading all the files.'),
action: payload =>
dispatch('getFiles', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
......
......@@ -28,7 +28,7 @@ export const receiveLatestPipelineError = ({ commit, dispatch }, err) => {
dispatch(
'setErrorMessage',
{
text: __('An error occured whilst fetching the latest pipeline.'),
text: __('An error occurred whilst fetching the latest pipeline.'),
action: () =>
dispatch('forcePipelineRequest').then(() =>
dispatch('setErrorMessage', null, { root: true }),
......@@ -84,7 +84,7 @@ export const receiveJobsError = ({ commit, dispatch }, stage) => {
dispatch(
'setErrorMessage',
{
text: __('An error occured whilst loading the pipelines jobs.'),
text: __('An error occurred whilst loading the pipelines jobs.'),
action: payload =>
dispatch('fetchJobs', payload).then(() =>
dispatch('setErrorMessage', null, { root: true }),
......@@ -123,7 +123,7 @@ export const receiveJobTraceError = ({ commit, dispatch }) => {
dispatch(
'setErrorMessage',
{
text: __('An error occured whilst fetching the job trace.'),
text: __('An error occurred whilst fetching the job trace.'),
action: () =>
dispatch('fetchJobTrace').then(() => dispatch('setErrorMessage', null, { root: true })),
actionText: __('Please try again'),
......
......@@ -47,7 +47,7 @@ export default {
errorMessage() {
return sprintf(
s__(
'ClusterIntegration|An error occured while trying to fetch zone machine types: %{error}',
'ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}',
),
{ error: this.gapiError },
);
......
......@@ -93,7 +93,7 @@ export default {
}
return sprintf(
s__('ClusterIntegration|An error occured while trying to fetch your projects: %{error}'),
s__('ClusterIntegration|An error occurred while trying to fetch your projects: %{error}'),
{ error: this.gapiError },
);
},
......
---
title: 'SystemCheck: Use a more reliable way to detect current Ruby version'
merge_request: 23291
author:
type: changed
---
title: Update rack to 2.0.6 (for QA environments)
merge_request: 23171
author: Takuya Noguchi
type: security
---
title: Upgrade minimum required Git version to 2.18.0
merge_request: 22803
author:
type: other
---
title: Fix typo for scheduled pipeline
merge_request: 23218
author: Davy Defaud
type: other
---
title: Show what RPC is called in the performance bar
merge_request: 23140
author:
type: other
......@@ -668,7 +668,7 @@ POST /projects/:id/issues/:issue_iid/move
| `to_project_id` | integer | yes | The ID of the new project |
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data '{"to_project_id": 5}' https://gitlab.example.com/api/v4/projects/4/issues/85/move
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form to_project_id=5 https://gitlab.example.com/api/v4/projects/4/issues/85/move
```
Example response:
......
......@@ -1634,6 +1634,10 @@ rspec:
- bundle exec rspec
```
NOTE: **Note:**
`include` requires the external YAML files to have the extensions `.yml` or `.yaml`.
The external file will not be included if the extension is missing.
You can define it either as a single string, or, in case you want to include
more than one files, an array of different values . The following examples
are both valid cases:
......
......@@ -79,7 +79,7 @@ Make sure you have the right version of Git installed
# Install Git
sudo apt-get install -y git-core
# Make sure Git is version 2.9.5 or higher
# Make sure Git is version 2.18.0 or higher
git --version
Is the system packaged Git too old? Remove it and compile from source.
......
......@@ -4,92 +4,95 @@ This documentation is for enabling shibboleth with omnibus-gitlab package.
In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however this is difficult to configure using the bundled Nginx provided in the omnibus-gitlab package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider.
To enable the Shibboleth OmniAuth provider you must:
1. Configure Apache shibboleth module. Installation and configuration of module it self is out of scope of this document.
Check https://wiki.shibboleth.net/ for more info.
1. You can find Apache config in gitlab-recipes (https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache)
Following changes are needed to enable shibboleth:
protect omniauth-shibboleth callback URL:
```
<Location /users/auth/shibboleth/callback>
AuthType shibboleth
ShibRequestSetting requireSession 1
ShibUseHeaders On
require valid-user
</Location>
Alias /shibboleth-sp /usr/share/shibboleth
<Location /shibboleth-sp>
Satisfy any
</Location>
<Location /Shibboleth.sso>
SetHandler shib
</Location>
```
exclude shibboleth URLs from rewriting, add "RewriteCond %{REQUEST_URI} !/Shibboleth.sso" and "RewriteCond %{REQUEST_URI} !/shibboleth-sp", config should look like this:
```
# Apache equivalent of Nginx try files
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/Shibboleth.sso
RewriteCond %{REQUEST_URI} !/shibboleth-sp
RewriteRule .* http://127.0.0.1:8080%{REQUEST_URI} [P,QSA]
RequestHeader set X_FORWARDED_PROTO 'https'
```
1. Edit /etc/gitlab/gitlab.rb configuration file to enable OmniAuth and add
Shibboleth as an OmniAuth provider. User attributes will be sent from the
Apache reverse proxy to GitLab as headers with the names from the Shibboleth
attribute mapping. Therefore the values of the `args` hash
should be in the form of `"HTTP_ATTRIBUTE"`. The keys in the hash are arguments
to the [OmniAuth::Strategies::Shibboleth class](https://github.com/toyokazu/omniauth-shibboleth/blob/master/lib/omniauth/strategies/shibboleth.rb)
and are documented by the [omniauth-shibboleth gem](https://github.com/toyokazu/omniauth-shibboleth)
(take care to note the version of the gem packaged with GitLab). If some of
your users appear to be authenticated by Shibboleth and Apache, but GitLab
rejects their account with a URI that contains "e-mail is invalid" then your
Shibboleth Identity Provider or Attribute Authority may be asserting multiple
e-mail addresses. In this instance, you might consider setting the
`multi_values` argument to `first`.
File should look like this:
```
external_url 'https://gitlab.example.com'
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
# disable Nginx
nginx['enable'] = false
gitlab_rails['omniauth_allow_single_sign_on'] = true
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_providers'] = [
{
"name" => "'shibboleth"',
"label" => "Text for Login Button",
"args" => {
"shib_session_id_field" => "HTTP_SHIB_SESSION_ID",
"shib_application_id_field" => "HTTP_SHIB_APPLICATION_ID",
"uid_field" => 'HTTP_EPPN',
"name_field" => 'HTTP_CN',
"info_fields" => { "email" => 'HTTP_MAIL'}
}
}
]
```
1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you
To enable the Shibboleth OmniAuth provider you must configure Apache shibboleth module.
Installation and configuration of module it self is out of scope of this document.
Check <https://wiki.shibboleth.net/> for more info.
You can find Apache config in gitlab-recipes (<https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache>).
The following changes are needed to enable Shibboleth:
1. Protect omniauth-shibboleth callback URL:
```
<Location /users/auth/shibboleth/callback>
AuthType shibboleth
ShibRequestSetting requireSession 1
ShibUseHeaders On
require valid-user
</Location>
Alias /shibboleth-sp /usr/share/shibboleth
<Location /shibboleth-sp>
Satisfy any
</Location>
<Location /Shibboleth.sso>
SetHandler shib
</Location>
```
1. Exclude shibboleth URLs from rewriting. Add `RewriteCond %{REQUEST_URI} !/Shibboleth.sso` and `RewriteCond %{REQUEST_URI} !/shibboleth-sp`. Config should look like this:
```
# Apache equivalent of Nginx try files
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/Shibboleth.sso
RewriteCond %{REQUEST_URI} !/shibboleth-sp
RewriteRule .* http://127.0.0.1:8080%{REQUEST_URI} [P,QSA]
RequestHeader set X_FORWARDED_PROTO 'https'
```
1. Edit `/etc/gitlab/gitlab.rb` configuration file to enable OmniAuth and add
Shibboleth as an OmniAuth provider. User attributes will be sent from the
Apache reverse proxy to GitLab as headers with the names from the Shibboleth
attribute mapping. Therefore the values of the `args` hash
should be in the form of `"HTTP_ATTRIBUTE"`. The keys in the hash are arguments
to the [OmniAuth::Strategies::Shibboleth class](https://github.com/toyokazu/omniauth-shibboleth/blob/master/lib/omniauth/strategies/shibboleth.rb)
and are documented by the [omniauth-shibboleth gem](https://github.com/toyokazu/omniauth-shibboleth)
(take care to note the version of the gem packaged with GitLab). If some of
your users appear to be authenticated by Shibboleth and Apache, but GitLab
rejects their account with a URI that contains "e-mail is invalid" then your
Shibboleth Identity Provider or Attribute Authority may be asserting multiple
e-mail addresses. In this instance, you might consider setting the
`multi_values` argument to `first`.
The file should look like this:
```
external_url 'https://gitlab.example.com'
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
# disable Nginx
nginx['enable'] = false
gitlab_rails['omniauth_allow_single_sign_on'] = true
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_providers'] = [
{
"name" => "'shibboleth"',
"label" => "Text for Login Button",
"args" => {
"shib_session_id_field" => "HTTP_SHIB_SESSION_ID",
"shib_application_id_field" => "HTTP_SHIB_APPLICATION_ID",
"uid_field" => 'HTTP_EPPN',
"name_field" => 'HTTP_CN',
"info_fields" => { "email" => 'HTTP_MAIL'}
}
}
]
```
1. [Reconfigure](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) or [restart](../administration/restart_gitlab.md#installations-from-source) GitLab for the changes to take effect if you
installed GitLab via Omnibus or from source respectively.
On the sign in page there should now be a "Sign in with: Shibboleth" icon below the regular sign in form. Click the icon to begin the authentication process. You will be redirected to IdP server (Depends on your Shibboleth module configuration). If everything goes well the user will be returned to GitLab and will be signed in.
On the sign in page, there should now be a "Sign in with: Shibboleth" icon below the regular sign in form. Click the icon to begin the authentication process. You will be redirected to IdP server (depends on your Shibboleth module configuration). If everything goes well the user will be returned to GitLab and will be signed in.
## Apache 2.4 / GitLab 8.6 update
The order of the first 2 Location directives is important. If they are reversed,
you will not get a shibboleth session!
......@@ -135,6 +138,3 @@ you will not get a shibboleth session!
RequestHeader set X_FORWARDED_PROTO 'https'
RequestHeader set X-Forwarded-Ssl on
```
[reconfigure]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure
[restart GitLab]: ../administration/restart_gitlab.md#installations-from-source
......@@ -20,7 +20,7 @@ database migrations for GitLab 7.2.
## Stash changes
If you [deleted the vendors folder during your original installation](https://github.com/gitlabhq/gitlabhq/issues/4883#issuecomment-31108431), [you will get an error](https://gitlab.com/gitlab-org/gitlab-ce/issues/1494) when you attempt to rebuild the assets in step 7. To avoid this, stash the changes in your GitLab working copy before starting:
If you deleted the vendors folder during your original installation, [you will get an error](https://gitlab.com/gitlab-org/gitlab-ce/issues/1494) when you attempt to rebuild the assets in step 7. To avoid this, stash the changes in your GitLab working copy before starting:
git stash
......
# Discord Notifications service
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22684) in GitLab 11.5.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22684) in GitLab 11.6.
The Discord Notifications service sends event notifications from GitLab to the channel for which the webhook was created.
......
......@@ -10,7 +10,7 @@ module Gitlab
image: 'illustrations/illustrations_scheduled-job_countdown.svg',
size: 'svg-394',
title: _("This is a delayed job to run in %{remainingTime}"),
content: _("This job will automatically run after it's timer finishes. " \
content: _("This job will automatically run after its timer finishes. " \
"Often they are used for incremental roll-out deploys " \
"to production environments. When unscheduled it converts " \
"into a manual action.")
......
# frozen_string_literal: true
# Gitaly note: JV: seems to be completely migrated (behind feature flags).
module Gitlab
module Git
class Blob
......
......@@ -885,12 +885,6 @@ module Gitlab
Gitlab::GitalyClient::ConflictsService.new(self, our_commit_oid, their_commit_oid)
end
def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block)
wrapped_gitaly_errors do
Gitlab::GitalyClient.migrate(method, status: status, &block)
end
end
def clean_stale_repository_files
wrapped_gitaly_errors do
gitaly_repository_client.cleanup if exists?
......
......@@ -9,11 +9,6 @@ require 'grpc/health/v1/health_services_pb'
module Gitlab
module GitalyClient
include Gitlab::Metrics::Methods
module MigrationStatus
DISABLED = 1
OPT_IN = 2
OPT_OUT = 3
end
class TooManyInvocationsError < StandardError
attr_reader :call_site, :invocation_count, :max_call_stack
......@@ -31,7 +26,7 @@ module Gitlab
end
end
SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'.freeze
SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'
MAXIMUM_GITALY_CALLS = 35
CLIENT_NAME = (Sidekiq.server? ? 'gitlab-sidekiq' : 'gitlab-web').freeze
......@@ -43,11 +38,6 @@ module Gitlab
self.query_time = 0
define_histogram :gitaly_migrate_call_duration_seconds do
docstring "Gitaly migration call execution timings"
base_labels gitaly_enabled: nil, feature: nil
end
define_histogram :gitaly_controller_action_duration_seconds do
docstring "Gitaly endpoint histogram by controller and action combination"
base_labels Gitlab::Metrics::Transaction::BASE_LABELS.merge(gitaly_service: nil, rpc: nil)
......@@ -126,7 +116,6 @@ module Gitlab
def self.call(storage, service, rpc, request, remote_storage: nil, timeout: nil)
start = Gitlab::Metrics::System.monotonic_time
request_hash = request.is_a?(Google::Protobuf::MessageExts) ? request.to_h : {}
@current_call_id ||= SecureRandom.uuid
enforce_gitaly_request_limits(:call)
......@@ -145,9 +134,7 @@ module Gitlab
current_transaction_labels.merge(gitaly_service: service.to_s, rpc: rpc.to_s),
duration)
add_call_details(id: @current_call_id, feature: service, duration: duration, request: request_hash)
@current_call_id = nil
add_call_details(feature: "#{service}##{rpc}", duration: duration, request: request_hash, rpc: rpc)
end
def self.handle_grpc_unavailable!(ex)
......@@ -222,7 +209,7 @@ module Gitlab
result
end
SERVER_FEATURE_FLAGS = %w[gogit_findcommit].freeze
SERVER_FEATURE_FLAGS = %w[].freeze
def self.server_feature_flags
SERVER_FEATURE_FLAGS.map do |f|
......@@ -237,82 +224,8 @@ module Gitlab
params['gitaly_token'].presence || Gitlab.config.gitaly['token']
end
# Evaluates whether a feature toggle is on or off
def self.feature_enabled?(feature_name, status: MigrationStatus::OPT_IN)
# Disabled features are always off!
return false if status == MigrationStatus::DISABLED
feature = Feature.get("gitaly_#{feature_name}")
# If the feature has been set, always evaluate
if Feature.persisted?(feature)
if feature.percentage_of_time_value > 0
# Probabilistically enable this feature
return Random.rand() * 100 < feature.percentage_of_time_value
end
return feature.enabled?
end
# If the feature has not been set, the default depends
# on it's status
case status
when MigrationStatus::OPT_OUT
true
when MigrationStatus::OPT_IN
opt_into_all_features? && !explicit_opt_in_required.include?(feature_name)
else
false
end
rescue => ex
# During application startup feature lookups in SQL can fail
Rails.logger.warn "exception while checking Gitaly feature status for #{feature_name}: #{ex}"
false
end
# We have a mechanism to let GitLab automatically opt in to all Gitaly
# features. We want to be able to exclude some features from automatic
# opt-in. This function has an override in EE.
def self.explicit_opt_in_required
[]
end
# opt_into_all_features? returns true when the current environment
# is one in which we opt into features automatically
def self.opt_into_all_features?
Rails.env.development? || ENV["GITALY_FEATURE_DEFAULT_ON"] == "1"
end
private_class_method :opt_into_all_features?
def self.migrate(feature, status: MigrationStatus::OPT_IN)
# Enforce limits at both the `migrate` and `call` sites to ensure that
# problems are not hidden by a feature being disabled
enforce_gitaly_request_limits(:migrate)
is_enabled = feature_enabled?(feature, status: status)
metric_name = feature.to_s
metric_name += "_gitaly" if is_enabled
Gitlab::Metrics.measure(metric_name) do
# Some migrate calls wrap other migrate calls
allow_n_plus_1_calls do
feature_stack = Thread.current[:gitaly_feature_stack] ||= []
feature_stack.unshift(feature)
begin
start = Gitlab::Metrics::System.monotonic_time
@current_call_id = SecureRandom.uuid
call_details = { id: @current_call_id }
yield is_enabled
ensure
total_time = Gitlab::Metrics::System.monotonic_time - start
gitaly_migrate_call_duration_seconds.observe({ gitaly_enabled: is_enabled, feature: feature }, total_time)
feature_stack.shift
Thread.current[:gitaly_feature_stack] = nil if feature_stack.empty?
add_call_details(call_details.merge(feature: feature, duration: total_time))
end
end
end
def self.feature_enabled?(feature_name)
Feature.enabled?("gitaly_#{feature_name}")
end
# Ensures that Gitaly is not being abuse through n+1 misuse etc
......@@ -368,48 +281,29 @@ module Gitlab
end
private_class_method :decrement_call_count
# Returns an estimate of the number of Gitaly calls made for this
# request
# Returns the of the number of Gitaly calls made for this request
def self.get_request_count
return 0 unless Gitlab::SafeRequestStore.active?
gitaly_migrate_count = get_call_count("gitaly_migrate_actual")
gitaly_call_count = get_call_count("gitaly_call_actual")
# Using the maximum of migrate and call_count will provide an
# indicator of how many Gitaly calls will be made, even
# before a feature is enabled. This provides us with a single
# metric, but not an exact number, but this tradeoff is acceptable
if gitaly_migrate_count > gitaly_call_count
gitaly_migrate_count
else
gitaly_call_count
end
get_call_count("gitaly_call_actual")
end
def self.reset_counts
return unless Gitlab::SafeRequestStore.active?
%w[migrate call].each do |call_site|
Gitlab::SafeRequestStore["gitaly_#{call_site}_actual"] = 0
Gitlab::SafeRequestStore["gitaly_#{call_site}_permitted"] = 0
end
Gitlab::SafeRequestStore["gitaly_call_actual"] = 0
Gitlab::SafeRequestStore["gitaly_call_permitted"] = 0
end
def self.add_call_details(details)
id = details.delete(:id)
return unless id && Gitlab::SafeRequestStore[:peek_enabled]
return unless Gitlab::SafeRequestStore[:peek_enabled]
Gitlab::SafeRequestStore['gitaly_call_details'] ||= {}
Gitlab::SafeRequestStore['gitaly_call_details'][id] ||= {}
Gitlab::SafeRequestStore['gitaly_call_details'][id].merge!(details)
Gitlab::SafeRequestStore['gitaly_call_details'] ||= []
Gitlab::SafeRequestStore['gitaly_call_details'] << details
end
def self.list_call_details
return {} unless Gitlab::SafeRequestStore[:peek_enabled]
return [] unless Gitlab::SafeRequestStore[:peek_enabled]
Gitlab::SafeRequestStore['gitaly_call_details'] || {}
Gitlab::SafeRequestStore['gitaly_call_details'] || []
end
def self.expected_server_version
......
......@@ -23,7 +23,6 @@ module Peek
def details
::Gitlab::GitalyClient.list_call_details
.values
.sort { |a, b| b[:duration] <=> a[:duration] }
.map(&method(:format_call_details))
end
......
......@@ -7,7 +7,7 @@ module SystemCheck
set_check_pass -> { "yes (#{self.current_version})" }
def self.required_version
@required_version ||= Gitlab::VersionInfo.new(2, 9, 5)
@required_version ||= Gitlab::VersionInfo.parse('2.18.0')
end
def self.current_version
......
......@@ -11,7 +11,7 @@ module SystemCheck
end
def self.current_version
@current_version ||= Gitlab::VersionInfo.parse(Gitlab::TaskHelpers.run_command(%w(ruby --version)))
@current_version ||= Gitlab::VersionInfo.parse(RUBY_VERSION)
end
def check?
......
......@@ -599,42 +599,15 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
msgid "An error occured creating the new branch."
msgstr ""
msgid "An error occured whilst fetching the job trace."
msgstr ""
msgid "An error occured whilst fetching the latest pipeline."
msgstr ""
msgid "An error occured whilst loading all the files."
msgstr ""
msgid "An error occured whilst loading the file content."
msgstr ""
msgid "An error occured whilst loading the file."
msgstr ""
msgid "An error occured whilst loading the merge request changes."
msgstr ""
msgid "An error occured whilst loading the merge request version data."
msgstr ""
msgid "An error occured whilst loading the merge request."
msgstr ""
msgid "An error occured whilst loading the pipelines jobs."
msgstr ""
msgid "An error occurred adding a draft to the discussion."
msgstr ""
msgid "An error occurred adding a new draft."
msgstr ""
msgid "An error occurred creating the new branch."
msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
......@@ -743,6 +716,33 @@ msgstr ""
msgid "An error occurred while validating username"
msgstr ""
msgid "An error occurred whilst fetching the job trace."
msgstr ""
msgid "An error occurred whilst fetching the latest pipeline."
msgstr ""
msgid "An error occurred whilst loading all the files."
msgstr ""
msgid "An error occurred whilst loading the file content."
msgstr ""
msgid "An error occurred whilst loading the file."
msgstr ""
msgid "An error occurred whilst loading the merge request changes."
msgstr ""
msgid "An error occurred whilst loading the merge request version data."
msgstr ""
msgid "An error occurred whilst loading the merge request."
msgstr ""
msgid "An error occurred whilst loading the pipelines jobs."
msgstr ""
msgid "An error occurred. Please try again."
msgstr ""
......@@ -1600,7 +1600,7 @@ msgstr ""
msgid "CiVariable|Create wildcard"
msgstr ""
msgid "CiVariable|Error occured while saving variables"
msgid "CiVariable|Error occurred while saving variables"
msgstr ""
msgid "CiVariable|New environment"
......@@ -1708,13 +1708,13 @@ msgstr ""
msgid "ClusterIntegration|An error occured while trying to fetch project zones: %{error}"
msgstr ""
msgid "ClusterIntegration|An error occured while trying to fetch your projects: %{error}"
msgid "ClusterIntegration|An error occurred when trying to contact the Google Cloud API. Please try again later."
msgstr ""
msgid "ClusterIntegration|An error occured while trying to fetch zone machine types: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch your projects: %{error}"
msgstr ""
msgid "ClusterIntegration|An error occurred when trying to contact the Google Cloud API. Please try again later."
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
msgid "ClusterIntegration|Applications"
......@@ -8289,7 +8289,7 @@ msgstr ""
msgid "This job requires a manual action"
msgstr ""
msgid "This job will automatically run after it's timer finishes. Often they are used for incremental roll-out deploys to production environments. When unscheduled it converts into a manual action."
msgid "This job will automatically run after its timer finishes. Often they are used for incremental roll-out deploys to production environments. When unscheduled it converts into a manual action."
msgstr ""
msgid "This means you can not push code until you create an empty repository or import existing one."
......
......@@ -56,7 +56,7 @@ GEM
byebug (~> 9.1)
pry (~> 0.10)
public_suffix (3.0.1)
rack (2.0.3)
rack (2.0.6)
rack-test (0.8.2)
rack (>= 1.0, < 3)
rake (12.3.0)
......@@ -103,4 +103,4 @@ DEPENDENCIES
selenium-webdriver (~> 3.8.0)
BUNDLED WITH
1.16.4
1.17.1
GEM
remote: https://rubygems.org/
specs:
rack (2.0.4)
rack (2.0.6)
rake (12.3.0)
PLATFORMS
......@@ -12,4 +12,4 @@ DEPENDENCIES
rake
BUNDLED WITH
1.16.1
1.17.1
# frozen_string_literal: true
module RuboCop
module Cop
class SafeParams < RuboCop::Cop::Cop
MSG = 'Use `safe_params` instead of `params` in url_for.'.freeze
METHOD_NAME_PATTERN = :url_for
UNSAFE_PARAM = :params
def on_send(node)
return unless method_name(node) == METHOD_NAME_PATTERN
add_offense(node, location: :expression) unless safe_params?(node)
end
private
def safe_params?(node)
node.descendants.each do |param_node|
next unless param_node.descendants.empty?
return false if method_name(param_node) == UNSAFE_PARAM
end
true
end
def method_name(node)
node.children[1]
end
end
end
end
......@@ -5,6 +5,7 @@ require_relative 'cop/gitlab/httparty'
require_relative 'cop/gitlab/finder_with_find_by'
require_relative 'cop/gitlab/union'
require_relative 'cop/include_sidekiq_worker'
require_relative 'cop/safe_params'
require_relative 'cop/avoid_return_from_blocks'
require_relative 'cop/avoid_break_from_strong_memoize'
require_relative 'cop/avoid_route_redirect_leading_slash'
......
......@@ -111,6 +111,6 @@ Promise.all(matchedFiles.map(checkFileWithPrettierConfig))
if (didWarn) process.exit(1);
})
.catch(e => {
console.log(`\nAn error occured while processing files with prettier: ${e.message}\n`);
console.log(`\nAn error occurred while processing files with prettier: ${e.message}\n`);
process.exit(1);
});
......@@ -106,6 +106,7 @@ module Trigger
def extra_variables
{
'GITLAB_VERSION' => ENV['CI_COMMIT_SHA'],
'GITLAB_REF_SLUG' => ENV['CI_COMMIT_REF_SLUG'],
'ALTERNATIVE_SOURCES' => 'true',
'ee' => Trigger.ee? ? 'true' : 'false',
'QA_BRANCH' => ENV['QA_BRANCH'] || 'master'
......
......@@ -596,7 +596,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
it 'shows delayed job', :js do
expect(page).to have_content('This is a delayed job to run in')
expect(page).to have_content("This job will automatically run after it's timer finishes.")
expect(page).to have_content("This job will automatically run after its timer finishes.")
expect(page).to have_link('Unschedule job')
end
......
require 'spec_helper'
describe 'User updates wiki page' do
shared_examples 'wiki page user update' do
let(:user) { create(:user) }
let(:user) { create(:user) }
before do
project.add_maintainer(user)
sign_in(user)
end
context 'when wiki is empty' do
before do
project.add_maintainer(user)
sign_in(user)
visit(project_wikis_path(project))
click_link "Create your first page"
end
context 'when wiki is empty' do
before do
visit(project_wikis_path(project))
click_link "Create your first page"
end
context 'in a user namespace' do
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
context 'in a user namespace' do
let(:project) { create(:project, :wiki_repo) }
it 'redirects back to the home edit page' do
page.within(:css, '.wiki-form .form-actions') do
click_on('Cancel')
end
expect(current_path).to eq project_wiki_path(project, :home)
it 'redirects back to the home edit page' do
page.within(:css, '.wiki-form .form-actions') do
click_on('Cancel')
end
it 'updates a page that has a path', :js do
click_on('New page')
expect(current_path).to eq project_wiki_path(project, :home)
end
page.within('#modal-new-wiki') do
fill_in(:new_wiki_path, with: 'one/two/three-test')
click_on('Create page')
end
it 'updates a page that has a path', :js do
click_on('New page')
page.within '.wiki-form' do
fill_in(:wiki_content, with: 'wiki content')
click_on('Create page')
end
page.within('#modal-new-wiki') do
fill_in(:new_wiki_path, with: 'one/two/three-test')
click_on('Create page')
end
expect(current_path).to include('one/two/three-test')
expect(find('.wiki-pages')).to have_content('Three')
page.within '.wiki-form' do
fill_in(:wiki_content, with: 'wiki content')
click_on('Create page')
end
first(:link, text: 'Three').click
expect(current_path).to include('one/two/three-test')
expect(find('.wiki-pages')).to have_content('Three')
expect(find('.nav-text')).to have_content('Three')
first(:link, text: 'Three').click
click_on('Edit')
expect(find('.nav-text')).to have_content('Three')
expect(current_path).to include('one/two/three-test')
expect(page).to have_content('Edit Page')
click_on('Edit')
fill_in('Content', with: 'Updated Wiki Content')
click_on('Save changes')
expect(current_path).to include('one/two/three-test')
expect(page).to have_content('Edit Page')
expect(page).to have_content('Updated Wiki Content')
end
fill_in('Content', with: 'Updated Wiki Content')
click_on('Save changes')
it_behaves_like 'wiki file attachments'
expect(page).to have_content('Updated Wiki Content')
end
end
context 'when wiki is not empty' do
let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: 'home', content: 'Home page' }) }
it_behaves_like 'wiki file attachments'
end
end
before do
visit(project_wikis_path(project))
context 'when wiki is not empty' do
let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: 'home', content: 'Home page' }) }
click_link('Edit')
end
before do
visit(project_wikis_path(project))
context 'in a user namespace' do
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
click_link('Edit')
end
it 'updates a page' do
# Commit message field should have correct value.
expect(page).to have_field('wiki[message]', with: 'Update home')
context 'in a user namespace' do
let(:project) { create(:project, :wiki_repo) }
fill_in(:wiki_content, with: 'My awesome wiki!')
click_button('Save changes')
it 'updates a page' do
# Commit message field should have correct value.
expect(page).to have_field('wiki[message]', with: 'Update home')
expect(page).to have_content('Home')
expect(page).to have_content("Last edited by #{user.name}")
expect(page).to have_content('My awesome wiki!')
end
fill_in(:wiki_content, with: 'My awesome wiki!')
click_button('Save changes')
it 'shows a validation error message' do
fill_in(:wiki_content, with: '')
click_button('Save changes')
expect(page).to have_content('Home')
expect(page).to have_content("Last edited by #{user.name}")
expect(page).to have_content('My awesome wiki!')
end
expect(page).to have_selector('.wiki-form')
expect(page).to have_content('Edit Page')
expect(page).to have_content('The form contains the following error:')
expect(page).to have_content("Content can't be blank")
expect(find('textarea#wiki_content').value).to eq('')
end
it 'shows a validation error message' do
fill_in(:wiki_content, with: '')
click_button('Save changes')
it 'shows the emoji autocompletion dropdown', :js do
find('#wiki_content').native.send_keys('')
fill_in(:wiki_content, with: ':')
expect(page).to have_selector('.wiki-form')
expect(page).to have_content('Edit Page')
expect(page).to have_content('The form contains the following error:')
expect(page).to have_content("Content can't be blank")
expect(find('textarea#wiki_content').value).to eq('')
end
expect(page).to have_selector('.atwho-view')
end
it 'shows the emoji autocompletion dropdown', :js do
find('#wiki_content').native.send_keys('')
fill_in(:wiki_content, with: ':')
it 'shows the error message' do
wiki_page.update(content: 'Update')
expect(page).to have_selector('.atwho-view')
end
click_button('Save changes')
it 'shows the error message' do
wiki_page.update(content: 'Update')
expect(page).to have_content('Someone edited the page the same time you did.')
end
click_button('Save changes')
it 'updates a page' do
fill_in('Content', with: 'Updated Wiki Content')
click_on('Save changes')
expect(page).to have_content('Someone edited the page the same time you did.')
end
expect(page).to have_content('Updated Wiki Content')
end
it 'updates a page' do
fill_in('Content', with: 'Updated Wiki Content')
click_on('Save changes')
it 'cancels editing of a page' do
page.within(:css, '.wiki-form .form-actions') do
click_on('Cancel')
end
expect(page).to have_content('Updated Wiki Content')
end
expect(current_path).to eq(project_wiki_path(project, wiki_page))
it 'cancels editing of a page' do
page.within(:css, '.wiki-form .form-actions') do
click_on('Cancel')
end
it_behaves_like 'wiki file attachments'
expect(current_path).to eq(project_wiki_path(project, wiki_page))
end
context 'in a group namespace' do
let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
it_behaves_like 'wiki file attachments'
end
it 'updates a page' do
# Commit message field should have correct value.
expect(page).to have_field('wiki[message]', with: 'Update home')
context 'in a group namespace' do
let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
fill_in(:wiki_content, with: 'My awesome wiki!')
it 'updates a page' do
# Commit message field should have correct value.
expect(page).to have_field('wiki[message]', with: 'Update home')
click_button('Save changes')
fill_in(:wiki_content, with: 'My awesome wiki!')
expect(page).to have_content('Home')
expect(page).to have_content("Last edited by #{user.name}")
expect(page).to have_content('My awesome wiki!')
end
click_button('Save changes')
it_behaves_like 'wiki file attachments'
expect(page).to have_content('Home')
expect(page).to have_content("Last edited by #{user.name}")
expect(page).to have_content('My awesome wiki!')
end
end
context 'when the page is in a subdir' do
let!(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
let(:page_name) { 'page_name' }
let(:page_dir) { "foo/bar/#{page_name}" }
let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: page_dir, content: 'Home page' }) }
it_behaves_like 'wiki file attachments'
end
end
before do
visit(project_wiki_edit_path(project, wiki_page))
end
context 'when the page is in a subdir' do
let!(:project) { create(:project, :wiki_repo) }
let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
let(:page_name) { 'page_name' }
let(:page_dir) { "foo/bar/#{page_name}" }
let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, attrs: { title: page_dir, content: 'Home page' }) }
it 'moves the page to the root folder', :skip_gitaly_mock do
fill_in(:wiki_title, with: "/#{page_name}")
before do
visit(project_wiki_edit_path(project, wiki_page))
end
click_button('Save changes')
it 'moves the page to the root folder' do
fill_in(:wiki_title, with: "/#{page_name}")
expect(current_path).to eq(project_wiki_path(project, page_name))
end
click_button('Save changes')
it 'moves the page to other dir' do
new_page_dir = "foo1/bar1/#{page_name}"
expect(current_path).to eq(project_wiki_path(project, page_name))
end
fill_in(:wiki_title, with: new_page_dir)
it 'moves the page to other dir' do
new_page_dir = "foo1/bar1/#{page_name}"
click_button('Save changes')
fill_in(:wiki_title, with: new_page_dir)
expect(current_path).to eq(project_wiki_path(project, new_page_dir))
end
click_button('Save changes')
it 'remains in the same place if title has not changed' do
original_path = project_wiki_path(project, wiki_page)
expect(current_path).to eq(project_wiki_path(project, new_page_dir))
end
fill_in(:wiki_title, with: page_name)
it 'remains in the same place if title has not changed' do
original_path = project_wiki_path(project, wiki_page)
click_button('Save changes')
fill_in(:wiki_title, with: page_name)
expect(current_path).to eq(original_path)
end
click_button('Save changes')
it 'can be moved to a different dir with a different name' do
new_page_dir = "foo1/bar1/new_page_name"
expect(current_path).to eq(original_path)
end
fill_in(:wiki_title, with: new_page_dir)
it 'can be moved to a different dir with a different name' do
new_page_dir = "foo1/bar1/new_page_name"
click_button('Save changes')
fill_in(:wiki_title, with: new_page_dir)
expect(current_path).to eq(project_wiki_path(project, new_page_dir))
end
click_button('Save changes')
it 'can be renamed and moved to the root folder' do
new_name = 'new_page_name'
expect(current_path).to eq(project_wiki_path(project, new_page_dir))
end
fill_in(:wiki_title, with: "/#{new_name}")
it 'can be renamed and moved to the root folder' do
new_name = 'new_page_name'
click_button('Save changes')
fill_in(:wiki_title, with: "/#{new_name}")
expect(current_path).to eq(project_wiki_path(project, new_name))
end
click_button('Save changes')
it 'squishes the title before creating the page' do
new_page_dir = " foo1 / bar1 / #{page_name} "
expect(current_path).to eq(project_wiki_path(project, new_name))
end
fill_in(:wiki_title, with: new_page_dir)
it 'squishes the title before creating the page' do
new_page_dir = " foo1 / bar1 / #{page_name} "
click_button('Save changes')
fill_in(:wiki_title, with: new_page_dir)
expect(current_path).to eq(project_wiki_path(project, "foo1/bar1/#{page_name}"))
end
click_button('Save changes')
it_behaves_like 'wiki file attachments'
expect(current_path).to eq(project_wiki_path(project, "foo1/bar1/#{page_name}"))
end
end
context 'when Gitaly is enabled' do
it_behaves_like 'wiki page user update'
end
context 'when Gitaly is disabled', :skip_gitaly_mock do
it_behaves_like 'wiki page user update'
it_behaves_like 'wiki file attachments'
end
end
require 'spec_helper'
describe 'User views a wiki page' do
shared_examples 'wiki page user view' do
include WikiHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:path) { 'image.png' }
let(:wiki_page) do
create(:wiki_page,
wiki: project.wiki,
attrs: { title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})" })
end
include WikiHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:path) { 'image.png' }
let(:wiki_page) do
create(:wiki_page,
wiki: project.wiki,
attrs: { title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})" })
end
before do
project.add_maintainer(user)
sign_in(user)
end
before do
project.add_maintainer(user)
sign_in(user)
end
context 'when wiki is empty' do
before do
visit(project_wikis_path(project))
click_link "Create your first page"
context 'when wiki is empty' do
before do
visit(project_wikis_path(project))
click_link "Create your first page"
click_on('New page')
click_on('New page')
page.within('#modal-new-wiki') do
fill_in(:new_wiki_path, with: 'one/two/three-test')
click_on('Create page')
end
page.within('#modal-new-wiki') do
fill_in(:new_wiki_path, with: 'one/two/three-test')
click_on('Create page')
end
page.within('.wiki-form') do
fill_in(:wiki_content, with: 'wiki content')
click_on('Create page')
end
page.within('.wiki-form') do
fill_in(:wiki_content, with: 'wiki content')
click_on('Create page')
end
end
it 'shows the history of a page that has a path', :js do
expect(current_path).to include('one/two/three-test')
it 'shows the history of a page that has a path', :js do
expect(current_path).to include('one/two/three-test')
first(:link, text: 'Three').click
click_on('Page history')
first(:link, text: 'Three').click
click_on('Page history')
expect(current_path).to include('one/two/three-test')
expect(current_path).to include('one/two/three-test')
page.within(:css, '.nav-text') do
expect(page).to have_content('History')
end
page.within(:css, '.nav-text') do
expect(page).to have_content('History')
end
end
it 'shows an old version of a page', :js do
expect(current_path).to include('one/two/three-test')
expect(find('.wiki-pages')).to have_content('Three')
first(:link, text: 'Three').click
expect(find('.nav-text')).to have_content('Three')
it 'shows an old version of a page', :js do
expect(current_path).to include('one/two/three-test')
expect(find('.wiki-pages')).to have_content('Three')
click_on('Edit')
first(:link, text: 'Three').click
expect(current_path).to include('one/two/three-test')
expect(page).to have_content('Edit Page')
expect(find('.nav-text')).to have_content('Three')
fill_in('Content', with: 'Updated Wiki Content')
click_on('Edit')
click_on('Save changes')
click_on('Page history')
expect(current_path).to include('one/two/three-test')
expect(page).to have_content('Edit Page')
page.within(:css, '.nav-text') do
expect(page).to have_content('History')
end
fill_in('Content', with: 'Updated Wiki Content')
find('a[href*="?version_id"]')
end
end
context 'when a page does not have history' do
before do
visit(project_wiki_path(project, wiki_page))
end
click_on('Save changes')
click_on('Page history')
it 'shows all the pages' do
expect(page).to have_content(user.name)
expect(find('.wiki-pages')).to have_content(wiki_page.title.capitalize)
page.within(:css, '.nav-text') do
expect(page).to have_content('History')
end
context 'shows a file stored in a page' do
let(:path) { upload_file_to_wiki(project, user, 'dk.png') }
find('a[href*="?version_id"]')
end
end
it do
expect(page).to have_xpath("//img[@data-src='#{project.wiki.wiki_base_path}/#{path}']")
expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/#{path}")
context 'when a page does not have history' do
before do
visit(project_wiki_path(project, wiki_page))
end
click_on('image')
it 'shows all the pages' do
expect(page).to have_content(user.name)
expect(find('.wiki-pages')).to have_content(wiki_page.title.capitalize)
end
expect(current_path).to match("wikis/#{path}")
expect(page).not_to have_xpath('/html') # Page should render the image which means there is no html involved
end
end
context 'shows a file stored in a page' do
let(:path) { upload_file_to_wiki(project, user, 'dk.png') }
it 'shows the creation page if file does not exist' do
it do
expect(page).to have_xpath("//img[@data-src='#{project.wiki.wiki_base_path}/#{path}']")
expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/#{path}")
click_on('image')
expect(current_path).to match("wikis/#{path}")
expect(page).to have_content('New Wiki Page')
expect(page).to have_content('Create page')
expect(page).not_to have_xpath('/html') # Page should render the image which means there is no html involved
end
end
context 'when a page has history' do
before do
wiki_page.update(message: 'updated home', content: 'updated [some link](other-page)')
end
it 'shows the creation page if file does not exist' do
expect(page).to have_link('image', href: "#{project.wiki.wiki_base_path}/#{path}")
it 'shows the page history' do
visit(project_wiki_path(project, wiki_page))
click_on('image')
expect(page).to have_selector('a.btn', text: 'Edit')
expect(current_path).to match("wikis/#{path}")
expect(page).to have_content('New Wiki Page')
expect(page).to have_content('Create page')
end
end
click_on('Page history')
context 'when a page has history' do
before do
wiki_page.update(message: 'updated home', content: 'updated [some link](other-page)')
end
expect(page).to have_content(user.name)
expect(page).to have_content("#{user.username} created page: home")
expect(page).to have_content('updated home')
end
it 'shows the page history' do
visit(project_wiki_path(project, wiki_page))
it 'does not show the "Edit" button' do
visit(project_wiki_path(project, wiki_page, version_id: wiki_page.versions.last.id))
expect(page).to have_selector('a.btn', text: 'Edit')
expect(page).not_to have_selector('a.btn', text: 'Edit')
end
click_on('Page history')
expect(page).to have_content(user.name)
expect(page).to have_content("#{user.username} created page: home")
expect(page).to have_content('updated home')
end
context 'when page has invalid content encoding' do
let(:content) { 'whatever'.force_encoding('ISO-8859-1') }
it 'does not show the "Edit" button' do
visit(project_wiki_path(project, wiki_page, version_id: wiki_page.versions.last.id))
before do
allow(Gitlab::EncodingHelper).to receive(:encode!).and_return(content)
expect(page).not_to have_selector('a.btn', text: 'Edit')
end
end
visit(project_wiki_path(project, wiki_page))
end
context 'when page has invalid content encoding' do
let(:content) { 'whatever'.force_encoding('ISO-8859-1') }
it 'does not show "Edit" button' do
expect(page).not_to have_selector('a.btn', text: 'Edit')
end
before do
allow(Gitlab::EncodingHelper).to receive(:encode!).and_return(content)
it 'shows error' do
page.within(:css, '.flash-notice') do
expect(page).to have_content('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')
end
end
visit(project_wiki_path(project, wiki_page))
end
it 'opens a default wiki page', :js do
visit(project_path(project))
find('.shortcuts-wiki').click
click_link "Create your first page"
it 'does not show "Edit" button' do
expect(page).not_to have_selector('a.btn', text: 'Edit')
end
expect(page).to have_content('Home · Create Page')
it 'shows error' do
page.within(:css, '.flash-notice') do
expect(page).to have_content('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')
end
end
end
context 'when Gitaly is enabled' do
it_behaves_like 'wiki page user view'
end
it 'opens a default wiki page', :js do
visit(project_path(project))
find('.shortcuts-wiki').click
click_link "Create your first page"
context 'when Gitaly is disabled', :skip_gitaly_mock do
it_behaves_like 'wiki page user view'
expect(page).to have_content('Home · Create Page')
end
end
......@@ -296,7 +296,7 @@ describe('IDE store file actions', () => {
.getFileData({ state: store.state, commit() {}, dispatch }, { path: localFile.path })
.then(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the file.',
text: 'An error occurred whilst loading the file.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
......@@ -408,7 +408,7 @@ describe('IDE store file actions', () => {
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the file content.',
text: 'An error occurred whilst loading the file content.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
......
......@@ -82,7 +82,7 @@ describe('IDE store merge request actions', () => {
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the merge request.',
text: 'An error occurred whilst loading the merge request.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
......@@ -155,7 +155,7 @@ describe('IDE store merge request actions', () => {
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the merge request changes.',
text: 'An error occurred whilst loading the merge request changes.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
......@@ -225,7 +225,7 @@ describe('IDE store merge request actions', () => {
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading the merge request version data.',
text: 'An error occurred whilst loading the merge request version data.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: {
......
......@@ -143,7 +143,7 @@ describe('Multi-file store tree actions', () => {
.then(done.fail)
.catch(() => {
expect(dispatch).toHaveBeenCalledWith('setErrorMessage', {
text: 'An error occured whilst loading all the files.',
text: 'An error occurred whilst loading all the files.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: { projectId: 'abc/def', branchId: 'master-testing' },
......
......@@ -77,7 +77,7 @@ describe('IDE pipelines actions', () => {
{
type: 'setErrorMessage',
payload: {
text: 'An error occured whilst fetching the latest pipeline.',
text: 'An error occurred whilst fetching the latest pipeline.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: null,
......@@ -223,7 +223,7 @@ describe('IDE pipelines actions', () => {
{
type: 'setErrorMessage',
payload: {
text: 'An error occured whilst loading the pipelines jobs.',
text: 'An error occurred whilst loading the pipelines jobs.',
action: jasmine.anything(),
actionText: 'Please try again',
actionPayload: { id: 1 },
......@@ -360,7 +360,7 @@ describe('IDE pipelines actions', () => {
{
type: 'setErrorMessage',
payload: {
text: 'An error occured whilst fetching the job trace.',
text: 'An error occurred whilst fetching the job trace.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: null,
......
......@@ -205,28 +205,18 @@ describe ExtractsPath do
end
describe '#lfs_blob_ids' do
shared_examples '#lfs_blob_ids' do
let(:tag) { @project.repository.add_tag(@project.owner, 'my-annotated-tag', 'master', 'test tag') }
let(:ref) { tag.target }
let(:params) { { ref: ref, path: 'README.md' } }
let(:tag) { @project.repository.add_tag(@project.owner, 'my-annotated-tag', 'master', 'test tag') }
let(:ref) { tag.target }
let(:params) { { ref: ref, path: 'README.md' } }
before do
@project = create(:project, :repository)
end
it 'handles annotated tags' do
assign_ref_vars
expect(lfs_blob_ids).to eq([])
end
before do
@project = create(:project, :repository)
end
context 'when gitaly is enabled' do
it_behaves_like '#lfs_blob_ids'
end
it 'handles annotated tags' do
assign_ref_vars
context 'when gitaly is disabled', :skip_gitaly_mock do
it_behaves_like '#lfs_blob_ids'
expect(lfs_blob_ids).to eq([])
end
end
end
......@@ -37,17 +37,7 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
let(:stub_path) { '.gitignore' }
end
shared_examples 'initializes a DiffCollection' do
it 'returns a valid instance of a DiffCollection' do
expect(diff_files).to be_a(Gitlab::Git::DiffCollection)
end
end
context 'with Gitaly disabled', :disable_gitaly do
it_behaves_like 'initializes a DiffCollection'
end
context 'with Gitaly enabled' do
it_behaves_like 'initializes a DiffCollection'
it 'returns a valid instance of a DiffCollection' do
expect(diff_files).to be_a(Gitlab::Git::DiffCollection)
end
end
......@@ -128,7 +128,7 @@ describe Gitlab::Git::Blob, :seed_helper do
end
end
shared_examples 'finding blobs by ID' do
describe '.raw' do
let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) }
let(:bad_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::BigCommit::ID) }
......@@ -166,16 +166,6 @@ describe Gitlab::Git::Blob, :seed_helper do
end
end
describe '.raw' do
context 'when the blob_raw Gitaly feature is enabled' do
it_behaves_like 'finding blobs by ID'
end
context 'when the blob_raw Gitaly feature is disabled', :skip_gitaly_mock do
it_behaves_like 'finding blobs by ID'
end
end
describe '.batch' do
let(:blob_references) do
[
......
......@@ -183,110 +183,100 @@ describe Gitlab::Git::Commit, :seed_helper do
end
end
shared_examples '.where' do
context 'path is empty string' do
subject do
commits = described_class.where(
repo: repository,
ref: 'master',
path: '',
limit: 10
)
commits.map { |c| c.id }
end
context 'path is empty string' do
subject do
commits = described_class.where(
repo: repository,
ref: 'master',
path: '',
limit: 10
)
it 'has 10 elements' do
expect(subject.size).to eq(10)
end
it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
commits.map { |c| c.id }
end
context 'path is nil' do
subject do
commits = described_class.where(
repo: repository,
ref: 'master',
path: nil,
limit: 10
)
commits.map { |c| c.id }
end
it 'has 10 elements' do
expect(subject.size).to eq(10)
end
it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
it 'has 10 elements' do
expect(subject.size).to eq(10)
end
it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
end
context 'ref is branch name' do
subject do
commits = described_class.where(
repo: repository,
ref: 'master',
path: 'files',
limit: 3,
offset: 1
)
context 'path is nil' do
subject do
commits = described_class.where(
repo: repository,
ref: 'master',
path: nil,
limit: 10
)
commits.map { |c| c.id }
end
commits.map { |c| c.id }
end
it 'has 3 elements' do
expect(subject.size).to eq(3)
end
it { is_expected.to include("d14d6c0abdd253381df51a723d58691b2ee1ab08") }
it { is_expected.not_to include("eb49186cfa5c4338011f5f590fac11bd66c5c631") }
it 'has 10 elements' do
expect(subject.size).to eq(10)
end
it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
end
context 'ref is commit id' do
subject do
commits = described_class.where(
repo: repository,
ref: "874797c3a73b60d2187ed6e2fcabd289ff75171e",
path: 'files',
limit: 3,
offset: 1
)
context 'ref is branch name' do
subject do
commits = described_class.where(
repo: repository,
ref: 'master',
path: 'files',
limit: 3,
offset: 1
)
commits.map { |c| c.id }
end
commits.map { |c| c.id }
end
it 'has 3 elements' do
expect(subject.size).to eq(3)
end
it { is_expected.to include("2f63565e7aac07bcdadb654e253078b727143ec4") }
it { is_expected.not_to include(SeedRepo::Commit::ID) }
it 'has 3 elements' do
expect(subject.size).to eq(3)
end
it { is_expected.to include("d14d6c0abdd253381df51a723d58691b2ee1ab08") }
it { is_expected.not_to include("eb49186cfa5c4338011f5f590fac11bd66c5c631") }
end
context 'ref is tag' do
subject do
commits = described_class.where(
repo: repository,
ref: 'v1.0.0',
path: 'files',
limit: 3,
offset: 1
)
context 'ref is commit id' do
subject do
commits = described_class.where(
repo: repository,
ref: "874797c3a73b60d2187ed6e2fcabd289ff75171e",
path: 'files',
limit: 3,
offset: 1
)
commits.map { |c| c.id }
end
commits.map { |c| c.id }
end
it 'has 3 elements' do
expect(subject.size).to eq(3)
end
it { is_expected.to include("874797c3a73b60d2187ed6e2fcabd289ff75171e") }
it { is_expected.not_to include(SeedRepo::Commit::ID) }
it 'has 3 elements' do
expect(subject.size).to eq(3)
end
it { is_expected.to include("2f63565e7aac07bcdadb654e253078b727143ec4") }
it { is_expected.not_to include(SeedRepo::Commit::ID) }
end
describe '.where with gitaly' do
it_should_behave_like '.where'
end
context 'ref is tag' do
subject do
commits = described_class.where(
repo: repository,
ref: 'v1.0.0',
path: 'files',
limit: 3,
offset: 1
)
describe '.where without gitaly', :skip_gitaly_mock do
it_should_behave_like '.where'
commits.map { |c| c.id }
end
it 'has 3 elements' do
expect(subject.size).to eq(3)
end
it { is_expected.to include("874797c3a73b60d2187ed6e2fcabd289ff75171e") }
it { is_expected.not_to include(SeedRepo::Commit::ID) }
end
describe '.between' do
......@@ -508,7 +498,7 @@ describe Gitlab::Git::Commit, :seed_helper do
end
end
shared_examples '#stats' do
describe '#stats' do
subject { commit.stats }
describe '#additions' do
......@@ -527,14 +517,6 @@ describe Gitlab::Git::Commit, :seed_helper do
end
end
describe '#stats with gitaly on' do
it_should_behave_like '#stats'
end
describe '#stats with gitaly disabled', :skip_gitaly_mock do
it_should_behave_like '#stats'
end
describe '#has_zero_stats?' do
it { expect(commit.has_zero_stats?).to eq(false) }
end
......@@ -577,25 +559,15 @@ describe Gitlab::Git::Commit, :seed_helper do
commit_ids.map { |id| described_class.get_message(repository, id) }
end
shared_examples 'getting commit messages' do
it 'gets commit messages' do
expect(subject).to contain_exactly(
"Added contributing guide\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"Add submodule\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n"
)
end
end
context 'when Gitaly commit_messages feature is enabled' do
it_behaves_like 'getting commit messages'
it 'gets messages in one batch', :request_store do
expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
end
it 'gets commit messages' do
expect(subject).to contain_exactly(
"Added contributing guide\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n",
"Add submodule\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n"
)
end
context 'when Gitaly commit_messages feature is disabled', :disable_gitaly do
it_behaves_like 'getting commit messages'
it 'gets messages in one batch', :request_store do
expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
end
end
......
......@@ -3,7 +3,7 @@ require "spec_helper"
describe Gitlab::Git::Tag, :seed_helper do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
shared_examples 'Gitlab::Git::Repository#tags' do
describe '#tags' do
describe 'first tag' do
let(:tag) { repository.tags.first }
......@@ -25,14 +25,6 @@ describe Gitlab::Git::Tag, :seed_helper do
it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) }
end
context 'when Gitaly tags feature is enabled' do
it_behaves_like 'Gitlab::Git::Repository#tags'
end
context 'when Gitaly tags feature is disabled', :skip_gitaly_mock do
it_behaves_like 'Gitlab::Git::Repository#tags'
end
describe '.get_message' do
let(:tag_ids) { %w[f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8 8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b] }
......@@ -40,23 +32,13 @@ describe Gitlab::Git::Tag, :seed_helper do
tag_ids.map { |id| described_class.get_message(repository, id) }
end
shared_examples 'getting tag messages' do
it 'gets tag messages' do
expect(subject[0]).to eq("Release\n")
expect(subject[1]).to eq("Version 1.1.0\n")
end
end
context 'when Gitaly tag_messages feature is enabled' do
it_behaves_like 'getting tag messages'
it 'gets messages in one batch', :request_store do
expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
end
it 'gets tag messages' do
expect(subject[0]).to eq("Release\n")
expect(subject[1]).to eq("Version 1.1.0\n")
end
context 'when Gitaly tag_messages feature is disabled', :disable_gitaly do
it_behaves_like 'getting tag messages'
it 'gets messages in one batch', :request_store do
expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
end
end
......
......@@ -80,18 +80,8 @@ describe Gitlab::Git::Tree, :seed_helper do
end
describe '#where' do
shared_examples '#where' do
it 'returns an empty array when called with an invalid ref' do
expect(described_class.where(repository, 'foobar-does-not-exist')).to eq([])
end
end
context 'with gitaly' do
it_behaves_like '#where'
end
context 'without gitaly', :skip_gitaly_mock do
it_behaves_like '#where'
it 'returns an empty array when called with an invalid ref' do
expect(described_class.where(repository, 'foobar-does-not-exist')).to eq([])
end
end
end
......@@ -2,7 +2,7 @@ require 'spec_helper'
# We stub Gitaly in `spec/support/gitaly.rb` for other tests. We don't want
# those stubs while testing the GitalyClient itself.
describe Gitlab::GitalyClient, skip_gitaly_mock: true do
describe Gitlab::GitalyClient do
describe '.stub_class' do
it 'returns the gRPC health check stub' do
expect(described_class.stub_class(:health_check)).to eq(::Grpc::Health::V1::Health::Stub)
......@@ -191,102 +191,13 @@ describe Gitlab::GitalyClient, skip_gitaly_mock: true do
let(:feature_name) { 'my_feature' }
let(:real_feature_name) { "gitaly_#{feature_name}" }
context 'when Gitaly is disabled' do
before do
allow(described_class).to receive(:enabled?).and_return(false)
end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name)).to be(false)
end
end
context 'when the feature status is DISABLED' do
let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::DISABLED }
it 'returns false' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
end
end
context 'when the feature_status is OPT_IN' do
let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::OPT_IN }
context "when the feature flag hasn't been set" do
it 'returns false' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
end
end
context "when the feature flag is set to disable" do
before do
Feature.get(real_feature_name).disable
end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
end
end
context "when the feature flag is set to enable" do
before do
Feature.get(real_feature_name).enable
end
it 'returns true' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
end
end
context "when the feature flag is set to a percentage of time" do
before do
Feature.get(real_feature_name).enable_percentage_of_time(70)
end
it 'bases the result on pseudo-random numbers' do
expect(Random).to receive(:rand).and_return(0.3)
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
expect(Random).to receive(:rand).and_return(0.8)
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
end
end
context "when a feature is not persisted" do
it 'returns false when opt_into_all_features is off' do
allow(Feature).to receive(:persisted?).and_return(false)
allow(described_class).to receive(:opt_into_all_features?).and_return(false)
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
end
it 'returns true when the override is on' do
allow(Feature).to receive(:persisted?).and_return(false)
allow(described_class).to receive(:opt_into_all_features?).and_return(true)
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
end
end
before do
allow(Feature).to receive(:enabled?).and_return(false)
end
context 'when the feature_status is OPT_OUT' do
let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::OPT_OUT }
context "when the feature flag hasn't been set" do
it 'returns true' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
end
end
context "when the feature flag is set to disable" do
before do
Feature.get(real_feature_name).disable
end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
end
end
it 'returns false' do
expect(Feature).to receive(:enabled?).with(real_feature_name)
expect(described_class.feature_enabled?(feature_name)).to be(false)
end
end
......@@ -305,4 +216,29 @@ describe Gitlab::GitalyClient, skip_gitaly_mock: true do
end
end
end
describe 'Peek Performance bar details' do
let(:gitaly_server) { Gitaly::Server.all.first }
before do
Gitlab::SafeRequestStore[:peek_enabled] = true
end
context 'when the request store is active', :request_store do
it 'records call details if a RPC is called' do
gitaly_server.server_version
expect(described_class.list_call_details).not_to be_empty
expect(described_class.list_call_details.size).to be(1)
end
end
context 'when no request store is active' do
it 'records nothing' do
gitaly_server.server_version
expect(described_class.list_call_details).to be_empty
end
end
end
end
......@@ -30,48 +30,38 @@ describe MergeRequest do
end
describe '#squash_in_progress?' do
shared_examples 'checking whether a squash is in progress' do
let(:repo_path) do
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
subject.source_project.repository.path
end
end
let(:squash_path) { File.join(repo_path, "gitlab-worktree", "squash-#{subject.id}") }
before do
system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} worktree add --detach #{squash_path} master))
end
it 'returns true when there is a current squash directory' do
expect(subject.squash_in_progress?).to be_truthy
let(:repo_path) do
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
subject.source_project.repository.path
end
end
let(:squash_path) { File.join(repo_path, "gitlab-worktree", "squash-#{subject.id}") }
it 'returns false when there is no squash directory' do
FileUtils.rm_rf(squash_path)
before do
system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} worktree add --detach #{squash_path} master))
end
expect(subject.squash_in_progress?).to be_falsey
end
it 'returns true when there is a current squash directory' do
expect(subject.squash_in_progress?).to be_truthy
end
it 'returns false when the squash directory has expired' do
time = 20.minutes.ago.to_time
File.utime(time, time, squash_path)
it 'returns false when there is no squash directory' do
FileUtils.rm_rf(squash_path)
expect(subject.squash_in_progress?).to be_falsey
end
expect(subject.squash_in_progress?).to be_falsey
end
it 'returns false when the source project has been removed' do
allow(subject).to receive(:source_project).and_return(nil)
it 'returns false when the squash directory has expired' do
time = 20.minutes.ago.to_time
File.utime(time, time, squash_path)
expect(subject.squash_in_progress?).to be_falsey
end
expect(subject.squash_in_progress?).to be_falsey
end
context 'when Gitaly squash_in_progress is enabled' do
it_behaves_like 'checking whether a squash is in progress'
end
it 'returns false when the source project has been removed' do
allow(subject).to receive(:source_project).and_return(nil)
context 'when Gitaly squash_in_progress is disabled', :disable_gitaly do
it_behaves_like 'checking whether a squash is in progress'
expect(subject.squash_in_progress?).to be_falsey
end
end
......@@ -3016,14 +3006,6 @@ describe MergeRequest do
expect(subject.rebase_in_progress?).to be_falsey
end
end
context 'when Gitaly rebase_in_progress is enabled' do
it_behaves_like 'checking whether a rebase is in progress'
end
context 'when Gitaly rebase_in_progress is enabled', :disable_gitaly do
it_behaves_like 'checking whether a rebase is in progress'
end
end
describe '#allow_collaboration' do
......
......@@ -138,63 +138,53 @@ describe ProjectWiki do
end
describe "#find_page" do
shared_examples 'finding a wiki page' do
before do
create_page("index page", "This is an awesome Gollum Wiki")
end
after do
subject.pages.each { |page| destroy_page(page.page) }
end
before do
create_page("index page", "This is an awesome Gollum Wiki")
end
it "returns the latest version of the page if it exists" do
page = subject.find_page("index page")
expect(page.title).to eq("index page")
end
after do
subject.pages.each { |page| destroy_page(page.page) }
end
it "returns nil if the page does not exist" do
expect(subject.find_page("non-existent")).to eq(nil)
end
it "returns the latest version of the page if it exists" do
page = subject.find_page("index page")
expect(page.title).to eq("index page")
end
it "can find a page by slug" do
page = subject.find_page("index-page")
expect(page.title).to eq("index page")
end
it "returns nil if the page does not exist" do
expect(subject.find_page("non-existent")).to eq(nil)
end
it "returns a WikiPage instance" do
page = subject.find_page("index page")
expect(page).to be_a WikiPage
end
it "can find a page by slug" do
page = subject.find_page("index-page")
expect(page.title).to eq("index page")
end
context 'pages with multibyte-character title' do
before do
create_page("autre pagé", "C'est un génial Gollum Wiki")
end
it "returns a WikiPage instance" do
page = subject.find_page("index page")
expect(page).to be_a WikiPage
end
it "can find a page by slug" do
page = subject.find_page("autre pagé")
expect(page.title).to eq("autre pagé")
end
context 'pages with multibyte-character title' do
before do
create_page("autre pagé", "C'est un génial Gollum Wiki")
end
context 'pages with invalidly-encoded content' do
before do
create_page("encoding is fun", "f\xFCr".b)
end
it "can find the page" do
page = subject.find_page("encoding is fun")
expect(page.content).to eq("fr")
end
it "can find a page by slug" do
page = subject.find_page("autre pagé")
expect(page.title).to eq("autre pagé")
end
end
context 'when Gitaly wiki_find_page is enabled' do
it_behaves_like 'finding a wiki page'
end
context 'pages with invalidly-encoded content' do
before do
create_page("encoding is fun", "f\xFCr".b)
end
context 'when Gitaly wiki_find_page is disabled', :skip_gitaly_mock do
it_behaves_like 'finding a wiki page'
it "can find the page" do
page = subject.find_page("encoding is fun")
expect(page.content).to eq("fr")
end
end
end
......@@ -215,100 +205,80 @@ describe ProjectWiki do
end
describe '#find_file' do
shared_examples 'finding a wiki file' do
let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) }
before do
subject.wiki # Make sure the wiki repo exists
repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
subject.repository.path_to_repo
end
BareRepoOperations.new(repo_path).commit_file(image, 'image.png')
end
let(:image) { File.open(Rails.root.join('spec', 'fixtures', 'big-image.png')) }
it 'returns the latest version of the file if it exists' do
file = subject.find_file('image.png')
expect(file.mime_type).to eq('image/png')
end
before do
subject.wiki # Make sure the wiki repo exists
it 'returns nil if the page does not exist' do
expect(subject.find_file('non-existent')).to eq(nil)
repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
subject.repository.path_to_repo
end
it 'returns a Gitlab::Git::WikiFile instance' do
file = subject.find_file('image.png')
expect(file).to be_a Gitlab::Git::WikiFile
end
BareRepoOperations.new(repo_path).commit_file(image, 'image.png')
end
it 'returns the whole file' do
file = subject.find_file('image.png')
image.rewind
it 'returns the latest version of the file if it exists' do
file = subject.find_file('image.png')
expect(file.mime_type).to eq('image/png')
end
expect(file.raw_data.b).to eq(image.read.b)
end
it 'returns nil if the page does not exist' do
expect(subject.find_file('non-existent')).to eq(nil)
end
context 'when Gitaly wiki_find_file is enabled' do
it_behaves_like 'finding a wiki file'
it 'returns a Gitlab::Git::WikiFile instance' do
file = subject.find_file('image.png')
expect(file).to be_a Gitlab::Git::WikiFile
end
context 'when Gitaly wiki_find_file is disabled', :skip_gitaly_mock do
it_behaves_like 'finding a wiki file'
it 'returns the whole file' do
file = subject.find_file('image.png')
image.rewind
expect(file.raw_data.b).to eq(image.read.b)
end
end
describe "#create_page" do
shared_examples 'creating a wiki page' do
after do
destroy_page(subject.pages.first.page)
end
it "creates a new wiki page" do
expect(subject.create_page("test page", "this is content")).not_to eq(false)
expect(subject.pages.count).to eq(1)
end
it "returns false when a duplicate page exists" do
subject.create_page("test page", "content")
expect(subject.create_page("test page", "content")).to eq(false)
end
it "stores an error message when a duplicate page exists" do
2.times { subject.create_page("test page", "content") }
expect(subject.error_message).to match(/Duplicate page:/)
end
after do
destroy_page(subject.pages.first.page)
end
it "sets the correct commit message" do
subject.create_page("test page", "some content", :markdown, "commit message")
expect(subject.pages.first.page.version.message).to eq("commit message")
end
it "creates a new wiki page" do
expect(subject.create_page("test page", "this is content")).not_to eq(false)
expect(subject.pages.count).to eq(1)
end
it 'sets the correct commit email' do
subject.create_page('test page', 'content')
it "returns false when a duplicate page exists" do
subject.create_page("test page", "content")
expect(subject.create_page("test page", "content")).to eq(false)
end
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
it "stores an error message when a duplicate page exists" do
2.times { subject.create_page("test page", "content") }
expect(subject.error_message).to match(/Duplicate page:/)
end
it 'updates project activity' do
subject.create_page('Test Page', 'This is content')
it "sets the correct commit message" do
subject.create_page("test page", "some content", :markdown, "commit message")
expect(subject.pages.first.page.version.message).to eq("commit message")
end
project.reload
it 'sets the correct commit email' do
subject.create_page('test page', 'content')
expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
context 'when Gitaly wiki_write_page is enabled' do
it_behaves_like 'creating a wiki page'
end
it 'updates project activity' do
subject.create_page('Test Page', 'This is content')
context 'when Gitaly wiki_write_page is disabled', :skip_gitaly_mock do
it_behaves_like 'creating a wiki page'
project.reload
expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
end
......@@ -359,41 +329,31 @@ describe ProjectWiki do
end
describe "#delete_page" do
shared_examples 'deleting a wiki page' do
before do
create_page("index", "some content")
@page = subject.wiki.page(title: "index")
end
it "deletes the page" do
subject.delete_page(@page)
expect(subject.pages.count).to eq(0)
end
it 'sets the correct commit email' do
subject.delete_page(@page)
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
before do
create_page("index", "some content")
@page = subject.wiki.page(title: "index")
end
it 'updates project activity' do
subject.delete_page(@page)
it "deletes the page" do
subject.delete_page(@page)
expect(subject.pages.count).to eq(0)
end
project.reload
it 'sets the correct commit email' do
subject.delete_page(@page)
expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
expect(user.commit_email).not_to eq(user.email)
expect(commit.author_email).to eq(user.commit_email)
expect(commit.committer_email).to eq(user.commit_email)
end
context 'when Gitaly wiki_delete_page is enabled' do
it_behaves_like 'deleting a wiki page'
end
it 'updates project activity' do
subject.delete_page(@page)
project.reload
context 'when Gitaly wiki_delete_page is disabled', :skip_gitaly_mock do
it_behaves_like 'deleting a wiki page'
expect(project.last_activity_at).to be_within(1.minute).of(Time.now)
expect(project.last_repository_updated_at).to be_within(1.minute).of(Time.now)
end
end
......
......@@ -38,49 +38,29 @@ describe Repository do
end
describe '#branch_names_contains' do
shared_examples '#branch_names_contains' do
set(:project) { create(:project, :repository) }
let(:repository) { project.repository }
set(:project) { create(:project, :repository) }
let(:repository) { project.repository }
subject { repository.branch_names_contains(sample_commit.id) }
subject { repository.branch_names_contains(sample_commit.id) }
it { is_expected.to include('master') }
it { is_expected.not_to include('feature') }
it { is_expected.not_to include('fix') }
it { is_expected.to include('master') }
it { is_expected.not_to include('feature') }
it { is_expected.not_to include('fix') }
describe 'when storage is broken', :broken_storage do
it 'should raise a storage error' do
expect_to_raise_storage_error do
broken_repository.branch_names_contains(sample_commit.id)
end
describe 'when storage is broken', :broken_storage do
it 'should raise a storage error' do
expect_to_raise_storage_error do
broken_repository.branch_names_contains(sample_commit.id)
end
end
end
context 'when gitaly is enabled' do
it_behaves_like '#branch_names_contains'
end
context 'when gitaly is disabled', :skip_gitaly_mock do
it_behaves_like '#branch_names_contains'
end
end
describe '#tag_names_contains' do
shared_examples '#tag_names_contains' do
subject { repository.tag_names_contains(sample_commit.id) }
it { is_expected.to include('v1.1.0') }
it { is_expected.not_to include('v1.0.0') }
end
context 'when gitaly is enabled' do
it_behaves_like '#tag_names_contains'
end
subject { repository.tag_names_contains(sample_commit.id) }
context 'when gitaly is enabled', :skip_gitaly_mock do
it_behaves_like '#tag_names_contains'
end
it { is_expected.to include('v1.1.0') }
it { is_expected.not_to include('v1.0.0') }
end
describe 'tags_sorted_by' do
......@@ -238,61 +218,41 @@ describe Repository do
end
describe '#last_commit_for_path' do
shared_examples 'getting last commit for path' do
subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id }
subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id }
it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
describe 'when storage is broken', :broken_storage do
it 'should raise a storage error' do
expect_to_raise_storage_error do
broken_repository.last_commit_id_for_path(sample_commit.id, '.gitignore')
end
describe 'when storage is broken', :broken_storage do
it 'should raise a storage error' do
expect_to_raise_storage_error do
broken_repository.last_commit_id_for_path(sample_commit.id, '.gitignore')
end
end
end
context 'when Gitaly feature last_commit_for_path is enabled' do
it_behaves_like 'getting last commit for path'
end
context 'when Gitaly feature last_commit_for_path is disabled', :skip_gitaly_mock do
it_behaves_like 'getting last commit for path'
end
end
describe '#last_commit_id_for_path' do
shared_examples 'getting last commit ID for path' do
subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') }
subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') }
it "returns last commit id for a given path" do
is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8')
end
it "returns last commit id for a given path" do
is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8')
end
it "caches last commit id for a given path" do
cache = repository.send(:cache)
key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}"
it "caches last commit id for a given path" do
cache = repository.send(:cache)
key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}"
expect(cache).to receive(:fetch).with(key).and_return('c1acaa5')
is_expected.to eq('c1acaa5')
end
expect(cache).to receive(:fetch).with(key).and_return('c1acaa5')
is_expected.to eq('c1acaa5')
end
describe 'when storage is broken', :broken_storage do
it 'should raise a storage error' do
expect_to_raise_storage_error do
broken_repository.last_commit_for_path(sample_commit.id, '.gitignore').id
end
describe 'when storage is broken', :broken_storage do
it 'should raise a storage error' do
expect_to_raise_storage_error do
broken_repository.last_commit_for_path(sample_commit.id, '.gitignore').id
end
end
end
context 'when Gitaly feature last_commit_for_path is enabled' do
it_behaves_like 'getting last commit ID for path'
end
context 'when Gitaly feature last_commit_for_path is disabled', :skip_gitaly_mock do
it_behaves_like 'getting last commit ID for path'
end
end
describe '#commits' do
......@@ -374,78 +334,57 @@ describe Repository do
describe '#commits_by' do
set(:project) { create(:project, :repository) }
let(:oids) { TestEnv::BRANCH_SHA.values }
shared_examples 'batch commits fetching' do
let(:oids) { TestEnv::BRANCH_SHA.values }
subject { project.repository.commits_by(oids: oids) }
subject { project.repository.commits_by(oids: oids) }
it 'finds each commit' do
expect(subject).not_to include(nil)
expect(subject.size).to eq(oids.size)
end
it 'finds each commit' do
expect(subject).not_to include(nil)
expect(subject.size).to eq(oids.size)
end
it 'returns only Commit instances' do
expect(subject).to all( be_a(Commit) )
end
it 'returns only Commit instances' do
expect(subject).to all( be_a(Commit) )
context 'when some commits are not found ' do
let(:oids) do
['deadbeef'] + TestEnv::BRANCH_SHA.values.first(10)
end
context 'when some commits are not found ' do
let(:oids) do
['deadbeef'] + TestEnv::BRANCH_SHA.values.first(10)
end
it 'returns only found commits' do
expect(subject).not_to include(nil)
expect(subject.size).to eq(10)
end
it 'returns only found commits' do
expect(subject).not_to include(nil)
expect(subject.size).to eq(10)
end
end
context 'when no oids are passed' do
let(:oids) { [] }
context 'when no oids are passed' do
let(:oids) { [] }
it 'does not call #batch_by_oid' do
expect(Gitlab::Git::Commit).not_to receive(:batch_by_oid)
it 'does not call #batch_by_oid' do
expect(Gitlab::Git::Commit).not_to receive(:batch_by_oid)
subject
end
subject
end
end
context 'when Gitaly list_commits_by_oid is enabled' do
it_behaves_like 'batch commits fetching'
end
context 'when Gitaly list_commits_by_oid is enabled', :disable_gitaly do
it_behaves_like 'batch commits fetching'
end
end
describe '#find_commits_by_message' do
shared_examples 'finding commits by message' do
it 'returns commits with messages containing a given string' do
commit_ids = repository.find_commits_by_message('submodule').map(&:id)
expect(commit_ids).to include(
'5937ac0a7beb003549fc5fd26fc247adbce4a52e',
'6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9',
'cfe32cf61b73a0d5e9f13e774abde7ff789b1660'
)
expect(commit_ids).not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e')
end
it 'is case insensitive' do
commit_ids = repository.find_commits_by_message('SUBMODULE').map(&:id)
it 'returns commits with messages containing a given string' do
commit_ids = repository.find_commits_by_message('submodule').map(&:id)
expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
end
expect(commit_ids).to include(
'5937ac0a7beb003549fc5fd26fc247adbce4a52e',
'6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9',
'cfe32cf61b73a0d5e9f13e774abde7ff789b1660'
)
expect(commit_ids).not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e')
end
context 'when Gitaly commits_by_message feature is enabled' do
it_behaves_like 'finding commits by message'
end
it 'is case insensitive' do
commit_ids = repository.find_commits_by_message('SUBMODULE').map(&:id)
context 'when Gitaly commits_by_message feature is disabled', :skip_gitaly_mock do
it_behaves_like 'finding commits by message'
expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
end
describe 'when storage is broken', :broken_storage do
......@@ -1328,34 +1267,23 @@ describe Repository do
describe '#merge' do
let(:merge_request) { create(:merge_request, source_branch: 'feature', target_branch: 'master', source_project: project) }
let(:message) { 'Test \r\n\r\n message' }
shared_examples '#merge' do
it 'merges the code and returns the commit id' do
expect(merge_commit).to be_present
expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present
end
it 'sets the `in_progress_merge_commit_sha` flag for the given merge request' do
merge_commit_id = merge(repository, user, merge_request, message)
expect(merge_request.in_progress_merge_commit_sha).to eq(merge_commit_id)
end
it 'merges the code and returns the commit id' do
expect(merge_commit).to be_present
expect(repository.blob_at(merge_commit.id, 'files/ruby/feature.rb')).to be_present
end
it 'removes carriage returns from commit message' do
merge_commit_id = merge(repository, user, merge_request, message)
it 'sets the `in_progress_merge_commit_sha` flag for the given merge request' do
merge_commit_id = merge(repository, user, merge_request, message)
expect(repository.commit(merge_commit_id).message).to eq(message.delete("\r"))
end
expect(merge_request.in_progress_merge_commit_sha).to eq(merge_commit_id)
end
context 'with gitaly' do
it_behaves_like '#merge'
end
it 'removes carriage returns from commit message' do
merge_commit_id = merge(repository, user, merge_request, message)
context 'without gitaly', :skip_gitaly_mock do
it_behaves_like '#merge'
expect(repository.commit(merge_commit_id).message).to eq(message.delete("\r"))
end
def merge(repository, user, merge_request, message)
......@@ -1392,98 +1320,78 @@ describe Repository do
end
describe '#revert' do
shared_examples 'reverting a commit' do
let(:new_image_commit) { repository.commit('33f3729a45c02fc67d00adb1b8bca394b0e761d9') }
let(:update_image_commit) { repository.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
let(:message) { 'revert message' }
context 'when there is a conflict' do
it 'raises an error' do
expect { repository.revert(user, new_image_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
end
let(:new_image_commit) { repository.commit('33f3729a45c02fc67d00adb1b8bca394b0e761d9') }
let(:update_image_commit) { repository.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
let(:message) { 'revert message' }
context 'when commit was already reverted' do
it 'raises an error' do
repository.revert(user, update_image_commit, 'master', message)
expect { repository.revert(user, update_image_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
end
context 'when commit can be reverted' do
it 'reverts the changes' do
expect(repository.revert(user, update_image_commit, 'master', message)).to be_truthy
end
context 'when there is a conflict' do
it 'raises an error' do
expect { repository.revert(user, new_image_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
end
context 'reverting a merge commit' do
it 'reverts the changes' do
merge_commit
expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).to be_present
context 'when commit was already reverted' do
it 'raises an error' do
repository.revert(user, update_image_commit, 'master', message)
repository.revert(user, merge_commit, 'master', message)
expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).not_to be_present
end
expect { repository.revert(user, update_image_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
end
context 'when Gitaly revert feature is enabled' do
it_behaves_like 'reverting a commit'
context 'when commit can be reverted' do
it 'reverts the changes' do
expect(repository.revert(user, update_image_commit, 'master', message)).to be_truthy
end
end
context 'when Gitaly revert feature is disabled', :disable_gitaly do
it_behaves_like 'reverting a commit'
context 'reverting a merge commit' do
it 'reverts the changes' do
merge_commit
expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).to be_present
repository.revert(user, merge_commit, 'master', message)
expect(repository.blob_at_branch('master', 'files/ruby/feature.rb')).not_to be_present
end
end
end
describe '#cherry_pick' do
shared_examples 'cherry-picking a commit' do
let(:conflict_commit) { repository.commit('c642fe9b8b9f28f9225d7ea953fe14e74748d53b') }
let(:pickable_commit) { repository.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
let(:pickable_merge) { repository.commit('e56497bb5f03a90a51293fc6d516788730953899') }
let(:message) { 'cherry-pick message' }
context 'when there is a conflict' do
it 'raises an error' do
expect { repository.cherry_pick(user, conflict_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
let(:conflict_commit) { repository.commit('c642fe9b8b9f28f9225d7ea953fe14e74748d53b') }
let(:pickable_commit) { repository.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
let(:pickable_merge) { repository.commit('e56497bb5f03a90a51293fc6d516788730953899') }
let(:message) { 'cherry-pick message' }
context 'when there is a conflict' do
it 'raises an error' do
expect { repository.cherry_pick(user, conflict_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
end
context 'when commit was already cherry-picked' do
it 'raises an error' do
repository.cherry_pick(user, pickable_commit, 'master', message)
context 'when commit was already cherry-picked' do
it 'raises an error' do
repository.cherry_pick(user, pickable_commit, 'master', message)
expect { repository.cherry_pick(user, pickable_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
expect { repository.cherry_pick(user, pickable_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
end
end
context 'when commit can be cherry-picked' do
it 'cherry-picks the changes' do
expect(repository.cherry_pick(user, pickable_commit, 'master', message)).to be_truthy
end
context 'when commit can be cherry-picked' do
it 'cherry-picks the changes' do
expect(repository.cherry_pick(user, pickable_commit, 'master', message)).to be_truthy
end
end
context 'cherry-picking a merge commit' do
it 'cherry-picks the changes' do
expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).to be_nil
context 'cherry-picking a merge commit' do
it 'cherry-picks the changes' do
expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).to be_nil
cherry_pick_commit_sha = repository.cherry_pick(user, pickable_merge, 'improve/awesome', message)
cherry_pick_commit_message = project.commit(cherry_pick_commit_sha).message
cherry_pick_commit_sha = repository.cherry_pick(user, pickable_merge, 'improve/awesome', message)
cherry_pick_commit_message = project.commit(cherry_pick_commit_sha).message
expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).not_to be_nil
expect(cherry_pick_commit_message).to eq(message)
end
expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).not_to be_nil
expect(cherry_pick_commit_message).to eq(message)
end
end
context 'when Gitaly cherry_pick feature is enabled' do
it_behaves_like 'cherry-picking a commit'
end
context 'when Gitaly cherry_pick feature is disabled', :disable_gitaly do
it_behaves_like 'cherry-picking a commit'
end
end
describe '#before_delete' do
......@@ -2190,33 +2098,23 @@ describe Repository do
let(:commit) { repository.commit }
let(:ancestor) { commit.parents.first }
shared_examples '#ancestor?' do
it 'it is an ancestor' do
expect(repository.ancestor?(ancestor.id, commit.id)).to eq(true)
end
it 'it is not an ancestor' do
expect(repository.ancestor?(commit.id, ancestor.id)).to eq(false)
end
it 'returns false on nil-values' do
expect(repository.ancestor?(nil, commit.id)).to eq(false)
expect(repository.ancestor?(ancestor.id, nil)).to eq(false)
expect(repository.ancestor?(nil, nil)).to eq(false)
end
it 'it is an ancestor' do
expect(repository.ancestor?(ancestor.id, commit.id)).to eq(true)
end
it 'returns false for invalid commit IDs' do
expect(repository.ancestor?(commit.id, Gitlab::Git::BLANK_SHA)).to eq(false)
expect(repository.ancestor?( Gitlab::Git::BLANK_SHA, commit.id)).to eq(false)
end
it 'it is not an ancestor' do
expect(repository.ancestor?(commit.id, ancestor.id)).to eq(false)
end
context 'with Gitaly enabled' do
it_behaves_like('#ancestor?')
it 'returns false on nil-values' do
expect(repository.ancestor?(nil, commit.id)).to eq(false)
expect(repository.ancestor?(ancestor.id, nil)).to eq(false)
expect(repository.ancestor?(nil, nil)).to eq(false)
end
context 'with Gitaly disabled', :skip_gitaly_mock do
it_behaves_like('#ancestor?')
it 'returns false for invalid commit IDs' do
expect(repository.ancestor?(commit.id, Gitlab::Git::BLANK_SHA)).to eq(false)
expect(repository.ancestor?( Gitlab::Git::BLANK_SHA, commit.id)).to eq(false)
end
end
......
......@@ -200,180 +200,160 @@ describe WikiPage do
end
describe '#create' do
shared_examples 'create method' do
context 'with valid attributes' do
it 'raises an error if a page with the same path already exists' do
create_page('New Page', 'content')
create_page('foo/bar', 'content')
expect { create_page('New Page', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
expect { create_page('foo/bar', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
destroy_page('New Page')
destroy_page('bar', 'foo')
end
context 'with valid attributes' do
it 'raises an error if a page with the same path already exists' do
create_page('New Page', 'content')
create_page('foo/bar', 'content')
expect { create_page('New Page', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
expect { create_page('foo/bar', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
it 'if the title is preceded by a / it is removed' do
create_page('/New Page', 'content')
destroy_page('New Page')
destroy_page('bar', 'foo')
end
expect(wiki.find_page('New Page')).not_to be_nil
it 'if the title is preceded by a / it is removed' do
create_page('/New Page', 'content')
destroy_page('New Page')
end
expect(wiki.find_page('New Page')).not_to be_nil
destroy_page('New Page')
end
end
end
context 'when Gitaly is enabled' do
it_behaves_like 'create method'
describe "#update" do
before do
create_page("Update", "content")
@page = wiki.find_page("Update")
end
context 'when Gitaly is disabled', :skip_gitaly_mock do
it_behaves_like 'create method'
after do
destroy_page(@page.title, @page.directory)
end
end
describe "#update" do
shared_examples 'update method' do
before do
create_page("Update", "content")
context "with valid attributes" do
it "updates the content of the page" do
new_content = "new content"
@page.update(content: new_content)
@page = wiki.find_page("Update")
end
after do
destroy_page(@page.title, @page.directory)
expect(@page.content).to eq("new content")
end
context "with valid attributes" do
it "updates the content of the page" do
new_content = "new content"
@page.update(content: new_content)
@page = wiki.find_page("Update")
expect(@page.content).to eq("new content")
end
it "updates the title of the page" do
new_title = "Index v.1.2.4"
it "updates the title of the page" do
new_title = "Index v.1.2.4"
@page.update(title: new_title)
@page = wiki.find_page(new_title)
@page.update(title: new_title)
@page = wiki.find_page(new_title)
expect(@page.title).to eq(new_title)
end
expect(@page.title).to eq(new_title)
end
it "returns true" do
expect(@page.update(content: "more content")).to be_truthy
end
it "returns true" do
expect(@page.update(content: "more content")).to be_truthy
end
end
context 'with same last commit sha' do
it 'returns true' do
expect(@page.update(content: 'more content', last_commit_sha: @page.last_commit_sha)).to be_truthy
end
context 'with same last commit sha' do
it 'returns true' do
expect(@page.update(content: 'more content', last_commit_sha: @page.last_commit_sha)).to be_truthy
end
end
context 'with different last commit sha' do
it 'raises exception' do
expect { @page.update(content: 'more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError)
end
context 'with different last commit sha' do
it 'raises exception' do
expect { @page.update(content: 'more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError)
end
end
context 'when renaming a page' do
it 'raises an error if the page already exists' do
create_page('Existing Page', 'content')
context 'when renaming a page' do
it 'raises an error if the page already exists' do
create_page('Existing Page', 'content')
expect { @page.update(title: 'Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
expect(@page.title).to eq 'Update'
expect(@page.content).to eq 'new_content'
expect { @page.update(title: 'Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
expect(@page.title).to eq 'Update'
expect(@page.content).to eq 'new_content'
destroy_page('Existing Page')
end
destroy_page('Existing Page')
end
it 'updates the content and rename the file' do
new_title = 'Renamed Page'
new_content = 'updated content'
it 'updates the content and rename the file' do
new_title = 'Renamed Page'
new_content = 'updated content'
expect(@page.update(title: new_title, content: new_content)).to be_truthy
expect(@page.update(title: new_title, content: new_content)).to be_truthy
@page = wiki.find_page(new_title)
@page = wiki.find_page(new_title)
expect(@page).not_to be_nil
expect(@page.content).to eq new_content
end
expect(@page).not_to be_nil
expect(@page.content).to eq new_content
end
end
context 'when moving a page' do
it 'raises an error if the page already exists' do
create_page('foo/Existing Page', 'content')
expect { @page.update(title: 'foo/Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
expect(@page.title).to eq 'Update'
expect(@page.content).to eq 'new_content'
context 'when moving a page' do
it 'raises an error if the page already exists' do
create_page('foo/Existing Page', 'content')
destroy_page('Existing Page', 'foo')
end
expect { @page.update(title: 'foo/Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
expect(@page.title).to eq 'Update'
expect(@page.content).to eq 'new_content'
it 'updates the content and moves the file' do
new_title = 'foo/Other Page'
new_content = 'new_content'
expect(@page.update(title: new_title, content: new_content)).to be_truthy
destroy_page('Existing Page', 'foo')
end
page = wiki.find_page(new_title)
it 'updates the content and moves the file' do
new_title = 'foo/Other Page'
new_content = 'new_content'
expect(page).not_to be_nil
expect(page.content).to eq new_content
end
expect(@page.update(title: new_title, content: new_content)).to be_truthy
context 'in subdir' do
before do
create_page('foo/Existing Page', 'content')
@page = wiki.find_page('foo/Existing Page')
end
page = wiki.find_page(new_title)
it 'moves the page to the root folder if the title is preceded by /', :skip_gitaly_mock do
expect(@page.slug).to eq 'foo/Existing-Page'
expect(@page.update(title: '/Existing Page', content: 'new_content')).to be_truthy
expect(@page.slug).to eq 'Existing-Page'
end
expect(page).not_to be_nil
expect(page.content).to eq new_content
end
it 'does nothing if it has the same title' do
original_path = @page.slug
context 'in subdir' do
before do
create_page('foo/Existing Page', 'content')
@page = wiki.find_page('foo/Existing Page')
end
expect(@page.update(title: 'Existing Page', content: 'new_content')).to be_truthy
expect(@page.slug).to eq original_path
end
it 'moves the page to the root folder if the title is preceded by /' do
expect(@page.slug).to eq 'foo/Existing-Page'
expect(@page.update(title: '/Existing Page', content: 'new_content')).to be_truthy
expect(@page.slug).to eq 'Existing-Page'
end
context 'in root dir' do
it 'does nothing if the title is preceded by /' do
original_path = @page.slug
it 'does nothing if it has the same title' do
original_path = @page.slug
expect(@page.update(title: '/Update', content: 'new_content')).to be_truthy
expect(@page.slug).to eq original_path
end
expect(@page.update(title: 'Existing Page', content: 'new_content')).to be_truthy
expect(@page.slug).to eq original_path
end
end
context "with invalid attributes" do
it 'aborts update if title blank' do
expect(@page.update(title: '', content: 'new_content')).to be_falsey
expect(@page.content).to eq 'new_content'
context 'in root dir' do
it 'does nothing if the title is preceded by /' do
original_path = @page.slug
page = wiki.find_page('Update')
expect(page.content).to eq 'content'
@page.title = 'Update'
expect(@page.update(title: '/Update', content: 'new_content')).to be_truthy
expect(@page.slug).to eq original_path
end
end
end
context 'when Gitaly is enabled' do
it_behaves_like 'update method'
end
context "with invalid attributes" do
it 'aborts update if title blank' do
expect(@page.update(title: '', content: 'new_content')).to be_falsey
expect(@page.content).to eq 'new_content'
context 'when Gitaly is disabled', :skip_gitaly_mock do
it_behaves_like 'update method'
page = wiki.find_page('Update')
expect(page.content).to eq 'content'
@page.title = 'Update'
end
end
end
......@@ -394,34 +374,24 @@ describe WikiPage do
end
describe "#versions" do
shared_examples 'wiki page versions' do
let(:page) { wiki.find_page("Update") }
let(:page) { wiki.find_page("Update") }
before do
create_page("Update", "content")
end
after do
destroy_page("Update")
end
it "returns an array of all commits for the page" do
3.times { |i| page.update(content: "content #{i}") }
expect(page.versions.count).to eq(4)
end
before do
create_page("Update", "content")
end
it 'returns instances of WikiPageVersion' do
expect(page.versions).to all( be_a(Gitlab::Git::WikiPageVersion) )
end
after do
destroy_page("Update")
end
context 'when Gitaly is enabled' do
it_behaves_like 'wiki page versions'
it "returns an array of all commits for the page" do
3.times { |i| page.update(content: "content #{i}") }
expect(page.versions.count).to eq(4)
end
context 'when Gitaly is disabled', :disable_gitaly do
it_behaves_like 'wiki page versions'
it 'returns instances of WikiPageVersion' do
expect(page.versions).to all( be_a(Gitlab::Git::WikiPageVersion) )
end
end
......@@ -555,23 +525,13 @@ describe WikiPage do
end
describe '#formatted_content' do
shared_examples 'fetching page formatted content' do
it 'returns processed content of the page' do
subject.create({ title: "RDoc", content: "*bold*", format: "rdoc" })
page = wiki.find_page('RDoc')
expect(page.formatted_content).to eq("\n<p><strong>bold</strong></p>\n")
it 'returns processed content of the page' do
subject.create({ title: "RDoc", content: "*bold*", format: "rdoc" })
page = wiki.find_page('RDoc')
destroy_page('RDoc')
end
end
context 'when Gitaly wiki_page_formatted_data is enabled' do
it_behaves_like 'fetching page formatted content'
end
expect(page.formatted_content).to eq("\n<p><strong>bold</strong></p>\n")
context 'when Gitaly wiki_page_formatted_data is disabled', :disable_gitaly do
it_behaves_like 'fetching page formatted content'
destroy_page('RDoc')
end
end
......
# frozen_string_literal: true
require 'spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
require_relative '../../../rubocop/cop/safe_params'
describe RuboCop::Cop::SafeParams do
include CopHelper
subject(:cop) { described_class.new }
it 'flags the params as an argument of url_for' do
expect_offense(<<~SOURCE)
url_for(params)
^^^^^^^^^^^^^^^ Use `safe_params` instead of `params` in url_for.
SOURCE
end
it 'flags the merged params as an argument of url_for' do
expect_offense(<<~SOURCE)
url_for(params.merge(additional_params))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `safe_params` instead of `params` in url_for.
SOURCE
end
it 'flags the merged params arg as an argument of url_for' do
expect_offense(<<~SOURCE)
url_for(something.merge(additional).merge(params))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `safe_params` instead of `params` in url_for.
SOURCE
end
it 'does not flag other argument of url_for' do
expect_no_offenses(<<~SOURCE)
url_for(something)
SOURCE
end
end
RSpec.configure do |config|
config.before(:each) do |example|
if example.metadata[:disable_gitaly]
# Use 'and_wrap_original' to make sure the arguments are valid
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original { |m, *args| m.call(*args) && false }
else
next if example.metadata[:skip_gitaly_mock]
# Use 'and_wrap_original' to make sure the arguments are valid
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original do |m, *args|
m.call(*args)
!Gitlab::GitalyClient.explicit_opt_in_required.include?(args.first)
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