Commit 135a02cf authored by Phil Hughes's avatar Phil Hughes

Merge branch 'master' into ph-axios-2

parents b1c8b3aa 5b73e0eb
......@@ -704,7 +704,9 @@ Style/RedundantSelf:
# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral:
Enabled: false
Enabled: true
EnforcedStyle: mixed
AllowInnerSlashes: false
# Offense count: 36
# Cop supports --auto-correct.
......
......@@ -340,7 +340,7 @@ GEM
mime-types (~> 3.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
google-protobuf (3.5.1.1-universal-darwin)
google-protobuf (3.5.1.1)
googleapis-common-protos-types (1.0.1)
google-protobuf (~> 3.0)
googleauth (0.5.3)
......@@ -369,7 +369,7 @@ GEM
rake
grape_logging (1.7.0)
grape
grpc (1.8.3-universal-darwin)
grpc (1.8.3)
google-protobuf (~> 3.1)
googleapis-common-protos-types (~> 1.0.0)
googleauth (>= 0.5.1, < 0.7)
......
/* eslint-disable class-methods-use-this */
import _ from 'underscore';
import Cookies from 'js-cookie';
import { s__ } from './locale';
import { __ } from './locale';
import { isInIssuePage, updateTooltipTitle } from './lib/utils/common_utils';
import flash from './flash';
import axios from './lib/utils/axios_utils';
......@@ -451,7 +451,7 @@ class AwardsHandler {
callback();
}
})
.catch(() => flash(s__('Something went wrong on our end.')));
.catch(() => flash(__('Something went wrong on our end.')));
}
}
......
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, consistent-return, one-var, one-var-declaration-per-line, no-cond-assign, max-len, object-shorthand, no-param-reassign, comma-dangle, prefer-template, no-unused-vars, no-return-assign */
import fuzzaldrinPlus from 'fuzzaldrin-plus';
import axios from '~/lib/utils/axios_utils';
import flash from '~/flash';
import { __ } from '~/locale';
// highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> )
const highlighter = function(element, text, matches) {
......@@ -72,19 +75,14 @@ export default class ProjectFindFile {
// files pathes load
load(url) {
return $.ajax({
url: url,
method: "get",
dataType: "json",
success: (function(_this) {
return function(data) {
_this.element.find(".loading").hide();
_this.filePaths = data;
_this.findFile();
return _this.element.find(".files-slider tr.tree-item").eq(0).addClass("selected").focus();
};
})(this)
});
axios.get(url)
.then(({ data }) => {
this.element.find('.loading').hide();
this.filePaths = data;
this.findFile();
this.element.find('.files-slider tr.tree-item').eq(0).addClass('selected').focus();
})
.catch(() => flash(__('An error occurred while loading filenames')));
}
// render result
......
......@@ -7,7 +7,12 @@
//
// <code class="js-render-math"></div>
//
// Only load once
import { __ } from './locale';
import axios from './lib/utils/axios_utils';
import flash from './flash';
// Only load once
let katexLoaded = false;
// Loop over all math elements and render math
......@@ -33,19 +38,26 @@ export default function renderMath($els) {
if (katexLoaded) {
renderWithKaTeX($els);
} else {
$.get(gon.katex_css_url, () => {
axios.get(gon.katex_css_url)
.then(() => {
const css = $('<link>', {
rel: 'stylesheet',
type: 'text/css',
href: gon.katex_css_url,
});
css.appendTo('head');
// Load KaTeX js
$.getScript(gon.katex_js_url, () => {
})
.then(() => axios.get(gon.katex_js_url, {
responseType: 'text',
}))
.then(({ data }) => {
// Add katex js to our document
$.globalEval(data);
})
.then(() => {
katexLoaded = true;
renderWithKaTeX($els); // Run KaTeX
});
});
})
.catch(() => flash(__('An error occurred while rendering KaTeX')));
}
}
import _ from 'underscore';
import { scaleLinear, scaleThreshold } from 'd3-scale';
import { select } from 'd3-selection';
import { getDayName, getDayDifference } from '../lib/utils/datetime_utility';
import { getDayName, getDayDifference } from '~/lib/utils/datetime_utility';
import axios from '~/lib/utils/axios_utils';
import flash from '~/flash';
import { __ } from '~/locale';
const d3 = { select, scaleLinear, scaleThreshold };
......@@ -221,14 +224,16 @@ export default class ActivityCalendar {
this.currentSelectedDate.getDate(),
].join('-');
$.ajax({
url: this.calendarActivitiesPath,
data: { date },
cache: false,
dataType: 'html',
beforeSend: () => $('.user-calendar-activities').html(LOADING_HTML),
success: data => $('.user-calendar-activities').html(data),
});
$('.user-calendar-activities').html(LOADING_HTML);
axios.get(this.calendarActivitiesPath, {
params: {
date,
},
responseType: 'text',
})
.then(({ data }) => $('.user-calendar-activities').html(data))
.catch(() => flash(__('An error occurred while retrieving calendar activity')));
} else {
this.currentSelectedDate = '';
$('.user-calendar-activities').html('');
......
export default {
name: 'MRWidgetRelatedLinks',
props: {
relatedLinks: { type: Object, required: true },
state: { type: String, required: false },
},
computed: {
hasLinks() {
const { closing, mentioned, assignToMe } = this.relatedLinks;
return closing || mentioned || assignToMe;
},
closesText() {
if (this.state === 'merged') {
return 'Closed';
}
if (this.state === 'closed') {
return 'Did not close';
}
return 'Closes';
},
},
template: `
<section
v-if="hasLinks"
class="mr-info-list mr-links">
<p v-if="relatedLinks.closing">
{{closesText}} <span v-html="relatedLinks.closing"></span>
</p>
<p v-if="relatedLinks.mentioned">
Mentions <span v-html="relatedLinks.mentioned"></span>
</p>
<p v-if="relatedLinks.assignToMe">
<span v-html="relatedLinks.assignToMe"></span>
</p>
</section>
`,
};
<script>
import { s__ } from '~/locale';
export default {
name: 'MRWidgetRelatedLinks',
props: {
relatedLinks: {
type: Object,
required: true,
default: () => ({}),
},
state: {
type: String,
required: false,
default: '',
},
},
computed: {
closesText() {
if (this.state === 'merged') {
return s__('mrWidget|Closed');
}
if (this.state === 'closed') {
return s__('mrWidget|Did not close');
}
return s__('mrWidget|Closes');
},
},
};
</script>
<template>
<section class="mr-info-list mr-links">
<p v-if="relatedLinks.closing">
{{ closesText }} <span v-html="relatedLinks.closing"></span>
</p>
<p v-if="relatedLinks.mentioned">
{{ s__("mrWidget|Mentions") }} <span v-html="relatedLinks.mentioned"></span>
</p>
<p v-if="relatedLinks.assignToMe">
<span v-html="relatedLinks.assignToMe"></span>
</p>
</section>
</template>
......@@ -15,7 +15,7 @@ export { default as WidgetHeader } from './components/mr_widget_header';
export { default as WidgetMergeHelp } from './components/mr_widget_merge_help';
export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue';
export { default as WidgetDeployment } from './components/mr_widget_deployment';
export { default as WidgetRelatedLinks } from './components/mr_widget_related_links';
export { default as WidgetRelatedLinks } from './components/mr_widget_related_links.vue';
export { default as MergedState } from './components/states/mr_widget_merged.vue';
export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue';
export { default as ClosedState } from './components/states/mr_widget_closed.vue';
......
......@@ -257,7 +257,8 @@ export default {
<mr-widget-related-links
v-if="shouldRenderRelatedLinks"
:state="mr.state"
:related-links="mr.relatedLinks" />
:related-links="mr.relatedLinks"
/>
</div>
<div
class="mr-widget-footer"
......
......@@ -94,6 +94,7 @@ module IssuableCollections
@filter_params[:project_id] = @project.id
elsif @group
@filter_params[:group_id] = @group.id
@filter_params[:include_subgroups] = true
else
# TODO: this filter ignore issues/mr created in public or
# internal repos where you are not a member. Enable this filter
......
......@@ -118,10 +118,10 @@ class GroupsController < Groups::ApplicationController
end
def group_params
params.require(:group).permit(group_params_ce)
params.require(:group).permit(group_params_attributes)
end
def group_params_ce
def group_params_attributes
[
:avatar,
:description,
......
......@@ -5,7 +5,7 @@ class HelpController < ApplicationController
# Taken from Jekyll
# https://github.com/jekyll/jekyll/blob/3.5-stable/lib/jekyll/document.rb#L13
YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m
YAML_FRONT_MATTER_REGEXP = /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
def index
# Remove YAML frontmatter so that it doesn't look weird
......
......@@ -403,6 +403,6 @@ class ProjectsController < Projects::ApplicationController
# to
# localhost/group/project
#
redirect_to request.original_url.sub(/\.git\/?\Z/, '') if params[:format] == 'git'
redirect_to request.original_url.sub(%r{\.git/?\Z}, '') if params[:format] == 'git'
end
end
......@@ -87,9 +87,18 @@ class GroupProjectsFinder < ProjectsFinder
options.fetch(:only_shared, false)
end
# subgroups are supported only for owned projects not for shared
def include_subgroups?
options.fetch(:include_subgroups, false)
end
def owned_projects
if include_subgroups?
Project.where(namespace_id: group.self_and_descendants.select(:id))
else
group.projects
end
end
def shared_projects
group.shared_projects
......
......@@ -43,6 +43,7 @@ class IssuableFinder
search
sort
state
include_subgroups
].freeze
ARRAY_PARAMS = { label_name: [], iids: [], assignee_username: [] }.freeze
......@@ -148,7 +149,8 @@ class IssuableFinder
if current_user && params[:authorized_only].presence && !current_user_related?
current_user.authorized_projects
elsif group
GroupProjectsFinder.new(group: group, current_user: current_user).execute
finder_options = { include_subgroups: params[:include_subgroups], only_owned: true }
GroupProjectsFinder.new(group: group, current_user: current_user, options: finder_options).execute
else
ProjectsFinder.new(current_user: current_user, project_ids_relation: item_project_ids(items)).execute
end
......
module SidekiqHelper
SIDEKIQ_PS_REGEXP = /\A
SIDEKIQ_PS_REGEXP = %r{\A
(?<pid>\d+)\s+
(?<cpu>[\d\.,]+)\s+
(?<mem>[\d\.,]+)\s+
(?<state>[DIEKNRSTVWXZNLpsl\+<>\/\d]+)\s+
(?<state>[DIEKNRSTVWXZNLpsl\+<>/\d]+)\s+
(?<start>.+?)\s+
(?<command>(?:ruby\d+:\s+)?sidekiq.*\].*)
\z/x
\z}x
def parse_sidekiq_ps(line)
match = line.strip.match(SIDEKIQ_PS_REGEXP)
......
......@@ -11,7 +11,7 @@ module SubmoduleHelper
url = File.join(Gitlab.config.gitlab.url, @project.full_path)
end
if url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/
if url =~ %r{([^/:]+)/([^/]+(?:\.git)?)\Z}
namespace, project = $1, $2
gitlab_hosts = [Gitlab.config.gitlab.url,
Gitlab.config.gitlab_shell.ssh_path_prefix]
......@@ -23,7 +23,7 @@ module SubmoduleHelper
end
end
namespace.sub!(/\A\//, '')
namespace.sub!(%r{\A/}, '')
project.rstrip!
project.sub!(/\.git\z/, '')
......@@ -47,11 +47,11 @@ module SubmoduleHelper
protected
def github_dot_com_url?(url)
url =~ /github\.com[\/:][^\/]+\/[^\/]+\Z/
url =~ %r{github\.com[/:][^/]+/[^/]+\Z}
end
def gitlab_dot_com_url?(url)
url =~ /gitlab\.com[\/:][^\/]+\/[^\/]+\Z/
url =~ %r{gitlab\.com[/:][^/]+/[^/]+\Z}
end
def self_url?(url, namespace, project)
......@@ -65,7 +65,7 @@ module SubmoduleHelper
def relative_self_url?(url)
# (./)?(../repo.git) || (./)?(../../project/repo.git) )
url =~ /\A((\.\/)?(\.\.\/))(?!(\.\.)|(.*\/)).*(\.git)?\z/ || url =~ /\A((\.\/)?(\.\.\/){2})(?!(\.\.))([^\/]*)\/(?!(\.\.)|(.*\/)).*(\.git)?\z/
url =~ %r{\A((\./)?(\.\./))(?!(\.\.)|(.*/)).*(\.git)?\z} || url =~ %r{\A((\./)?(\.\./){2})(?!(\.\.))([^/]*)/(?!(\.\.)|(.*/)).*(\.git)?\z}
end
def standard_links(host, namespace, project, commit)
......
......@@ -110,7 +110,7 @@ module TreeHelper
# returns the relative path of the first subdir that doesn't have only one directory descendant
def flatten_tree(root_path, tree)
return tree.flat_path.sub(/\A#{root_path}\//, '') if tree.flat_path.present?
return tree.flat_path.sub(%r{\A#{root_path}/}, '') if tree.flat_path.present?
subtree = Gitlab::Git::Tree.where(@repository, @commit.id, tree.path)
if subtree.count == 1 && subtree.first.dir?
......
......@@ -292,7 +292,7 @@ module Ci
def repo_url
auth = "gitlab-ci-token:#{ensure_token!}@"
project.http_url_to_repo.sub(/^https?:\/\//) do |prefix|
project.http_url_to_repo.sub(%r{^https?://}) do |prefix|
prefix + auth
end
end
......
......@@ -141,7 +141,7 @@ class CommitStatus < ActiveRecord::Base
end
def group_name
name.to_s.gsub(/\d+[\s:\/\\]+\d+\s*/, '').strip
name.to_s.gsub(%r{\d+[\s:/\\]+\d+\s*}, '').strip
end
def failed_but_allowed?
......
......@@ -9,13 +9,13 @@ require 'task_list/filter'
module Taskable
COMPLETED = 'completed'.freeze
INCOMPLETE = 'incomplete'.freeze
ITEM_PATTERN = /
ITEM_PATTERN = %r{
^
\s*(?:[-+*]|(?:\d+\.)) # list prefix required - task item has to be always in a list
\s+ # whitespace prefix has to be always presented for a list item
(\[\s\]|\[[xX]\]) # checkbox
(\s.+) # followed by whitespace and some text.
/x
}x
def self.get_tasks(content)
content.to_s.scan(ITEM_PATTERN).map do |checkbox, label|
......
......@@ -115,7 +115,7 @@ class Environment < ActiveRecord::Base
def formatted_external_url
return nil unless external_url
external_url.gsub(/\A.*?:\/\//, '')
external_url.gsub(%r{\A.*?://}, '')
end
def stop_action?
......
......@@ -234,7 +234,7 @@ class Project < ActiveRecord::Base
validates :creator, presence: true, on: :create
validates :description, length: { maximum: 2000 }, allow_blank: true
validates :ci_config_path,
format: { without: /(\.{2}|\A\/)/,
format: { without: %r{(\.{2}|\A/)},
message: 'cannot include leading slash or directory traversal.' },
length: { maximum: 255 },
allow_blank: true
......@@ -1338,7 +1338,7 @@ class Project < ActiveRecord::Base
host = "#{subdomain}.#{Settings.pages.host}".downcase
# The host in URL always needs to be downcased
url = Gitlab.config.pages.url.sub(/^https?:\/\//) do |prefix|
url = Gitlab.config.pages.url.sub(%r{^https?://}) do |prefix|
"#{prefix}#{subdomain}."
end.downcase
......
......@@ -84,7 +84,7 @@ http://app.asana.com/-/account_api'
# - fix/ed/es/ing
# - close/s/d
# - closing
issue_finder = /(fix\w*|clos[ei]\w*+)?\W*(?:https:\/\/app\.asana\.com\/\d+\/\d+\/(\d+)|#(\d+))/i
issue_finder = %r{(fix\w*|clos[ei]\w*+)?\W*(?:https://app\.asana\.com/\d+/\d+/(\d+)|#(\d+))}i
message.scan(issue_finder).each do |tuple|
# tuple will be
......
......@@ -10,9 +10,9 @@ class IssueTrackerService < Service
# overriden patterns. See ReferenceRegexes::EXTERNAL_PATTERN
def self.reference_pattern(only_long: false)
if only_long
%r{(\b[A-Z][A-Z0-9_]+-)(?<issue>\d+)}
/(\b[A-Z][A-Z0-9_]+-)(?<issue>\d+)/
else
%r{(\b[A-Z][A-Z0-9_]+-|#{Issue.reference_prefix})(?<issue>\d+)}
/(\b[A-Z][A-Z0-9_]+-|#{Issue.reference_prefix})(?<issue>\d+)/
end
end
......
......@@ -19,7 +19,7 @@ class JiraService < IssueTrackerService
# {PROJECT-KEY}-{NUMBER} Examples: JIRA-1, PROJECT-1
def self.reference_pattern(only_long: true)
@reference_pattern ||= %r{(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)}
@reference_pattern ||= /(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)/
end
def initialize_properties
......
......@@ -842,13 +842,13 @@ class User < ActiveRecord::Base
end
def full_website_url
return "http://#{website_url}" if website_url !~ /\Ahttps?:\/\//
return "http://#{website_url}" if website_url !~ %r{\Ahttps?://}
website_url
end
def short_website_url
website_url.sub(/\Ahttps?:\/\//, '')
website_url.sub(%r{\Ahttps?://}, '')
end
def all_ssh_keys
......
---
title: Include subgroup issues and merge requests on the group page
merge_request:
author:
type: changed
---
title: Enable RuboCop Style/RegexpLiteral
merge_request: 16752
author: Takuya Noguchi
type: other
---
title: Update minimum git version to 2.9.5
merge_request: 16683
author:
type: other
......@@ -110,7 +110,7 @@ class Settings < Settingslogic
url = "http://#{url}" unless url.start_with?('http')
# Get rid of the path so that we don't even have to encode it
url_without_path = url.sub(%r{(https?://[^\/]+)/?.*}, '\1')
url_without_path = url.sub(%r{(https?://[^/]+)/?.*}, '\1')
URI.parse(url_without_path).host
end
......@@ -469,10 +469,10 @@ end
# repository_downloads_path value.
#
repositories_storages = Settings.repositories.storages.values
repository_downloads_path = Settings.gitlab['repository_downloads_path'].to_s.gsub(/\/$/, '')
repository_downloads_path = Settings.gitlab['repository_downloads_path'].to_s.gsub(%r{/$}, '')
repository_downloads_full_path = File.expand_path(repository_downloads_path, Settings.gitlab['user_home'])
if repository_downloads_path.blank? || repositories_storages.any? { |rs| [repository_downloads_path, repository_downloads_full_path].include?(rs['path'].gsub(/\/$/, '')) }
if repository_downloads_path.blank? || repositories_storages.any? { |rs| [repository_downloads_path, repository_downloads_full_path].include?(rs['path'].gsub(%r{/$}, '')) }
Settings.gitlab['repository_downloads_path'] = File.join(Settings.shared['path'], 'cache/archive')
end
......
......@@ -54,7 +54,7 @@ elsif Gitlab::Database.mysql?
def initialize_type_map(mapping)
super mapping
mapping.register_type(%r(timestamp)i) do |sql_type|
mapping.register_type(/timestamp/i) do |sql_type|
precision = extract_precision(sql_type)
ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlDateTimeWithTimeZone.new(precision: precision)
end
......
namespace :admin do
resources :users, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } do
resources :users, constraints: { id: %r{[a-zA-Z./0-9_\-]+} } do
resources :keys, only: [:show, :destroy]
resources :identities, except: [:show]
resources :impersonation_tokens, only: [:index, :create] do
......
......@@ -35,7 +35,7 @@ constraints(GroupUrlConstrainer.new) do
post :toggle_subscription, on: :member
end
resources :milestones, constraints: { id: /[^\/]+/ }, only: [:index, :show, :edit, :update, :new, :create] do
resources :milestones, constraints: { id: %r{[^/]+} }, only: [:index, :show, :edit, :update, :new, :create] do
member do
get :merge_requests
get :participants
......@@ -52,7 +52,7 @@ constraints(GroupUrlConstrainer.new) do
resources :uploads, only: [:create] do
collection do
get ":secret/:filename", action: :show, as: :show, constraints: { filename: /[^\/]+/ }
get ":secret/:filename", action: :show, as: :show, constraints: { filename: %r{[^/]+} }
end
end
end
......
......@@ -40,7 +40,7 @@ constraints(ProjectUrlConstrainer.new) do
#
# Templates
#
get '/templates/:template_type/:key' => 'templates#show', as: :template, constraints: { key: /[^\/]+/ }
get '/templates/:template_type/:key' => 'templates#show', as: :template, constraints: { key: %r{[^/]+} }
resource :avatar, only: [:show, :destroy]
resources :commit, only: [:show], constraints: { id: /\h{7,40}/ } do
......@@ -55,7 +55,7 @@ constraints(ProjectUrlConstrainer.new) do
end
resource :pages, only: [:show, :destroy] do
resources :domains, only: [:show, :new, :create, :destroy], controller: 'pages_domains', constraints: { id: /[^\/]+/ }
resources :domains, only: [:show, :new, :create, :destroy], controller: 'pages_domains', constraints: { id: %r{[^/]+} }
end
resources :snippets, concerns: :awardable, constraints: { id: /\d+/ } do
......@@ -65,7 +65,7 @@ constraints(ProjectUrlConstrainer.new) do
end
end
resources :services, constraints: { id: /[^\/]+/ }, only: [:index, :edit, :update] do
resources :services, constraints: { id: %r{[^/]+} }, only: [:index, :edit, :update] do
member do
put :test
end
......@@ -346,7 +346,7 @@ constraints(ProjectUrlConstrainer.new) do
end
end
resources :project_members, except: [:show, :new, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ }, concerns: :access_requestable do
resources :project_members, except: [:show, :new, :edit], constraints: { id: %r{[a-zA-Z./0-9_\-#%+]+} }, concerns: :access_requestable do
collection do
delete :leave
......@@ -379,7 +379,7 @@ constraints(ProjectUrlConstrainer.new) do
resources :uploads, only: [:create] do
collection do
get ":secret/:filename", action: :show, as: :show, constraints: { filename: /[^\/]+/ }
get ":secret/:filename", action: :show, as: :show, constraints: { filename: %r{[^/]+} }
end
end
......
......@@ -2,17 +2,17 @@ scope path: :uploads do
# Note attachments and User/Group/Project avatars
get "-/system/:model/:mounted_as/:id/:filename",
to: "uploads#show",
constraints: { model: /note|user|group|project/, mounted_as: /avatar|attachment/, filename: /[^\/]+/ }
constraints: { model: /note|user|group|project/, mounted_as: /avatar|attachment/, filename: %r{[^/]+} }
# show uploads for models, snippets (notes) available for now
get '-/system/:model/:id/:secret/:filename',
to: 'uploads#show',
constraints: { model: /personal_snippet/, id: /\d+/, filename: /[^\/]+/ }
constraints: { model: /personal_snippet/, id: /\d+/, filename: %r{[^/]+} }
# show temporary uploads
get '-/system/temp/:secret/:filename',
to: 'uploads#show',
constraints: { filename: /[^\/]+/ }
constraints: { filename: %r{[^/]+} }
# Appearance
get "-/system/:model/:mounted_as/:id/:filename",
......@@ -22,7 +22,7 @@ scope path: :uploads do
# Project markdown uploads
get ":namespace_id/:project_id/:secret/:filename",
to: "projects/uploads#show",
constraints: { namespace_id: /[a-zA-Z.0-9_\-]+/, project_id: /[a-zA-Z.0-9_\-]+/, filename: /[^\/]+/ }
constraints: { namespace_id: /[a-zA-Z.0-9_\-]+/, project_id: /[a-zA-Z.0-9_\-]+/, filename: %r{[^/]+} }
# create uploads for models, snippets (notes) available for now
post ':model',
......@@ -34,4 +34,4 @@ end
# Redirect old note attachments path to new uploads path.
get "files/note/:id/:filename",
to: redirect("uploads/note/attachment/%{id}/%{filename}"),
constraints: { filename: /[^\/]+/ }
constraints: { filename: %r{[^/]+} }
......@@ -5,17 +5,32 @@ Enterprise Edition (look for the [`CE Upstream` merge requests]).
This merge is done automatically in a
[scheduled pipeline](https://gitlab.com/gitlab-org/release-tools/-/jobs/43201679).
If a merge is already in progress, the job [doesn't create a new one](https://gitlab.com/gitlab-org/release-tools/-/jobs/43157687).
**If you are pinged in a `CE Upstream` merge request to resolve a conflict,
please resolve the conflict as soon as possible or ask someone else to do it!**
>**Note:**
It's ok to resolve more conflicts than the one that you are asked to resolve. In
that case, it's a good habit to ask for a double-check on your resolution by
someone who is familiar with the code you touched.
## What to do if you are pinged in a `CE Upstream` merge request to resolve a conflict?
1. Please resolve the conflict as soon as possible or ask someone else to do it
- It's ok to resolve more conflicts than the one that you are asked to resolve.
In that case, it's a good habit to ask for a double-check on your resolution
by someone who is familiar with the code you touched.
1. Once you have resolved your conflicts, push to the branch (no force-push)
1. Assign the merge request to the next person that has to resolve a conflict
1. If all conflicts are resolved after your resolution is pushed, keep the merge
request assigned to you: **you are now responsible for the merge request to be
green**
1. If you need any help, you can ping the current [release managers], or ask in
the `#ce-to-ee` Slack channel
A few notes about the automatic CE->EE merge job:
- If a merge is already in progress, the job
[doesn't create a new one](https://gitlab.com/gitlab-org/release-tools/-/jobs/43157687).
- If there is nothing to merge (i.e. EE is up-to-date with CE), the job doesn't
create a new one
- The job posts messages to the `#ce-to-ee` Slack channel to inform what's the
current CE->EE merge status (e.g. "A new MR has been created", "A MR is still pending")
[`CE Upstream` merge requests]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests?label_name%5B%5D=CE+upstream
[release managers]: https://about.gitlab.com/release-managers/
## Always merge EE merge requests before their CE counterparts
......
......@@ -80,7 +80,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.14.3 or higher
# Make sure Git is version 2.9.5 or higher
git --version
Is the system packaged Git too old? Remove it and compile from source.
......@@ -93,9 +93,9 @@ Is the system packaged Git too old? Remove it and compile from source.
# Download and compile from source
cd /tmp
curl --remote-name --progress https://www.kernel.org/pub/software/scm/git/git-2.8.4.tar.gz
echo '626e319f8a24fc0866167ea5f6bf3e2f38f69d6cb2e59e150f13709ca3ebf301 git-2.8.4.tar.gz' | shasum -a256 -c - && tar -xzf git-2.8.4.tar.gz
cd git-2.8.4/
curl --remote-name --progress https://www.kernel.org/pub/software/scm/git/git-2.14.3.tar.gz
echo '023ffff6d3ba8a1bea779dfecc0ed0bb4ad68ab8601d14435dd8c08416f78d7f git-2.14.3.tar.gz' | shasum -a256 -c - && tar -xzf git-2.14.3.tar.gz
cd git-2.14.3/
./configure
make prefix=/usr/local all
......
......@@ -90,7 +90,8 @@ structure.
To create a subgroup:
1. In the group's dashboard go to the **Subgroups** page and click **New subgroup**.
1. In the group's dashboard expand the **New project** split button, select
**New subgroup** and click the **New subgroup** button.
![Subgroups page](img/create_subgroup_button.png)
......
......@@ -193,7 +193,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'The link with text "/ID" should have url "tree/markdownID"' do
find('a', text: /^\/#id$/)['href'] == current_host + project_tree_path(@project, "markdown") + '#id'
find('a', text: %r{^/#id$})['href'] == current_host + project_tree_path(@project, "markdown") + '#id'
end
step 'The link with text "README.mdID" '\
......@@ -203,7 +203,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
step 'The link with text "d/README.mdID" should have '\
'url "blob/markdown/d/README.mdID"' do
find('a', text: /^d\/README.md#id$/)['href'] == current_host + project_blob_path(@project, "d/markdown/README.md") + '#id'
find('a', text: %r{^d/README.md#id$})['href'] == current_host + project_blob_path(@project, "d/markdown/README.md") + '#id'
end
step 'The link with text "ID" should have url "blob/markdown/README.mdID"' do
......@@ -212,7 +212,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'The link with text "/ID" should have url "blob/markdown/README.mdID"' do
find('a', text: /^\/#id$/)['href'] == current_host + project_blob_path(@project, "markdown/README.md") + '#id'
find('a', text: %r{^/#id$})['href'] == current_host + project_blob_path(@project, "markdown/README.md") + '#id'
end
# Wiki
......
......@@ -17,15 +17,15 @@ module API
}
}.freeze
PROJECT_TEMPLATE_REGEX =
/[\<\{\[]
%r{[\<\{\[]
(project|description|
one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here
[\>\}\]]/xi.freeze
[\>\}\]]}xi.freeze
YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze
FULLNAME_TEMPLATE_REGEX =
/[\<\{\[]
%r{[\<\{\[]
(fullname|name\sof\s(author|copyright\sowner))
[\>\}\]]/xi.freeze
[\>\}\]]}xi.freeze
helpers do
def parsed_license_template
......
......@@ -173,7 +173,7 @@ module API
use :sort_params
use :pagination
end
get "/search/:query", requirements: { query: /[^\/]+/ } do
get "/search/:query", requirements: { query: %r{[^/]+} } do
search_service = Search::GlobalService.new(current_user, search: params[:query]).execute
projects = search_service.objects('projects', params[:page], false)
projects = projects.reorder(params[:order_by] => params[:sort])
......
......@@ -16,15 +16,15 @@ module API
}
}.freeze
PROJECT_TEMPLATE_REGEX =
/[\<\{\[]
%r{[\<\{\[]
(project|description|
one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here
[\>\}\]]/xi.freeze
[\>\}\]]}xi.freeze
YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze
FULLNAME_TEMPLATE_REGEX =
/[\<\{\[]
%r{[\<\{\[]
(fullname|name\sof\s(author|copyright\sowner))
[\>\}\]]/xi.freeze
[\>\}\]]}xi.freeze
DEPRECATION_MESSAGE = ' This endpoint is deprecated and has been removed in V4.'.freeze
helpers do
......
......@@ -54,9 +54,9 @@ module Banzai
# Build a regexp that matches all valid :emoji: names.
def self.emoji_pattern
@emoji_pattern ||=
/(?<=[^[:alnum:]:]|\n|^)
%r{(?<=[^[:alnum:]:]|\n|^)
:(#{Gitlab::Emoji.emojis_names.map { |name| Regexp.escape(name) }.join('|')}):
(?=[^[:alnum:]:]|$)/x
(?=[^[:alnum:]:]|$)}x
end
# Build a regexp that matches all valid unicode emojis names.
......
......@@ -51,10 +51,10 @@ module Banzai
# See https://github.com/gollum/gollum/wiki
#
# Rubular: http://rubular.com/r/7dQnE5CUCH
TAGS_PATTERN = %r{\[\[(.+?)\]\]}.freeze
TAGS_PATTERN = /\[\[(.+?)\]\]/.freeze
# Pattern to match allowed image extensions
ALLOWED_IMAGE_EXTENSIONS = %r{.+(jpg|png|gif|svg|bmp)\z}i.freeze
ALLOWED_IMAGE_EXTENSIONS = /.+(jpg|png|gif|svg|bmp)\z/i.freeze
def call
search_text_nodes(doc).each do |node|
......
......@@ -11,7 +11,7 @@ module ContainerRegistry
private
def default_path
@uri.sub(/^https?:\/\//, '')
@uri.sub(%r{^https?://}, '')
end
end
end
......@@ -56,7 +56,7 @@ module ExtractsPath
if valid_refs.length == 0
# No exact ref match, so just try our best
pair = id.match(/([^\/]+)(.*)/).captures
pair = id.match(%r{([^/]+)(.*)}).captures
else
# There is a distinct possibility that multiple refs prefix the ID.
# Use the longest match to maximize the chance that we have the
......@@ -68,7 +68,7 @@ module ExtractsPath
end
# Remove ending slashes from path
pair[1].gsub!(/^\/|\/$/, '')
pair[1].gsub!(%r{^/|/$}, '')
pair
end
......
......@@ -12,7 +12,7 @@ module Gitlab
# Ends with /:random_hex/:filename
FILE_UPLOADER_PATH = %r{/\h+/[^/]+\z}
FULL_PATH_CAPTURE = %r{\A(.+)#{FILE_UPLOADER_PATH}}
FULL_PATH_CAPTURE = /\A(.+)#{FILE_UPLOADER_PATH}/
# These regex patterns are tested against a relative path, relative to
# the upload directory.
......
......@@ -97,7 +97,7 @@ module Gitlab
end
def total_size
descendant_pattern = %r{^#{Regexp.escape(@path.to_s)}}
descendant_pattern = /^#{Regexp.escape(@path.to_s)}/
entries.sum do |path, entry|
(entry[:size] if path =~ descendant_pattern).to_i
end
......
......@@ -11,7 +11,7 @@ module Gitlab
end
def package_url(name)
"https://packagist.org/packages/#{name}" if name =~ %r{\A#{REPO_REGEX}\z}
"https://packagist.org/packages/#{name}" if name =~ /\A#{REPO_REGEX}\z/
end
end
end
......
......@@ -15,7 +15,7 @@ module Gitlab
link_regex(/(github:|:github\s*=>)\s*['"](?<name>[^'"]+)['"]/, &method(:github_url))
# Link `git: "https://gitlab.example.com/user/repo"` to https://gitlab.example.com/user/repo
link_regex(%r{(git:|:git\s*=>)\s*['"](?<name>#{URL_REGEX})['"]}, &:itself)
link_regex(/(git:|:git\s*=>)\s*['"](?<name>#{URL_REGEX})['"]/, &:itself)
# Link `source "https://rubygems.org"` to https://rubygems.org
link_method_call('source', URL_REGEX, &:itself)
......
......@@ -12,7 +12,7 @@ module Gitlab
def link_dependencies
link_method_call('homepage', URL_REGEX, &:itself)
link_regex(%r{(git:|:git\s*=>)\s*['"](?<name>#{URL_REGEX})['"]}, &:itself)
link_regex(/(git:|:git\s*=>)\s*['"](?<name>#{URL_REGEX})['"]/, &:itself)
link_method_call('license', &method(:license_url))
link_regex(/license\s*=\s*\{\s*(type:|:type\s*=>)\s*#{STRING_REGEX}/, &method(:license_url))
......
......@@ -43,7 +43,7 @@ module Gitlab
return "" unless decoded
# Certain trigger phrases that means we didn't parse correctly
if decoded =~ /(Content\-Type\:|multipart\/alternative|text\/plain)/
if decoded =~ %r{(Content\-Type\:|multipart/alternative|text/plain)}
return ""
end
......
......@@ -6,14 +6,14 @@ module Gitlab
module FileDetector
PATTERNS = {
# Project files
readme: /\Areadme[^\/]*\z/i,
changelog: /\A(changelog|history|changes|news)[^\/]*\z/i,
license: /\A(licen[sc]e|copying)(\.[^\/]+)?\z/i,
contributing: /\Acontributing[^\/]*\z/i,
readme: %r{\Areadme[^/]*\z}i,
changelog: %r{\A(changelog|history|changes|news)[^/]*\z}i,
license: %r{\A(licen[sc]e|copying)(\.[^/]+)?\z}i,
contributing: %r{\Acontributing[^/]*\z}i,
version: 'version',
avatar: /\Alogo\.(png|jpg|gif)\z/,
issue_template: /\A\.gitlab\/issue_templates\/[^\/]+\.md\z/,
merge_request_template: /\A\.gitlab\/merge_request_templates\/[^\/]+\.md\z/,
issue_template: %r{\A\.gitlab/issue_templates/[^/]+\.md\z},
merge_request_template: %r{\A\.gitlab/merge_request_templates/[^/]+\.md\z},
# Configuration files
gitignore: '.gitignore',
......@@ -22,17 +22,17 @@ module Gitlab
route_map: '.gitlab/route-map.yml',
# Dependency files
cartfile: /\ACartfile[^\/]*\z/,
cartfile: %r{\ACartfile[^/]*\z},
composer_json: 'composer.json',
gemfile: /\A(Gemfile|gems\.rb)\z/,
gemfile_lock: 'Gemfile.lock',
gemspec: /\A[^\/]*\.gemspec\z/,
gemspec: %r{\A[^/]*\.gemspec\z},
godeps_json: 'Godeps.json',
package_json: 'package.json',
podfile: 'Podfile',
podspec_json: /\A[^\/]*\.podspec\.json\z/,
podspec: /\A[^\/]*\.podspec\z/,
requirements_txt: /\A[^\/]*requirements\.txt\z/,
podspec_json: %r{\A[^/]*\.podspec\.json\z},
podspec: %r{\A[^/]*\.podspec\z},
requirements_txt: %r{\A[^/]*requirements\.txt\z},
yarn_lock: 'yarn.lock'
}.freeze
......
......@@ -11,7 +11,7 @@ module Gitlab
include Gitlab::EncodingHelper
def ref_name(ref)
encode!(ref).sub(/\Arefs\/(tags|heads|remotes)\//, '')
encode!(ref).sub(%r{\Arefs/(tags|heads|remotes)/}, '')
end
def branch_name(ref)
......
......@@ -107,7 +107,7 @@ module Gitlab
def find_entry_by_path(repository, root_id, path)
root_tree = repository.lookup(root_id)
# Strip leading slashes
path[/^\/*/] = ''
path[%r{^/*}] = ''
path_arr = path.split('/')
entry = root_tree.find do |entry|
......@@ -140,7 +140,7 @@ module Gitlab
def find_by_gitaly(repository, sha, path, limit: MAX_DATA_DISPLAY_SIZE)
return unless path
path = path.sub(/\A\/*/, '')
path = path.sub(%r{\A/*}, '')
path = '/' if path.empty?
name = File.basename(path)
......
......@@ -6,7 +6,7 @@ module Gitlab
class << self
def normalize_path(filename)
# Strip all leading slashes so that //foo -> foo
filename[/^\/*/] = ''
filename[%r{^/*}] = ''
# Expand relative paths (e.g. foo/../bar)
filename = Pathname.new(filename)
......
......@@ -23,7 +23,7 @@ module Gitlab
# Ex.
# Ref.extract_branch_name('refs/heads/master') #=> 'master'
def self.extract_branch_name(str)
str.gsub(/\Arefs\/heads\//, '')
str.gsub(%r{\Arefs/heads/}, '')
end
# Gitaly: this method will probably be migrated indirectly via its call sites.
......
......@@ -462,7 +462,6 @@ module Gitlab
path: nil,
follow: false,
skip_merges: false,
disable_walk: false,
after: nil,
before: nil
}
......@@ -494,11 +493,7 @@ module Gitlab
return []
end
if log_using_shell?(options)
log_by_shell(sha, options)
else
log_by_walk(sha, options)
end
end
def count_commits(options)
......@@ -1397,7 +1392,7 @@ module Gitlab
end
def search_files_by_name(query, ref)
safe_query = Regexp.escape(query.sub(/^\/*/, ""))
safe_query = Regexp.escape(query.sub(%r{^/*}, ""))
return [] if empty? || safe_query.blank?
......@@ -1645,24 +1640,6 @@ module Gitlab
end
end
def log_using_shell?(options)
options[:path].present? ||
options[:disable_walk] ||
options[:skip_merges] ||
options[:after] ||
options[:before]
end
def log_by_walk(sha, options)
walk_options = {
show: sha,
sort: Rugged::SORT_NONE,
limit: options[:limit],
offset: options[:offset]
}
Rugged::Walker.walk(rugged, walk_options).to_a
end
# Gitaly note: JV: although #log_by_shell shells out to Git I think the
# complexity is such that we should migrate it as Ruby before trying to
# do it in Go.
......@@ -2025,7 +2002,7 @@ module Gitlab
target_commit = Gitlab::Git::Commit.find(self, rugged_ref.target)
Gitlab::Git::Branch.new(self, rugged_ref.name, rugged_ref.target, target_commit)
rescue Rugged::ReferenceError => e
raise InvalidRef.new("Branch #{ref} already exists") if e.to_s =~ /'refs\/heads\/#{ref}'/
raise InvalidRef.new("Branch #{ref} already exists") if e.to_s =~ %r{'refs/heads/#{ref}'}
raise InvalidRef.new("Invalid reference #{start_point}")
end
......
......@@ -43,7 +43,7 @@ module Gitlab
branches = []
rugged.references.each("refs/remotes/#{remote_name}/*").map do |ref|
name = ref.name.sub(/\Arefs\/remotes\/#{remote_name}\//, '')
name = ref.name.sub(%r{\Arefs/remotes/#{remote_name}/}, '')
begin
target_commit = Gitlab::Git::Commit.find(self, ref.target)
......
......@@ -257,7 +257,7 @@ module Gitlab
offset: options[:offset],
follow: options[:follow],
skip_merges: options[:skip_merges],
disable_walk: options[:disable_walk]
disable_walk: true # This option is deprecated. The 'walk' implementation is being removed.
)
request.after = GitalyClient.timestamp(options[:after]) if options[:after]
request.before = GitalyClient.timestamp(options[:before]) if options[:before]
......
......@@ -13,7 +13,7 @@ module Gitlab
:diff_hunk, :author, :note, :created_at, :updated_at,
:github_id
NOTEABLE_ID_REGEX = /\/pull\/(?<iid>\d+)/i
NOTEABLE_ID_REGEX = %r{/pull/(?<iid>\d+)}i
# Builds a diff note from a GitHub API response.
#
......
......@@ -12,7 +12,7 @@ module Gitlab
expose_attribute :noteable_id, :noteable_type, :author, :note,
:created_at, :updated_at, :github_id
NOTEABLE_TYPE_REGEX = /\/(?<type>(pull|issues))\/(?<iid>\d+)/i
NOTEABLE_TYPE_REGEX = %r{/(?<type>(pull|issues))/(?<iid>\d+)}i
# Builds a note from a GitHub API response.
#
......
......@@ -59,7 +59,7 @@ module Gitlab
end
def extracted_files
Dir.glob("#{@shared.export_path}/**/*", File::FNM_DOTMATCH).reject { |f| f =~ /.*\/\.{1,2}$/ }
Dir.glob("#{@shared.export_path}/**/*", File::FNM_DOTMATCH).reject { |f| f =~ %r{.*/\.{1,2}$} }
end
end
end
......
......@@ -34,7 +34,7 @@ module Gitlab
end
def relative_path(path)
path.gsub(/^#{Rails.root.to_s}\/?/, '')
path.gsub(%r{^#{Rails.root.to_s}/?}, '')
end
def values_for(event)
......
......@@ -56,12 +56,12 @@ module Gitlab
end
def strip_url(url)
url.gsub(/\Ahttps?:\/\//, '')
url.gsub(%r{\Ahttps?://}, '')
end
def project_path(request)
path_info = request.env["PATH_INFO"]
path_info.sub!(/^\//, '')
path_info.sub!(%r{^/}, '')
project_path_match = "#{path_info}/".match(PROJECT_PATH_REGEX)
return unless project_path_match
......
module Gitlab
module Middleware
class Static < ActionDispatch::Static
UPLOADS_REGEX = /\A\/uploads(\/|\z)/.freeze
UPLOADS_REGEX = %r{\A/uploads(/|\z)}.freeze
def call(env)
return @app.call(env) if env['PATH_INFO'] =~ UPLOADS_REGEX
......
......@@ -9,7 +9,7 @@ module Gitlab
# if date doesn't present return time with current date
# in other cases return nil
class SpendTimeAndDateSeparator
DATE_REGEX = /(\d{2,4}[\/\-.]\d{1,2}[\/\-.]\d{1,2})/
DATE_REGEX = %r{(\d{2,4}[/\-.]\d{1,2}[/\-.]\d{1,2})}
def initialize(spend_command_arg)
@spend_arg = spend_command_arg
......
......@@ -30,7 +30,7 @@ module Gitlab
raise NotFoundError.new("No known storage path matches #{repo_path.inspect}")
end
result.sub(/\A\/*/, '')
result.sub(%r{\A/*}, '')
end
def self.find_project(project_path)
......
......@@ -31,7 +31,7 @@ module Gitlab
storages << { name: 'test_second_storage', path: Rails.root.join('tmp', 'tests', 'second_storage').to_s }
end
config = { socket_path: address.sub(%r{\Aunix:}, ''), storage: storages }
config = { socket_path: address.sub(/\Aunix:/, ''), storage: storages }
config[:auth] = { token: 'secret' } if Rails.env.test?
config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby
config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }
......
......@@ -16,7 +16,7 @@ module Gitlab
end
def relative_path
@relative_path ||= @file.gsub(/^#{Rails.root.to_s}\/?/, '')
@relative_path ||= @file.gsub(%r{^#{Rails.root.to_s}/?}, '')
end
def to_param
......
......@@ -2,7 +2,7 @@ module Gitlab
module Sherlock
# Rack middleware used for tracking request metrics.
class Middleware
CONTENT_TYPES = /text\/html|application\/json/i
CONTENT_TYPES = %r{text/html|application/json}i
IGNORE_PATHS = %r{^/sherlock}
......
......@@ -4,7 +4,7 @@ module Gitlab
attr_reader :id, :query, :started_at, :finished_at, :backtrace
# SQL identifiers that should be prefixed with newlines.
PREFIX_NEWLINE = /
PREFIX_NEWLINE = %r{
\s+(FROM
|(LEFT|RIGHT)?INNER\s+JOIN
|(LEFT|RIGHT)?OUTER\s+JOIN
......@@ -13,7 +13,7 @@ module Gitlab
|GROUP\s+BY
|ORDER\s+BY
|LIMIT
|OFFSET)\s+/ix # Vim indent breaks when this is on a newline :<
|OFFSET)\s+}ix # Vim indent breaks when this is on a newline :<
# Creates a new Query using a String and a separate Array of bindings.
#
......
......@@ -49,7 +49,7 @@ module Gitlab
def fetch_git_tags
remote_tags, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git))
remote_tags.split("\n").grep(/tags\/v#{current_version.major}/)
remote_tags.split("\n").grep(%r{tags/v#{current_version.major}})
end
def update_commands
......
......@@ -5,7 +5,7 @@ module SystemCheck
set_check_pass -> { "yes (#{self.current_version})" }
def self.required_version
@required_version ||= Gitlab::VersionInfo.new(2, 7, 3)
@required_version ||= Gitlab::VersionInfo.new(2, 9, 5)
end
def self.current_version
......
require 'securerandom'
module QA
module Factory
module Resource
......
......@@ -7,7 +7,7 @@ module QA
element :settings_link, 'link_to edit_project_path'
element :repository_link, "title: 'Repository'"
element :pipelines_settings_link, "title: 'CI / CD'"
element :issues_link, %r{link_to.*shortcuts-issues}
element :issues_link, /link_to.*shortcuts-issues/
element :issues_link_text, "Issues"
element :top_level_items, '.sidebar-top-level-items'
element :activity_link, "title: 'Activity'"
......
module QA
feature 'creates issue', :core do
let(:issue_title) { 'issue title' }
scenario 'user creates issue' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
Factory::Resource::Issue.fabricate! do |issue|
issue.title = issue_title
end
Page::Menu::Side.act { click_issues }
expect(page).to have_content(issue_title)
end
end
end
......@@ -3,7 +3,7 @@ describe QA::Runtime::RSAKey do
subject { described_class.new.public_key }
it 'generates a public RSA key' do
expect(subject).to match(/\Assh\-rsa AAAA[0-9A-Za-z+\/]+={0,3}\z/)
expect(subject).to match(%r{\Assh\-rsa AAAA[0-9A-Za-z+/]+={0,3}\z})
end
end
end
......@@ -29,7 +29,7 @@ module RuboCop
path = Pathname.new(source_name).relative_path_from(rails_root)
dirname = File.dirname(path)
.sub(%r{\Adb/(migrate|post_migrate)}, 'spec/migrations')
filename = File.basename(source_name, '.rb').sub(%r{\A\d+_}, '')
filename = File.basename(source_name, '.rb').sub(/\A\d+_/, '')
File.join(dirname, "#{filename}_spec.rb")
end
......
......@@ -137,8 +137,8 @@ describe Projects::JobsController do
it 'exposes needed information' do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['raw_path']).to match(/jobs\/\d+\/raw\z/)
expect(json_response.dig('merge_request', 'path')).to match(/merge_requests\/\d+\z/)
expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z})
expect(json_response.dig('merge_request', 'path')).to match(%r{merge_requests/\d+\z})
expect(json_response['new_issue_path'])
.to include('/issues/new')
end
......
......@@ -36,7 +36,7 @@ describe Projects::TodosController do
expect(response).to have_gitlab_http_status(200)
expect(json_response['count']).to eq 1
expect(json_response['delete_path']).to match(/\/dashboard\/todos\/\d{1}/)
expect(json_response['delete_path']).to match(%r{/dashboard/todos/\d{1}})
end
end
......@@ -104,7 +104,7 @@ describe Projects::TodosController do
expect(response).to have_gitlab_http_status(200)
expect(json_response['count']).to eq 1
expect(json_response['delete_path']).to match(/\/dashboard\/todos\/\d{1}/)
expect(json_response['delete_path']).to match(%r{/dashboard/todos/\d{1}})
end
end
......
......@@ -64,7 +64,7 @@ describe "User Feed" do
end
it 'has XHTML summaries in issue descriptions' do
expect(body).to match /<hr ?\/>/
expect(body).to match %r{<hr ?/>}
end
it 'has XHTML summaries in notes' do
......@@ -72,7 +72,7 @@ describe "User Feed" do
end
it 'has XHTML summaries in merge request descriptions' do
expect(body).to match /Here is the fix: <a[^>]*><img[^>]*\/><\/a>/
expect(body).to match %r{Here is the fix: <a[^>]*><img[^>]*/></a>}
end
it 'has push event commit ID' do
......
......@@ -3,6 +3,7 @@ require 'spec_helper'
feature 'Group issues page' do
include FilteredSearchHelpers
context 'with shared examples' do
let(:path) { issues_group_path(group) }
let(:issuable) { create(:issue, project: project, title: "this is my created issuable")}
......@@ -39,4 +40,24 @@ feature 'Group issues page' do
expect(find('#js-dropdown-assignee .filter-dropdown')).not_to have_content(user2.name)
end
end
end
context 'issues list', :nested_groups do
let(:group) { create(:group)}
let(:subgroup) { create(:group, parent: group) }
let(:project) { create(:project, :public, group: group)}
let(:subgroup_project) { create(:project, :public, group: subgroup)}
let!(:issue) { create(:issue, project: project, title: 'root group issue') }
let!(:subgroup_issue) { create(:issue, project: subgroup_project, title: 'subgroup issue') }
it 'returns all group and subgroup issues' do
visit issues_group_path(group)
page.within('.issuable-list') do
expect(page).to have_selector('li.issue', count: 2)
expect(page).to have_content('root group issue')
expect(page).to have_content('subgroup issue')
end
end
end
end
......@@ -100,12 +100,12 @@ describe 'Merge request > User resolves conflicts', :js do
end
it 'shows a link to the conflict resolution page' do
expect(page).to have_link('conflicts', href: /\/conflicts\Z/)
expect(page).to have_link('conflicts', href: %r{/conflicts\Z})
end
context 'in Inline view mode' do
before do
click_link('conflicts', href: /\/conflicts\Z/)
click_link('conflicts', href: %r{/conflicts\Z})
end
include_examples "conflicts are resolved in Interactive mode"
......@@ -114,7 +114,7 @@ describe 'Merge request > User resolves conflicts', :js do
context 'in Parallel view mode' do
before do
click_link('conflicts', href: /\/conflicts\Z/)
click_link('conflicts', href: %r{/conflicts\Z})
click_button 'Side-by-side'
end
......@@ -128,7 +128,7 @@ describe 'Merge request > User resolves conflicts', :js do
before do
visit project_merge_request_path(project, merge_request)
click_link('conflicts', href: /\/conflicts\Z/)
click_link('conflicts', href: %r{/conflicts\Z})
end
it 'conflicts can not be resolved in Interactive mode' do
......@@ -181,7 +181,7 @@ describe 'Merge request > User resolves conflicts', :js do
end
it 'does not show a link to the conflict resolution page' do
expect(page).not_to have_link('conflicts', href: /\/conflicts\Z/)
expect(page).not_to have_link('conflicts', href: %r{/conflicts\Z})
end
it 'shows an error if the conflicts page is visited directly' do
......
......@@ -2,6 +2,7 @@ require 'spec_helper'
describe GroupProjectsFinder do
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
let(:current_user) { create(:user) }
let(:options) { {} }
......@@ -12,6 +13,8 @@ describe GroupProjectsFinder do
let!(:shared_project_1) { create(:project, :public, path: '3') }
let!(:shared_project_2) { create(:project, :private, path: '4') }
let!(:shared_project_3) { create(:project, :internal, path: '5') }
let!(:subgroup_project) { create(:project, :public, path: '6', group: subgroup) }
let!(:subgroup_private_project) { create(:project, :private, path: '7', group: subgroup) }
before do
shared_project_1.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group)
......@@ -35,13 +38,33 @@ describe GroupProjectsFinder do
context "only owned" do
let(:options) { { only_owned: true } }
context 'with subgroups projects', :nested_groups do
before do
options[:include_subgroups] = true
end
it { is_expected.to match_array([private_project, public_project, subgroup_project, subgroup_private_project]) }
end
context 'without subgroups projects' do
it { is_expected.to match_array([private_project, public_project]) }
end
end
context "all" do
context 'with subgroups projects', :nested_groups do
before do
options[:include_subgroups] = true
end
it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1, private_project, public_project, subgroup_project, subgroup_private_project]) }
end
context 'without subgroups projects' do
it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1, private_project, public_project]) }
end
end
end
describe 'without group member current_user' do
before do
......@@ -71,24 +94,55 @@ describe GroupProjectsFinder do
context "without external user" do
before do
private_project.add_master(current_user)
subgroup_private_project.add_master(current_user)
end
context 'with subgroups projects', :nested_groups do
before do
options[:include_subgroups] = true
end
it { is_expected.to match_array([private_project, public_project, subgroup_project, subgroup_private_project]) }
end
context 'without subgroups projects' do
it { is_expected.to match_array([private_project, public_project]) }
end
end
context "with external user" do
before do
current_user.update_attributes(external: true)
end
context 'with subgroups projects', :nested_groups do
before do
options[:include_subgroups] = true
end
it { is_expected.to match_array([public_project, subgroup_project]) }
end
context 'without subgroups projects' do
it { is_expected.to eq([public_project]) }
end
end
end
context "all" do
context 'with subgroups projects', :nested_groups do
before do
options[:include_subgroups] = true
end
it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1, public_project, subgroup_project]) }
end
context 'without subgroups projects' do
it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1, public_project]) }
end
end
end
describe "no user" do
context "only shared" do
......@@ -100,7 +154,17 @@ describe GroupProjectsFinder do
context "only owned" do
let(:options) { { only_owned: true } }
context 'with subgroups projects', :nested_groups do
before do
options[:include_subgroups] = true
end
it { is_expected.to match_array([public_project, subgroup_project]) }
end
context 'without subgroups projects' do
it { is_expected.to eq([public_project]) }
end
end
end
end
......@@ -3,13 +3,17 @@ require 'spec_helper'
describe IssuesFinder do
set(:user) { create(:user) }
set(:user2) { create(:user) }
set(:project1) { create(:project) }
set(:group) { create(:group) }
set(:subgroup) { create(:group, parent: group) }
set(:project1) { create(:project, group: group) }
set(:project2) { create(:project) }
set(:project3) { create(:project, group: subgroup) }
set(:milestone) { create(:milestone, project: project1) }
set(:label) { create(:label, project: project2) }
set(:issue1) { create(:issue, author: user, assignees: [user], project: project1, milestone: milestone, title: 'gitlab', created_at: 1.week.ago) }
set(:issue2) { create(:issue, author: user, assignees: [user], project: project2, description: 'gitlab') }
set(:issue3) { create(:issue, author: user2, assignees: [user2], project: project2, title: 'tanuki', description: 'tanuki', created_at: 1.week.from_now) }
set(:issue4) { create(:issue, project: project3) }
set(:award_emoji1) { create(:award_emoji, name: 'thumbsup', user: user, awardable: issue1) }
set(:award_emoji2) { create(:award_emoji, name: 'thumbsup', user: user2, awardable: issue2) }
set(:award_emoji3) { create(:award_emoji, name: 'thumbsdown', user: user, awardable: issue3) }
......@@ -25,10 +29,12 @@ describe IssuesFinder do
project1.add_master(user)
project2.add_developer(user)
project2.add_developer(user2)
project3.add_developer(user)
issue1
issue2
issue3
issue4
award_emoji1
award_emoji2
......@@ -39,7 +45,7 @@ describe IssuesFinder do
let(:scope) { 'all' }
it 'returns all issues' do
expect(issues).to contain_exactly(issue1, issue2, issue3)
expect(issues).to contain_exactly(issue1, issue2, issue3, issue4)
end
context 'filtering by assignee ID' do
......@@ -50,6 +56,26 @@ describe IssuesFinder do
end
end
context 'filtering by group_id' do
let(:params) { { group_id: group.id } }
context 'when include_subgroup param not set' do
it 'returns all group issues' do
expect(issues).to contain_exactly(issue1)
end
end
context 'when include_subgroup param is true', :nested_groups do
before do
params[:include_subgroups] = true
end
it 'returns all group and subgroup issues' do
expect(issues).to contain_exactly(issue1, issue4)
end
end
end
context 'filtering by author ID' do
let(:params) { { author_id: user2.id } }
......@@ -87,7 +113,7 @@ describe IssuesFinder do
let(:params) { { milestone_title: Milestone::None.title } }
it 'returns issues with no milestone' do
expect(issues).to contain_exactly(issue2, issue3)
expect(issues).to contain_exactly(issue2, issue3, issue4)
end
end
......@@ -185,7 +211,7 @@ describe IssuesFinder do
let(:params) { { label_name: Label::None.title } }
it 'returns issues with no labels' do
expect(issues).to contain_exactly(issue1, issue3)
expect(issues).to contain_exactly(issue1, issue3, issue4)
end
end
......@@ -210,7 +236,7 @@ describe IssuesFinder do
let(:params) { { state: 'opened' } }
it 'returns only opened issues' do
expect(issues).to contain_exactly(issue1, issue2, issue3)
expect(issues).to contain_exactly(issue1, issue2, issue3, issue4)
end
end
......@@ -226,7 +252,7 @@ describe IssuesFinder do
let(:params) { { state: 'all' } }
it 'returns all issues' do
expect(issues).to contain_exactly(issue1, issue2, issue3, closed_issue)
expect(issues).to contain_exactly(issue1, issue2, issue3, closed_issue, issue4)
end
end
......@@ -234,7 +260,7 @@ describe IssuesFinder do
let(:params) { { state: 'invalid_state' } }
it 'returns all issues' do
expect(issues).to contain_exactly(issue1, issue2, issue3, closed_issue)
expect(issues).to contain_exactly(issue1, issue2, issue3, closed_issue, issue4)
end
end
end
......@@ -338,7 +364,7 @@ describe IssuesFinder do
end
it "doesn't return issues if feature disabled" do
[project1, project2].each do |project|
[project1, project2, project3].each do |project|
project.project_feature.update!(issues_access_level: ProjectFeature::DISABLED)
end
......@@ -351,7 +377,7 @@ describe IssuesFinder do
it 'returns the number of rows for the default state' do
finder = described_class.new(user)
expect(finder.row_count).to eq(3)
expect(finder.row_count).to eq(4)
end
it 'returns the number of rows for a given state' do
......
......@@ -6,31 +6,36 @@ describe MergeRequestsFinder do
let(:user) { create :user }
let(:user2) { create :user }
let(:project1) { create(:project, :public) }
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
let(:project1) { create(:project, :public, group: group) }
let(:project2) { fork_project(project1, user) }
let(:project3) do
p = fork_project(project1, user)
p.update!(archived: true)
p
end
let(:project4) { create(:project, :public, group: subgroup) }
let!(:merge_request1) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1) }
let!(:merge_request2) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1, state: 'closed') }
let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2) }
let!(:merge_request4) { create(:merge_request, :simple, author: user, source_project: project3, target_project: project3) }
let!(:merge_request5) { create(:merge_request, :simple, author: user, source_project: project4, target_project: project4) }
before do
project1.add_master(user)
project2.add_developer(user)
project3.add_developer(user)
project2.add_developer(user2)
project4.add_developer(user)
end
describe "#execute" do
it 'filters by scope' do
params = { scope: 'authored', state: 'opened' }
merge_requests = described_class.new(user, params).execute
expect(merge_requests.size).to eq(3)
expect(merge_requests.size).to eq(4)
end
it 'filters by project' do
......@@ -39,10 +44,26 @@ describe MergeRequestsFinder do
expect(merge_requests.size).to eq(1)
end
it 'filters by group' do
params = { group_id: group.id }
merge_requests = described_class.new(user, params).execute
expect(merge_requests.size).to eq(2)
end
it 'filters by group including subgroups', :nested_groups do
params = { group_id: group.id, include_subgroups: true }
merge_requests = described_class.new(user, params).execute
expect(merge_requests.size).to eq(3)
end
it 'filters by non_archived' do
params = { non_archived: true }
merge_requests = described_class.new(user, params).execute
expect(merge_requests.size).to eq(3)
expect(merge_requests.size).to eq(4)
end
it 'filters by iid' do
......@@ -73,14 +94,14 @@ describe MergeRequestsFinder do
end
context 'with created_after and created_before params' do
let(:project4) { create(:project, forked_from_project: project1) }
let(:new_project) { create(:project, forked_from_project: project1) }
let!(:new_merge_request) do
create(:merge_request,
:simple,
author: user,
created_at: 1.week.from_now,
source_project: project4,
source_project: new_project,
target_project: project1)
end
......@@ -89,12 +110,12 @@ describe MergeRequestsFinder do
:simple,
author: user,
created_at: 1.week.ago,
source_project: project4,
target_project: project4)
source_project: new_project,
target_project: new_project)
end
before do
project4.add_master(user)
new_project.add_master(user)
end
it 'filters by created_after' do
......@@ -106,7 +127,7 @@ describe MergeRequestsFinder do
end
it 'filters by created_before' do
params = { project_id: project4.id, created_before: old_merge_request.created_at + 1.second }
params = { project_id: new_project.id, created_before: old_merge_request.created_at + 1.second }
merge_requests = described_class.new(user, params).execute
......@@ -119,7 +140,7 @@ describe MergeRequestsFinder do
it 'returns the number of rows for the default state' do
finder = described_class.new(user)
expect(finder.row_count).to eq(3)
expect(finder.row_count).to eq(4)
end
it 'returns the number of rows for a given state' do
......
......@@ -105,7 +105,7 @@ describe GroupsHelper do
it 'outputs the groups in the correct order' do
expect(helper.group_title(very_deep_nested_group))
.to match(/<li style="text-indent: 16px;"><a.*>#{deep_nested_group.name}.*<\/li>.*<a.*>#{very_deep_nested_group.name}<\/a>/m)
.to match(%r{<li style="text-indent: 16px;"><a.*>#{deep_nested_group.name}.*</li>.*<a.*>#{very_deep_nested_group.name}</a>}m)
end
end
......@@ -120,7 +120,7 @@ describe GroupsHelper do
let(:possible_help_texts) do
{
default_help: "This setting will be applied to all subgroups unless overridden by a group owner",
ancestor_locked_but_you_can_override: /This setting is applied on <a .+>.+<\/a>\. You can override the setting or .+/,
ancestor_locked_but_you_can_override: %r{This setting is applied on <a .+>.+</a>\. You can override the setting or .+},
ancestor_locked_so_ask_the_owner: /This setting is applied on .+\. To share projects in this group with another group, ask the owner to override the setting or remove the share with group lock from .+/,
ancestor_locked_and_has_been_overridden: /This setting is applied on .+ and has been overridden on this subgroup/
}
......
......@@ -104,7 +104,7 @@ describe LabelsHelper do
context 'with a tooltip argument' do
context 'set to false' do
it 'does not include the has-tooltip class' do
expect(link_to_label(label, tooltip: false)).not_to match %r{has-tooltip}
expect(link_to_label(label, tooltip: false)).not_to match /has-tooltip/
end
end
end
......
......@@ -27,7 +27,7 @@ describe VersionCheckHelper do
end
it 'should have a VersionCheck url as the src' do
expect(@image_tag).to match(/src="https:\/\/version\.host\.com\/check\.svg\?gitlab_info=xxx"/)
expect(@image_tag).to match(%r{src="https://version\.host\.com/check\.svg\?gitlab_info=xxx"})
end
end
end
......
import Vue from 'vue';
import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links';
const createComponent = (data) => {
const Component = Vue.extend(relatedLinksComponent);
return new Component({
el: document.createElement('div'),
propsData: data,
});
};
import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('MRWidgetRelatedLinks', () => {
describe('props', () => {
it('should have props', () => {
const { relatedLinks } = relatedLinksComponent.props;
let vm;
expect(relatedLinks).toBeDefined();
expect(relatedLinks.type instanceof Object).toBeTruthy();
expect(relatedLinks.required).toBeTruthy();
});
});
const createComponent = (data) => {
const Component = Vue.extend(relatedLinksComponent);
describe('computed', () => {
const data = {
relatedLinks: {
closing: '/foo',
mentioned: '/foo',
assignToMe: '/foo',
},
return mountComponent(Component, data);
};
describe('hasLinks', () => {
it('should return correct value when we have links reference', () => {
const vm = createComponent(data);
expect(vm.hasLinks).toBeTruthy();
vm.relatedLinks.closing = null;
expect(vm.hasLinks).toBeTruthy();
vm.relatedLinks.mentioned = null;
expect(vm.hasLinks).toBeTruthy();
vm.relatedLinks.assignToMe = null;
expect(vm.hasLinks).toBeFalsy();
});
afterEach(() => {
vm.$destroy();
});
describe('computed', () => {
describe('closesText', () => {
it('returns correct text for open merge request', () => {
data.state = 'open';
const vm = createComponent(data);
it('returns Closes text for open merge request', () => {
vm = createComponent({ state: 'open', relatedLinks: {} });
expect(vm.closesText).toEqual('Closes');
});
it('returns correct text for closed merge request', () => {
data.state = 'closed';
const vm = createComponent(data);
vm = createComponent({ state: 'closed', relatedLinks: {} });
expect(vm.closesText).toEqual('Did not close');
});
it('returns correct tense for merged request', () => {
data.state = 'merged';
const vm = createComponent(data);
vm = createComponent({ state: 'merged', relatedLinks: {} });
expect(vm.closesText).toEqual('Closed');
});
});
});
describe('template', () => {
it('should have only have closing issues text', () => {
const vm = createComponent({
vm = createComponent({
relatedLinks: {
closing: '<a href="#">#23</a> and <a>#42</a>',
},
......@@ -81,7 +47,7 @@ describe('MRWidgetRelatedLinks', () => {
});
it('should have only have mentioned issues text', () => {
const vm = createComponent({
vm = createComponent({
relatedLinks: {
mentioned: '<a href="#">#7</a>',
},
......@@ -92,7 +58,7 @@ describe('MRWidgetRelatedLinks', () => {
});
it('should have closing and mentioned issues at the same time', () => {
const vm = createComponent({
vm = createComponent({
relatedLinks: {
closing: '<a href="#">#7</a>',
mentioned: '<a href="#">#23</a> and <a>#42</a>',
......@@ -105,7 +71,7 @@ describe('MRWidgetRelatedLinks', () => {
});
it('should have assing issues link', () => {
const vm = createComponent({
vm = createComponent({
relatedLinks: {
assignToMe: '<a href="#">Assign yourself to these issues</a>',
},
......@@ -113,5 +79,4 @@ describe('MRWidgetRelatedLinks', () => {
expect(vm.$el.innerText).toContain('Assign yourself to these issues');
});
});
});
......@@ -53,7 +53,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter do
doc = reference_filter("See (#{reference}.)")
exp = Regexp.escape(range.reference_link_text)
expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>#{exp}</a>\.\)})
end
it 'ignores invalid commit IDs' do
......@@ -222,7 +222,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter do
doc = reference_filter("Fixed (#{reference}.)")
exp = Regexp.escape(range.reference_link_text(project))
expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>#{exp}</a>\.\)})
end
it 'ignores invalid commit IDs on the referenced project' do
......
......@@ -42,7 +42,7 @@ describe Banzai::Filter::CommitReferenceFilter do
it 'links with adjacent text' do
doc = reference_filter("See (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{commit.short_id}<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>#{commit.short_id}</a>\.\)})
end
it 'ignores invalid commit IDs' do
......@@ -199,12 +199,12 @@ describe Banzai::Filter::CommitReferenceFilter do
it 'links with adjacent text' do
doc = reference_filter("Fixed (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{commit.reference_link_text(project)}<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>#{commit.reference_link_text(project)}</a>\.\)})
end
it 'ignores invalid commit IDs on the referenced project' do
act = "Committed #{invalidate_reference(reference)}"
expect(reference_filter(act).to_html).to match(/<a.+>#{Regexp.escape(invalidate_reference(reference))}<\/a>/)
expect(reference_filter(act).to_html).to match(%r{<a.+>#{Regexp.escape(invalidate_reference(reference))}</a>})
end
end
end
......@@ -49,7 +49,7 @@ describe Banzai::Filter::ExternalIssueReferenceFilter do
it 'links with adjacent text' do
doc = filter("Issue (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{reference}<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>#{reference}</a>\.\)})
end
it 'includes a title attribute' do
......
......@@ -14,7 +14,7 @@ describe Banzai::Filter::ImageLinkFilter do
it 'does not wrap a duplicate link' do
doc = filter(%Q(<a href="/whatever">#{image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')}</a>))
expect(doc.to_html).to match /^<a href="\/whatever"><img[^>]*><\/a>$/
expect(doc.to_html).to match %r{^<a href="/whatever"><img[^>]*></a>$}
end
it 'works with external images' do
......@@ -24,6 +24,6 @@ describe Banzai::Filter::ImageLinkFilter do
it 'works with inline images' do
doc = filter(%Q(<p>test #{image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')} inline</p>))
expect(doc.to_html).to match /^<p>test <a[^>]*><img[^>]*><\/a> inline<\/p>$/
expect(doc.to_html).to match %r{^<p>test <a[^>]*><img[^>]*></a> inline</p>$}
end
end
......@@ -288,7 +288,7 @@ describe Banzai::Filter::IssueReferenceFilter do
it 'links with adjacent text' do
doc = reference_filter("Fixed (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(issue.to_reference(project))} \(comment 123\)<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>#{Regexp.escape(issue.to_reference(project))} \(comment 123\)</a>\.\)})
end
it 'includes default classes' do
......@@ -317,7 +317,7 @@ describe Banzai::Filter::IssueReferenceFilter do
it 'links with adjacent text' do
doc = reference_filter("Fixed (#{reference_link}.)")
expect(doc.to_html).to match(/\(<a.+>Reference<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>Reference</a>\.\)})
end
it 'includes default classes' do
......@@ -346,7 +346,7 @@ describe Banzai::Filter::IssueReferenceFilter do
it 'links with adjacent text' do
doc = reference_filter("Fixed (#{reference_link}.)")
expect(doc.to_html).to match(/\(<a.+>Reference<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>Reference</a>\.\)})
end
it 'includes default classes' do
......
......@@ -42,7 +42,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter do
it 'links with adjacent text' do
doc = reference_filter("Merge (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>#{Regexp.escape(reference)}</a>\.\)})
end
it 'ignores invalid merge IDs' do
......@@ -211,7 +211,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter do
it 'links with adjacent text' do
doc = reference_filter("Merge (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(merge.to_reference(project))} \(diffs, comment 123\)<\/a>\.\)/)
expect(doc.to_html).to match(%r{\(<a.+>#{Regexp.escape(merge.to_reference(project))} \(diffs, comment 123\)</a>\.\)})
end
end
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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