Commit 8f9cf685 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-02-05

# Conflicts:
#	app/assets/javascripts/dispatcher.js
#	app/assets/javascripts/main.js
#	app/assets/stylesheets/framework.scss
#	app/controllers/application_controller.rb
#	app/helpers/projects_helper.rb
#	app/models/note.rb
#	app/models/protected_branch.rb
#	app/services/ci/register_job_service.rb
#	app/services/users/build_service.rb
#	app/views/admin/health_check/show.html.haml
#	app/views/ci/variables/_variable_row.html.haml
#	app/views/help/index.html.haml
#	app/views/layouts/devise.html.haml
#	app/views/layouts/nav/sidebar/_profile.html.haml
#	lib/api/helpers/runner.rb
#	lib/gitlab/auth.rb
#	spec/lib/gitlab/current_settings_spec.rb
#	spec/lib/gitlab/usage_data_spec.rb

[ci skip]
parents 1f577b6a 9f553730
...@@ -51,6 +51,9 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._ ...@@ -51,6 +51,9 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
## Contribute to GitLab ## Contribute to GitLab
For a first-time step-by-step guide to the contribution process, see
["Contributing to GitLab"](https://about.gitlab.com/contributing/).
Thank you for your interest in contributing to GitLab. This guide details how Thank you for your interest in contributing to GitLab. This guide details how
to contribute to GitLab in a way that is efficient for everyone. to contribute to GitLab in a way that is efficient for everyone.
......
...@@ -235,7 +235,7 @@ export default class FileTemplateMediator { ...@@ -235,7 +235,7 @@ export default class FileTemplateMediator {
} }
setFilename(name) { setFilename(name) {
this.$filenameInput.val(name); this.$filenameInput.val(name).trigger('change');
} }
getSelected() { getSelected() {
......
...@@ -12,6 +12,7 @@ import ShortcutsIssuable from './shortcuts_issuable'; ...@@ -12,6 +12,7 @@ import ShortcutsIssuable from './shortcuts_issuable';
import Diff from './diff'; import Diff from './diff';
import SearchAutocomplete from './search_autocomplete'; import SearchAutocomplete from './search_autocomplete';
<<<<<<< HEAD
// EE-only // EE-only
import UsersSelect from './users_select'; import UsersSelect from './users_select';
import UserCallout from './user_callout'; import UserCallout from './user_callout';
...@@ -22,6 +23,8 @@ import initPathLocks from 'ee/path_locks'; // eslint-disable-line import/first ...@@ -22,6 +23,8 @@ import initPathLocks from 'ee/path_locks'; // eslint-disable-line import/first
import initApprovals from 'ee/approvals'; // eslint-disable-line import/first import initApprovals from 'ee/approvals'; // eslint-disable-line import/first
import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line import/first import initLDAPGroupsSelect from 'ee/ldap_groups_select'; // eslint-disable-line import/first
=======
>>>>>>> upstream/master
var Dispatcher; var Dispatcher;
(function() { (function() {
......
...@@ -461,7 +461,7 @@ class GfmAutoComplete { ...@@ -461,7 +461,7 @@ class GfmAutoComplete {
const accentAChar = decodeURI('%C3%80'); const accentAChar = decodeURI('%C3%80');
const accentYChar = decodeURI('%C3%BF'); const accentYChar = decodeURI('%C3%BF');
const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi'); const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_\`${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi');
return regexp.exec(targetSubtext); return regexp.exec(targetSubtext);
} }
......
...@@ -33,9 +33,12 @@ import './projects_dropdown'; ...@@ -33,9 +33,12 @@ import './projects_dropdown';
import './render_gfm'; import './render_gfm';
import initBreadcrumbs from './breadcrumb'; import initBreadcrumbs from './breadcrumb';
<<<<<<< HEAD
// EE-only scripts // EE-only scripts
import 'ee/main'; import 'ee/main';
=======
>>>>>>> upstream/master
import initDispatcher from './dispatcher'; import initDispatcher from './dispatcher';
// eslint-disable-next-line global-require, import/no-commonjs // eslint-disable-next-line global-require, import/no-commonjs
......
...@@ -59,5 +59,8 @@ ...@@ -59,5 +59,8 @@
@import "framework/memory_graph"; @import "framework/memory_graph";
@import "framework/responsive_tables"; @import "framework/responsive_tables";
@import "framework/stacked-progress-bar"; @import "framework/stacked-progress-bar";
<<<<<<< HEAD
@import "framework/sortable"; @import "framework/sortable";
=======
>>>>>>> upstream/master
@import "framework/ci_variable_list"; @import "framework/ci_variable_list";
...@@ -16,3 +16,31 @@ ...@@ -16,3 +16,31 @@
background-color: $user-mention-bg-hover; background-color: $user-mention-bg-hover;
} }
} }
.gfm-color_chip {
display: inline-block;
margin: 0 0 2px 4px;
vertical-align: middle;
border-radius: 3px;
$chip-size: 0.9em;
$bg-size: $chip-size / 0.9;
$bg-pos: $bg-size / 2;
width: $chip-size;
height: $chip-size;
background: $white-light;
background-image: linear-gradient(135deg, $gray-dark 25%, transparent 0%, transparent 75%, $gray-dark 0%),
linear-gradient(135deg, $gray-dark 25%, transparent 0%, transparent 75%, $gray-dark 0%);
background-size: $bg-size $bg-size;
background-position: 0 0, $bg-pos $bg-pos;
> span {
display: inline-block;
width: 100%;
height: 100%;
margin-bottom: 2px;
border-radius: 3px;
border: 1px solid $black-transparent;
}
}
...@@ -123,11 +123,15 @@ class ApplicationController < ActionController::Base ...@@ -123,11 +123,15 @@ class ApplicationController < ActionController::Base
end end
def after_sign_out_path_for(resource) def after_sign_out_path_for(resource)
<<<<<<< HEAD
if Gitlab::Geo.secondary? if Gitlab::Geo.secondary?
Gitlab::Geo.primary_node.oauth_logout_url(@geo_logout_state) Gitlab::Geo.primary_node.oauth_logout_url(@geo_logout_state)
else else
Gitlab::CurrentSettings.after_sign_out_path.presence || new_user_session_path Gitlab::CurrentSettings.after_sign_out_path.presence || new_user_session_path
end end
=======
Gitlab::CurrentSettings.after_sign_out_path.presence || new_user_session_path
>>>>>>> upstream/master
end end
def can?(object, action, subject = :global) def can?(object, action, subject = :global)
......
module ProjectsHelper module ProjectsHelper
<<<<<<< HEAD
prepend ::EE::ProjectsHelper prepend ::EE::ProjectsHelper
=======
>>>>>>> upstream/master
def link_to_project(project) def link_to_project(project)
link_to [project.namespace.becomes(Namespace), project], title: h(project.name) do link_to [project.namespace.becomes(Namespace), project], title: h(project.name) do
title = content_tag(:span, project.name, class: 'project-name') title = content_tag(:span, project.name, class: 'project-name')
......
...@@ -36,9 +36,8 @@ class Key < ActiveRecord::Base ...@@ -36,9 +36,8 @@ class Key < ActiveRecord::Base
after_destroy :refresh_user_cache after_destroy :refresh_user_cache
def key=(value) def key=(value)
value&.delete!("\n\r") write_attribute(:key, value.present? ? Gitlab::SSHPublicKey.sanitize(value) : nil)
value.strip! unless value.blank?
write_attribute(:key, value)
@public_key = nil @public_key = nil
end end
...@@ -100,7 +99,7 @@ class Key < ActiveRecord::Base ...@@ -100,7 +99,7 @@ class Key < ActiveRecord::Base
def generate_fingerprint def generate_fingerprint
self.fingerprint = nil self.fingerprint = nil
return unless self.key.present? return unless public_key.valid?
self.fingerprint = public_key.fingerprint self.fingerprint = public_key.fingerprint
end end
......
...@@ -3,8 +3,11 @@ ...@@ -3,8 +3,11 @@
# A note of this type is never resolvable. # A note of this type is never resolvable.
class Note < ActiveRecord::Base class Note < ActiveRecord::Base
extend ActiveModel::Naming extend ActiveModel::Naming
<<<<<<< HEAD
prepend EE::Note prepend EE::Note
=======
>>>>>>> upstream/master
include Participable include Participable
include Mentionable include Mentionable
include Elastic::NotesSearch include Elastic::NotesSearch
......
class ProtectedBranch < ActiveRecord::Base class ProtectedBranch < ActiveRecord::Base
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include ProtectedRef include ProtectedRef
<<<<<<< HEAD
prepend EE::ProtectedRef prepend EE::ProtectedRef
=======
>>>>>>> upstream/master
protected_ref_access_levels :merge, :push protected_ref_access_levels :merge, :push
......
...@@ -180,15 +180,7 @@ class Repository ...@@ -180,15 +180,7 @@ class Repository
end end
def find_branch(name, fresh_repo: true) def find_branch(name, fresh_repo: true)
# Since the Repository object may have in-memory index changes, invalidating the memoized Repository object may raw_repository.find_branch(name, fresh_repo)
# cause unintended side effects. Because finding a branch is a read-only operation, we can safely instantiate
# a new repo here to ensure a consistent state to avoid a libgit2 bug where concurrent access (e.g. via git gc)
# may cause the branch to "disappear" erroneously or have the wrong SHA.
#
# See: https://github.com/libgit2/libgit2/issues/1534 and https://gitlab.com/gitlab-org/gitlab-ce/issues/15392
raw_repo = fresh_repo ? initialize_raw_repository : raw_repository
raw_repo.find_branch(name)
end end
def find_tag(name) def find_tag(name)
...@@ -728,11 +720,11 @@ class Repository ...@@ -728,11 +720,11 @@ class Repository
end end
def branch_names_contains(sha) def branch_names_contains(sha)
refs_contains_sha('branch', sha) raw_repository.branch_names_contains_sha(sha)
end end
def tag_names_contains(sha) def tag_names_contains(sha)
refs_contains_sha('tag', sha) raw_repository.tag_names_contains_sha(sha)
end end
def local_branches def local_branches
......
...@@ -2,8 +2,11 @@ module Ci ...@@ -2,8 +2,11 @@ module Ci
# This class responsible for assigning # This class responsible for assigning
# proper pending build to runner on runner API request # proper pending build to runner on runner API request
class RegisterJobService class RegisterJobService
<<<<<<< HEAD
prepend EE::Ci::RegisterJobService prepend EE::Ci::RegisterJobService
=======
>>>>>>> upstream/master
attr_reader :runner attr_reader :runner
Result = Struct.new(:build, :valid?) Result = Struct.new(:build, :valid?)
......
module Users module Users
class BuildService < BaseService class BuildService < BaseService
<<<<<<< HEAD
prepend ::EE::Users::BuildService prepend ::EE::Users::BuildService
=======
>>>>>>> upstream/master
def initialize(current_user, params = {}) def initialize(current_user, params = {})
@current_user = current_user @current_user = current_user
@params = params.dup @params = params.dup
......
...@@ -23,9 +23,13 @@ ...@@ -23,9 +23,13 @@
%code= liveness_url(token: Gitlab::CurrentSettings.health_check_access_token) %code= liveness_url(token: Gitlab::CurrentSettings.health_check_access_token)
%li %li
%code= metrics_url(token: Gitlab::CurrentSettings.health_check_access_token) %code= metrics_url(token: Gitlab::CurrentSettings.health_check_access_token)
<<<<<<< HEAD
- if Gitlab::Geo.secondary? - if Gitlab::Geo.secondary?
%li %li
%code= health_check_url(token: Gitlab::CurrentSettings.health_check_access_token, checks: :geo) %code= health_check_url(token: Gitlab::CurrentSettings.health_check_access_token, checks: :geo)
=======
>>>>>>> upstream/master
%hr %hr
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
......
...@@ -44,7 +44,10 @@ ...@@ -44,7 +44,10 @@
= sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked') = sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked')
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked') = sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
-# EE-specific start -# EE-specific start
<<<<<<< HEAD
= render 'ci/variables/environment_scope', form_field: form_field, variable: variable = render 'ci/variables/environment_scope', form_field: form_field, variable: variable
=======
>>>>>>> upstream/master
-# EE-specific end -# EE-specific end
%button.js-row-remove-button.ci-variable-row-remove-button{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') } %button.js-row-remove-button.ci-variable-row-remove-button{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') }
= icon('minus-circle') = icon('minus-circle')
...@@ -2,7 +2,11 @@ ...@@ -2,7 +2,11 @@
%div %div
- if Gitlab::CurrentSettings.help_page_text.present? - if Gitlab::CurrentSettings.help_page_text.present?
<<<<<<< HEAD
= markdown(Gitlab::CurrentSettings.help_page_text) = markdown(Gitlab::CurrentSettings.help_page_text)
=======
= markdown_field(Gitlab::CurrentSettings.current_application_settings, :help_page_text)
>>>>>>> upstream/master
%hr %hr
%h1 %h1
......
...@@ -28,11 +28,14 @@ ...@@ -28,11 +28,14 @@
- if Gitlab::CurrentSettings.sign_in_text.present? - if Gitlab::CurrentSettings.sign_in_text.present?
= markdown_field(Gitlab::CurrentSettings.current_application_settings, :sign_in_text) = markdown_field(Gitlab::CurrentSettings.current_application_settings, :sign_in_text)
<<<<<<< HEAD
- if Gitlab::CurrentSettings.help_text.present? - if Gitlab::CurrentSettings.help_text.present?
%h3 Need help? %h3 Need help?
%hr %hr
%p.slead %p.slead
= markdown(Gitlab::CurrentSettings.help_text) = markdown(Gitlab::CurrentSettings.help_text)
=======
>>>>>>> upstream/master
%hr.footer-fixed %hr.footer-fixed
.container.footer-container .container.footer-container
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
= link_to profile_account_path do = link_to profile_account_path do
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
#{ _('Account') } #{ _('Account') }
<<<<<<< HEAD
- if Gitlab::CurrentSettings.should_check_namespace_plan? - if Gitlab::CurrentSettings.should_check_namespace_plan?
= nav_link(controller: :billings) do = nav_link(controller: :billings) do
= link_to profile_billings_path do = link_to profile_billings_path do
...@@ -40,6 +41,8 @@ ...@@ -40,6 +41,8 @@
= link_to profile_billings_path do = link_to profile_billings_path do
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
#{ _('Billing') } #{ _('Billing') }
=======
>>>>>>> upstream/master
- if Gitlab::CurrentSettings.user_oauth_applications? - if Gitlab::CurrentSettings.user_oauth_applications?
= nav_link(controller: 'oauth/applications') do = nav_link(controller: 'oauth/applications') do
= link_to applications_profile_path do = link_to applications_profile_path do
......
---
title: Add Colors to GitLab Flavored Markdown
merge_request: 16095
author: Tony Rom <thetonyrom@gmail.com>
type: added
---
title: Show coverage to two decimal points in coverage badge
merge_request: 10083
author: Jeff Stubler
type: changed
---
title: Sanitize extra blank spaces used when uploading a SSH key
merge_request: 40552
author:
type: fixed
---
title: Fix forking projects when no restricted visibility levels are defined applicationwide
merge_request: 16881
author:
type: fixed
---
title: Trigger change event on filename input when file template is applied
merge_request: 16911
author: Sebastian Klingler
type: fixed
# Copy of 20180202111106 - this one should run before 20171207150343 to fix issues related to
# the removal of groups with labels.
class RemoveProjectLabelsGroupIdCopy < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# rubocop:disable Migration/UpdateColumnInBatches
update_column_in_batches(:labels, :group_id, nil) do |table, query|
query.where(table[:type].eq('ProjectLabel').and(table[:group_id].not_eq(nil)))
end
# rubocop:enable Migration/UpdateColumnInBatches
end
def down
end
end
...@@ -13,7 +13,7 @@ override certain values. ...@@ -13,7 +13,7 @@ override certain values.
Variable | Type | Description Variable | Type | Description
-------- | ---- | ----------- -------- | ---- | -----------
`GITLAB_CDN_HOST` | string | Sets the hostname for a CDN to serve static assets (e.g. `mycdnsubdomain.fictional-cdn.com`) `GITLAB_CDN_HOST` | string | Sets the base URL for a CDN to serve static assets (e.g. `//mycdnsubdomain.fictional-cdn.com`)
`GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation `GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation
`GITLAB_HOST` | string | The full URL of the GitLab server (including `http://` or `https://`) `GITLAB_HOST` | string | The full URL of the GitLab server (including `http://` or `https://`)
`RAILS_ENV` | string | The Rails environment; can be one of `production`, `development`, `staging` or `test` `RAILS_ENV` | string | The Rails environment; can be one of `production`, `development`, `staging` or `test`
......
...@@ -254,7 +254,7 @@ GFM will recognize the following: ...@@ -254,7 +254,7 @@ GFM will recognize the following:
| `@user_name` | specific user | | `@user_name` | specific user |
| `@group_name` | specific group | | `@group_name` | specific group |
| `@all` | entire team | | `@all` | entire team |
| `#123` | issue | | `#12345` | issue |
| `!123` | merge request | | `!123` | merge request |
| `$123` | snippet | | `$123` | snippet |
| `&123` | epic | | `&123` | epic |
...@@ -382,6 +382,45 @@ _Be advised that KaTeX only supports a [subset][katex-subset] of LaTeX._ ...@@ -382,6 +382,45 @@ _Be advised that KaTeX only supports a [subset][katex-subset] of LaTeX._
>**Note:** >**Note:**
This also works for the asciidoctor `:stem: latexmath`. For details see the [asciidoctor user manual][asciidoctor-manual]. This also works for the asciidoctor `:stem: latexmath`. For details see the [asciidoctor user manual][asciidoctor-manual].
### Colors
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#colors
It is possible to have color written in HEX, RGB or HSL format rendered with a color indicator.
Color written inside backticks will be followed by a color "chip".
Examples:
`#F00`
`#F00A`
`#FF0000`
`#FF0000AA`
`RGB(0,255,0)`
`RGB(0%,100%,0%)`
`RGBA(0,255,0,0.7)`
`HSL(540,70%,50%)`
`HSLA(540,70%,50%,0.7)`
Becomes:
`#F00`
`#F00A`
`#FF0000`
`#FF0000AA`
`RGB(0,255,0)`
`RGB(0%,100%,0%)`
`RGBA(0,255,0,0.7)`
`HSL(540,70%,50%)`
`HSLA(540,70%,50%,0.7)`
#### Supported formats:
* HEX: `` `#RGB[A]` `` or `` `#RRGGBB[AA]` ``
* RGB: `` `RGB[A](R, G, B[, A])` ``
* HSL: `` `HSL[A](H, S, L[, A])` ``
### Mermaid ### Mermaid
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15107) in > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15107) in
......
...@@ -46,7 +46,7 @@ namespace that started the import process. ...@@ -46,7 +46,7 @@ namespace that started the import process.
The importer will also import branches on forks of projects related to open pull The importer will also import branches on forks of projects related to open pull
requests. These branches will be imported with a naming scheme similar to requests. These branches will be imported with a naming scheme similar to
GH-SHA-Username/Pull-Request-number/fork-name/branch. This may lead to a discrepency GH-SHA-Username/Pull-Request-number/fork-name/branch. This may lead to a discrepancy
in branches compared to the GitHub Repository. in branches compared to the GitHub Repository.
For a more technical description and an overview of the architecture you can For a more technical description and an overview of the architecture you can
......
module API module API
module Helpers module Helpers
module Runner module Runner
<<<<<<< HEAD
prepend EE::API::Helpers::Runner prepend EE::API::Helpers::Runner
=======
>>>>>>> upstream/master
JOB_TOKEN_HEADER = 'HTTP_JOB_TOKEN'.freeze JOB_TOKEN_HEADER = 'HTTP_JOB_TOKEN'.freeze
JOB_TOKEN_PARAM = :token JOB_TOKEN_PARAM = :token
UPDATE_RUNNER_EVERY = 10 * 60 UPDATE_RUNNER_EVERY = 10 * 60
......
module Banzai
module ColorParser
ALPHA = /0(?:\.\d+)?|\.\d+|1(?:\.0+)?/ # 0.0..1.0
PERCENTS = /(?:\d{1,2}|100)%/ # 00%..100%
ALPHA_CHANNEL = /(?:,\s*(?:#{ALPHA}|#{PERCENTS}))?/
BITS = /\d{1,2}|1\d\d|2(?:[0-4]\d|5[0-5])/ # 00..255
DEGS = /-?\d+(?:deg)?/i # [-]digits[deg]
RADS = /-?(?:\d+(?:\.\d+)?|\.\d+)rad/i # [-](digits[.digits] OR .digits)rad
HEX_FORMAT = /\#(?:\h{3}|\h{4}|\h{6}|\h{8})/
RGB_FORMAT = %r{
(?:rgba?
\(
(?:
(?:(?:#{BITS},\s*){2}#{BITS})
|
(?:(?:#{PERCENTS},\s*){2}#{PERCENTS})
)
#{ALPHA_CHANNEL}
\)
)
}xi
HSL_FORMAT = %r{
(?:hsla?
\(
(?:#{DEGS}|#{RADS}),\s*#{PERCENTS},\s*#{PERCENTS}
#{ALPHA_CHANNEL}
\)
)
}xi
FORMATS = [HEX_FORMAT, RGB_FORMAT, HSL_FORMAT].freeze
COLOR_FORMAT = /\A(#{Regexp.union(FORMATS)})\z/ix
# Public: Analyzes whether the String is a color code.
#
# text - The String to be parsed.
#
# Returns the recognized color String or nil if none was found.
def self.parse(text)
text if COLOR_FORMAT =~ text
end
end
end
module Banzai
module Filter
# HTML filter that renders `color` followed by a color "chip".
#
class ColorFilter < HTML::Pipeline::Filter
COLOR_CHIP_CLASS = 'gfm-color_chip'.freeze
def call
doc.css('code').each do |node|
color = ColorParser.parse(node.content)
node << color_chip(color) if color
end
doc
end
private
def color_chip(color)
checkerboard = doc.document.create_element('span', class: COLOR_CHIP_CLASS)
chip = doc.document.create_element('span', style: inline_styles(color: color))
checkerboard << chip
end
def inline_styles(color:)
"background-color: #{color};"
end
end
end
end
...@@ -7,6 +7,7 @@ module Banzai ...@@ -7,6 +7,7 @@ module Banzai
Filter::SanitizationFilter, Filter::SanitizationFilter,
Filter::EmojiFilter, Filter::EmojiFilter,
Filter::ColorFilter,
Filter::AutolinkFilter, Filter::AutolinkFilter,
Filter::ExternalLinkFilter Filter::ExternalLinkFilter
] ]
......
...@@ -14,6 +14,7 @@ module Banzai ...@@ -14,6 +14,7 @@ module Banzai
Filter::SyntaxHighlightFilter, Filter::SyntaxHighlightFilter,
Filter::MathFilter, Filter::MathFilter,
Filter::ColorFilter,
Filter::MermaidFilter, Filter::MermaidFilter,
Filter::VideoLinkFilter, Filter::VideoLinkFilter,
Filter::ImageLazyLoadFilter, Filter::ImageLazyLoadFilter,
......
...@@ -14,8 +14,11 @@ module Gitlab ...@@ -14,8 +14,11 @@ module Gitlab
DEFAULT_SCOPES = [:api].freeze DEFAULT_SCOPES = [:api].freeze
class << self class << self
<<<<<<< HEAD
prepend EE::Gitlab::Auth prepend EE::Gitlab::Auth
=======
>>>>>>> upstream/master
def find_for_git_client(login, password, project:, ip:) def find_for_git_client(login, password, project:, ip:)
raise "Must provide an IP for rate limiting" if ip.nil? raise "Must provide an IP for rate limiting" if ip.nil?
......
...@@ -23,7 +23,7 @@ module Gitlab ...@@ -23,7 +23,7 @@ module Gitlab
@coverage ||= raw_coverage @coverage ||= raw_coverage
return unless @coverage return unless @coverage
@coverage.to_i @coverage.to_f.round(2)
end end
def metadata def metadata
......
...@@ -25,7 +25,7 @@ module Gitlab ...@@ -25,7 +25,7 @@ module Gitlab
end end
def value_text def value_text
@status ? "#{@status}%" : 'unknown' @status ? ("%.2f%%" % @status) : 'unknown'
end end
def key_width def key_width
...@@ -33,7 +33,7 @@ module Gitlab ...@@ -33,7 +33,7 @@ module Gitlab
end end
def value_width def value_width
@status ? 36 : 58 @status ? 54 : 58
end end
def value_color def value_color
......
# Gitaly note: JV: no RPC's here.
module Gitlab module Gitlab
module Git module Git
class Branch < Ref class Branch < Ref
......
...@@ -1363,20 +1363,23 @@ module Gitlab ...@@ -1363,20 +1363,23 @@ module Gitlab
raise CommandError.new(e) raise CommandError.new(e)
end end
def refs_contains_sha(ref_type, sha) def branch_names_contains_sha(sha)
args = %W(#{ref_type} --contains #{sha}) gitaly_migrate(:branch_names_contains_sha) do |is_enabled|
names = run_git(args).first if is_enabled
gitaly_ref_client.branch_names_contains_sha(sha)
if names.respond_to?(:split) else
names = names.split("\n").map(&:strip) refs_contains_sha(:branch, sha)
end
names.each do |name| end
name.slice! '* '
end end
names def tag_names_contains_sha(sha)
gitaly_migrate(:tag_names_contains_sha) do |is_enabled|
if is_enabled
gitaly_ref_client.tag_names_contains_sha(sha)
else else
[] refs_contains_sha(:tag, sha)
end
end end
end end
...@@ -1454,6 +1457,21 @@ module Gitlab ...@@ -1454,6 +1457,21 @@ module Gitlab
end end
end end
def refs_contains_sha(ref_type, sha)
args = %W(#{ref_type} --contains #{sha})
names = run_git(args).first
return [] unless names.respond_to?(:split)
names = names.split("\n").map(&:strip)
names.each do |name|
name.slice! '* '
end
names
end
def rugged_write_config(full_path:) def rugged_write_config(full_path:)
rugged.config['gitlab.fullpath'] = full_path rugged.config['gitlab.fullpath'] = full_path
end end
......
# Gitaly note: JV: no RPC's here.
#
module Gitlab module Gitlab
module Git module Git
class Tag < Ref class Tag < Ref
......
...@@ -145,6 +145,32 @@ module Gitlab ...@@ -145,6 +145,32 @@ module Gitlab
raise Gitlab::Git::Repository::GitError, response.git_error if response.git_error.present? raise Gitlab::Git::Repository::GitError, response.git_error if response.git_error.present?
end end
# Limit: 0 implies no limit, thus all tag names will be returned
def tag_names_contains_sha(sha, limit: 0)
request = Gitaly::ListTagNamesContainingCommitRequest.new(
repository: @gitaly_repo,
commit_id: sha,
limit: limit
)
stream = GitalyClient.call(@repository.storage, :ref_service, :list_tag_names_containing_commit, request)
consume_ref_contains_sha_response(stream, :tag_names)
end
# Limit: 0 implies no limit, thus all tag names will be returned
def branch_names_contains_sha(sha, limit: 0)
request = Gitaly::ListBranchNamesContainingCommitRequest.new(
repository: @gitaly_repo,
commit_id: sha,
limit: limit
)
stream = GitalyClient.call(@repository.storage, :ref_service, :list_branch_names_containing_commit, request)
consume_ref_contains_sha_response(stream, :branch_names)
end
private private
def consume_refs_response(response) def consume_refs_response(response)
...@@ -215,6 +241,13 @@ module Gitlab ...@@ -215,6 +241,13 @@ module Gitlab
Gitlab::Git::Commit.decorate(@repository, hash) Gitlab::Git::Commit.decorate(@repository, hash)
end end
def consume_ref_contains_sha_response(stream, collection_name)
stream.each_with_object([]) do |response, array|
encoded_names = response.send(collection_name).map { |b| Gitlab::Git.ref_name(b) } # rubocop:disable GitlabSecurity/PublicSend
array.concat(encoded_names)
end
end
def invalid_ref!(message) def invalid_ref!(message)
raise Gitlab::Git::Repository::InvalidRef.new(message) raise Gitlab::Git::Repository::InvalidRef.new(message)
end end
......
...@@ -21,6 +21,22 @@ module Gitlab ...@@ -21,6 +21,22 @@ module Gitlab
technology(name)&.supported_sizes technology(name)&.supported_sizes
end end
def self.sanitize(key_content)
ssh_type, *parts = key_content.strip.split
return key_content if parts.empty?
parts.each_with_object("#{ssh_type} ").with_index do |(part, content), index|
content << part
if Gitlab::SSHPublicKey.new(content).valid?
break [content, parts[index + 1]].compact.join(' ') # Add the comment part if present
elsif parts.size == index + 1 # return original content if we've reached the last element
break key_content
end
end
end
attr_reader :key_text, :key attr_reader :key_text, :key
# Unqualified MD5 fingerprint for compatibility # Unqualified MD5 fingerprint for compatibility
...@@ -37,23 +53,23 @@ module Gitlab ...@@ -37,23 +53,23 @@ module Gitlab
end end
def valid? def valid?
key.present? key.present? && bits && technology.supported_sizes.include?(bits)
end end
def type def type
technology.name if valid? technology.name if key.present?
end end
def bits def bits
return unless valid? return if key.blank?
case type case type
when :rsa when :rsa
key.n.num_bits key.n&.num_bits
when :dsa when :dsa
key.p.num_bits key.p&.num_bits
when :ecdsa when :ecdsa
key.group.order.num_bits key.group.order&.num_bits
when :ed25519 when :ed25519
256 256
else else
......
...@@ -59,7 +59,7 @@ module Gitlab ...@@ -59,7 +59,7 @@ module Gitlab
def allowed_levels def allowed_levels
restricted_levels = Gitlab::CurrentSettings.restricted_visibility_levels restricted_levels = Gitlab::CurrentSettings.restricted_visibility_levels
self.values - restricted_levels self.values - Array(restricted_levels)
end end
def closest_allowed_level(target_level) def closest_allowed_level(target_level)
......
...@@ -5,6 +5,10 @@ FactoryBot.define do ...@@ -5,6 +5,10 @@ FactoryBot.define do
title title
key { Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate + ' dummy@gitlab.com' } key { Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate + ' dummy@gitlab.com' }
factory :key_without_comment do
key { Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate }
end
factory :deploy_key, class: 'DeployKey' factory :deploy_key, class: 'DeployKey'
factory :personal_key do factory :personal_key do
......
...@@ -261,6 +261,10 @@ describe 'GitLab Markdown' do ...@@ -261,6 +261,10 @@ describe 'GitLab Markdown' do
it 'includes VideoLinkFilter' do it 'includes VideoLinkFilter' do
expect(doc).to parse_video_links expect(doc).to parse_video_links
end end
it 'includes ColorFilter' do
expect(doc).to parse_colors
end
end end
context 'wiki pipeline' do context 'wiki pipeline' do
...@@ -323,6 +327,10 @@ describe 'GitLab Markdown' do ...@@ -323,6 +327,10 @@ describe 'GitLab Markdown' do
it 'includes VideoLinkFilter' do it 'includes VideoLinkFilter' do
expect(doc).to parse_video_links expect(doc).to parse_video_links
end end
it 'includes ColorFilter' do
expect(doc).to parse_colors
end
end end
# Fake a `current_user` helper # Fake a `current_user` helper
......
...@@ -18,7 +18,7 @@ feature 'test coverage badge' do ...@@ -18,7 +18,7 @@ feature 'test coverage badge' do
show_test_coverage_badge show_test_coverage_badge
expect_coverage_badge('95%') expect_coverage_badge('95.00%')
end end
scenario 'user requests coverage badge for specific job' do scenario 'user requests coverage badge for specific job' do
...@@ -30,7 +30,7 @@ feature 'test coverage badge' do ...@@ -30,7 +30,7 @@ feature 'test coverage badge' do
show_test_coverage_badge(job: 'coverage') show_test_coverage_badge(job: 'coverage')
expect_coverage_badge('85%') expect_coverage_badge('85.00%')
end end
scenario 'user requests coverage badge for pipeline without coverage' do scenario 'user requests coverage badge for pipeline without coverage' do
......
...@@ -288,6 +288,18 @@ However the wrapping tags cannot be mixed as such: ...@@ -288,6 +288,18 @@ However the wrapping tags cannot be mixed as such:
![My Video](/assets/videos/gitlab-demo.mp4) ![My Video](/assets/videos/gitlab-demo.mp4)
### Colors
`#F00`
`#F00A`
`#FF0000`
`#FF0000AA`
`RGB(0,255,0)`
`RGB(0%,100%,0%)`
`RGBA(0,255,0,0.7)`
`HSL(540,70%,50%)`
`HSLA(540,70%,50%,0.7)`
### Mermaid ### Mermaid
> If this is not rendered correctly, see > If this is not rendered correctly, see
......
...@@ -130,16 +130,25 @@ describe('GfmAutoComplete', function () { ...@@ -130,16 +130,25 @@ describe('GfmAutoComplete', function () {
}); });
describe('should not match special sequences', () => { describe('should not match special sequences', () => {
const ShouldNotBeFollowedBy = flags.concat(['\x00', '\x10', '\x3f', '\n', ' ']); const shouldNotBeFollowedBy = flags.concat(['\x00', '\x10', '\x3f', '\n', ' ']);
const shouldNotBePrependedBy = ['`'];
flagsUseDefaultMatcher.forEach((atSign) => { flagsUseDefaultMatcher.forEach((atSign) => {
ShouldNotBeFollowedBy.forEach((followedSymbol) => { shouldNotBeFollowedBy.forEach((followedSymbol) => {
const seq = atSign + followedSymbol; const seq = atSign + followedSymbol;
it(`should not match "${seq}"`, () => { it(`should not match "${seq}"`, () => {
expect(defaultMatcher(atwhoInstance, atSign, seq)).toBe(null); expect(defaultMatcher(atwhoInstance, atSign, seq)).toBe(null);
}); });
}); });
shouldNotBePrependedBy.forEach((prependedSymbol) => {
const seq = prependedSymbol + atSign;
it(`should not match "${seq}"`, () => {
expect(defaultMatcher(atwhoInstance, atSign, seq)).toBe(null);
});
});
}); });
}); });
}); });
......
require 'spec_helper'
describe Banzai::ColorParser do
describe '.parse' do
context 'HEX format' do
[
'#abc', '#ABC',
'#d2d2d2', '#D2D2D2',
'#123a', '#123A',
'#123456aa', '#123456AA'
].each do |color|
it "parses the valid hex color #{color}" do
expect(subject.parse(color)).to eq(color)
end
end
[
'#', '#1', '#12', '#12g', '#12G',
'#12345', '#r2r2r2', '#R2R2R2', '#1234567',
'# 123', '# 1234', '# 123456', '# 12345678',
'#1 2 3', '#123 4', '#12 34 56', '#123456 78'
].each do |color|
it "does not parse the invalid hex color #{color}" do
expect(subject.parse(color)).to be_nil
end
end
end
context 'RGB format' do
[
'rgb(0,0,0)', 'rgb(255,255,255)',
'rgb(0, 0, 0)', 'RGB(0,0,0)',
'rgb(0,0,0,0)', 'rgb(0,0,0,0.0)', 'rgb(0,0,0,.0)',
'rgb(0,0,0, 0)', 'rgb(0,0,0, 0.0)', 'rgb(0,0,0, .0)',
'rgb(0,0,0,1)', 'rgb(0,0,0,1.0)',
'rgba(0,0,0)', 'rgba(0,0,0,0)', 'RGBA(0,0,0)',
'rgb(0%,0%,0%)', 'rgba(0%,0%,0%,0%)'
].each do |color|
it "parses the valid rgb color #{color}" do
expect(subject.parse(color)).to eq(color)
end
end
[
'FOOrgb(0,0,0)', 'rgb(0,0,0)BAR',
'rgb(0,0,-1)', 'rgb(0,0,-0)', 'rgb(0,0,256)',
'rgb(0,0,0,-0.1)', 'rgb(0,0,0,-0.0)', 'rgb(0,0,0,-.1)',
'rgb(0,0,0,1.1)', 'rgb(0,0,0,2)',
'rgba(0,0,0,)', 'rgba(0,0,0,0.)', 'rgba(0,0,0,1.)',
'rgb(0,0,0%)', 'rgb(101%,0%,0%)'
].each do |color|
it "does not parse the invalid rgb color #{color}" do
expect(subject.parse(color)).to be_nil
end
end
end
context 'HSL format' do
[
'hsl(0,0%,0%)', 'hsl(0,100%,100%)',
'hsl(540,0%,0%)', 'hsl(-720,0%,0%)',
'hsl(0deg,0%,0%)', 'hsl(0DEG,0%,0%)',
'hsl(0, 0%, 0%)', 'HSL(0,0%,0%)',
'hsl(0,0%,0%,0)', 'hsl(0,0%,0%,0.0)', 'hsl(0,0%,0%,.0)',
'hsl(0,0%,0%, 0)', 'hsl(0,0%,0%, 0.0)', 'hsl(0,0%,0%, .0)',
'hsl(0,0%,0%,1)', 'hsl(0,0%,0%,1.0)',
'hsla(0,0%,0%)', 'hsla(0,0%,0%,0)', 'HSLA(0,0%,0%)',
'hsl(1rad,0%,0%)', 'hsl(1.1rad,0%,0%)', 'hsl(.1rad,0%,0%)',
'hsl(-1rad,0%,0%)', 'hsl(1RAD,0%,0%)'
].each do |color|
it "parses the valid hsl color #{color}" do
expect(subject.parse(color)).to eq(color)
end
end
[
'hsl(+0,0%,0%)', 'hsl(0,0,0%)', 'hsl(0,0%,0)', 'hsl(0 deg,0%,0%)',
'hsl(0,-0%,0%)', 'hsl(0,101%,0%)', 'hsl(0,-1%,0%)',
'hsl(0,0%,0%,-0.1)', 'hsl(0,0%,0%,-.1)',
'hsl(0,0%,0%,1.1)', 'hsl(0,0%,0%,2)',
'hsl(0,0%,0%,)', 'hsl(0,0%,0%,0.)', 'hsl(0,0%,0%,1.)',
'hsl(deg,0%,0%)', 'hsl(rad,0%,0%)'
].each do |color|
it "does not parse the invalid hsl color #{color}" do
expect(subject.parse(color)).to be_nil
end
end
end
end
end
require 'spec_helper'
describe Banzai::Filter::ColorFilter, lib: true do
include FilterSpecHelper
let(:color) { '#F00' }
let(:color_chip_selector) { 'code > span.gfm-color_chip > span' }
['#123', '#1234', '#123456', '#12345678',
'rgb(0,0,0)', 'RGB(0, 0, 0)', 'rgba(0,0,0,1)', 'RGBA(0,0,0,0.7)',
'hsl(270,30%,50%)', 'HSLA(270, 30%, 50%, .7)'].each do |color|
it "inserts color chip for supported color format #{color}" do
content = code_tag(color)
doc = filter(content)
color_chip = doc.at_css(color_chip_selector)
expect(color_chip.content).to be_empty
expect(color_chip.parent[:class]).to eq 'gfm-color_chip'
expect(color_chip[:style]).to eq "background-color: #{color};"
end
end
it 'ignores valid color code without backticks(code tags)' do
doc = filter(color)
expect(doc.css('span.gfm-color_chip').size).to be_zero
end
it 'ignores valid color code with prepended space' do
content = code_tag(' ' + color)
doc = filter(content)
expect(doc.css(color_chip_selector).size).to be_zero
end
it 'ignores valid color code with appended space' do
content = code_tag(color + ' ')
doc = filter(content)
expect(doc.css(color_chip_selector).size).to be_zero
end
it 'ignores valid color code surrounded by spaces' do
content = code_tag(' ' + color + ' ')
doc = filter(content)
expect(doc.css(color_chip_selector).size).to be_zero
end
it 'ignores invalid color code' do
invalid_color = '#BAR'
content = code_tag(invalid_color)
doc = filter(content)
expect(doc.css(color_chip_selector).size).to be_zero
end
def code_tag(string)
"<code>#{string}</code>"
end
end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Badge::Coverage::Template do describe Gitlab::Badge::Coverage::Template do
let(:badge) { double(entity: 'coverage', status: 90) } let(:badge) { double(entity: 'coverage', status: 90.00) }
let(:template) { described_class.new(badge) } let(:template) { described_class.new(badge) }
describe '#key_text' do describe '#key_text' do
...@@ -13,7 +13,17 @@ describe Gitlab::Badge::Coverage::Template do ...@@ -13,7 +13,17 @@ describe Gitlab::Badge::Coverage::Template do
describe '#value_text' do describe '#value_text' do
context 'when coverage is known' do context 'when coverage is known' do
it 'returns coverage percentage' do it 'returns coverage percentage' do
expect(template.value_text).to eq '90%' expect(template.value_text).to eq '90.00%'
end
end
context 'when coverage is known to many digits' do
before do
allow(badge).to receive(:status).and_return(92.349)
end
it 'returns rounded coverage percentage' do
expect(template.value_text).to eq '92.35%'
end end
end end
...@@ -37,7 +47,7 @@ describe Gitlab::Badge::Coverage::Template do ...@@ -37,7 +47,7 @@ describe Gitlab::Badge::Coverage::Template do
describe '#value_width' do describe '#value_width' do
context 'when coverage is known' do context 'when coverage is known' do
it 'is narrower when coverage is known' do it 'is narrower when coverage is known' do
expect(template.value_width).to eq 36 expect(template.value_width).to eq 54
end end
end end
...@@ -113,7 +123,7 @@ describe Gitlab::Badge::Coverage::Template do ...@@ -113,7 +123,7 @@ describe Gitlab::Badge::Coverage::Template do
describe '#width' do describe '#width' do
context 'when coverage is known' do context 'when coverage is known' do
it 'returns the key width plus value width' do it 'returns the key width plus value width' do
expect(template.width).to eq 98 expect(template.width).to eq 116
end end
end end
......
...@@ -26,6 +26,7 @@ describe Gitlab::CurrentSettings do ...@@ -26,6 +26,7 @@ describe Gitlab::CurrentSettings do
allow(ActiveRecord::Base.connection).to receive(:active?).and_return(true) allow(ActiveRecord::Base.connection).to receive(:active?).and_return(true)
allow(ActiveRecord::Base.connection).to receive(:table_exists?).and_call_original allow(ActiveRecord::Base.connection).to receive(:table_exists?).and_call_original
allow(ActiveRecord::Base.connection).to receive(:table_exists?).with('application_settings').and_return(true) allow(ActiveRecord::Base.connection).to receive(:table_exists?).with('application_settings').and_return(true)
<<<<<<< HEAD
end end
# This method returns the ::ApplicationSetting.defaults hash # This method returns the ::ApplicationSetting.defaults hash
...@@ -34,6 +35,8 @@ describe Gitlab::CurrentSettings do ...@@ -34,6 +35,8 @@ describe Gitlab::CurrentSettings do
defaults = ::ApplicationSetting.defaults defaults = ::ApplicationSetting.defaults
ar_wrapped_defaults = ::ApplicationSetting.new(defaults).attributes ar_wrapped_defaults = ::ApplicationSetting.new(defaults).attributes
ar_wrapped_defaults.slice(*defaults.keys) ar_wrapped_defaults.slice(*defaults.keys)
=======
>>>>>>> upstream/master
end end
it 'attempts to use cached values first' do it 'attempts to use cached values first' do
......
...@@ -1162,7 +1162,8 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -1162,7 +1162,8 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'when Gitaly find_branch feature is disabled', :skip_gitaly_mock do context 'when Gitaly find_branch feature is disabled', :skip_gitaly_mock do
it_behaves_like 'finding a branch' it_behaves_like 'finding a branch'
it 'should reload Rugged::Repository and return master' do context 'force_reload is true' do
it 'should reload Rugged::Repository' do
expect(Rugged::Repository).to receive(:new).twice.and_call_original expect(Rugged::Repository).to receive(:new).twice.and_call_original
repository.find_branch('master') repository.find_branch('master')
...@@ -1172,6 +1173,18 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -1172,6 +1173,18 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(branch.name).to eq('master') expect(branch.name).to eq('master')
end end
end end
context 'force_reload is false' do
it 'should not reload Rugged::Repository' do
expect(Rugged::Repository).to receive(:new).once.and_call_original
branch = repository.find_branch('master', force_reload: false)
expect(branch).to be_a_kind_of(Gitlab::Git::Branch)
expect(branch.name).to eq('master')
end
end
end
end end
describe '#ref_name_for_sha' do describe '#ref_name_for_sha' do
......
...@@ -37,6 +37,41 @@ describe Gitlab::SSHPublicKey, lib: true do ...@@ -37,6 +37,41 @@ describe Gitlab::SSHPublicKey, lib: true do
end end
end end
describe '.sanitize(key_content)' do
let(:content) { build(:key).key }
context 'when key has blank space characters' do
it 'removes the extra blank space characters' do
unsanitized = content.insert(100, "\n")
.insert(40, "\r\n")
.insert(30, ' ')
sanitized = described_class.sanitize(unsanitized)
_, body = sanitized.split
expect(sanitized).not_to eq(unsanitized)
expect(body).not_to match(/\s/)
end
end
context "when key doesn't have blank space characters" do
it "doesn't modify the content" do
sanitized = described_class.sanitize(content)
expect(sanitized).to eq(content)
end
end
context "when key is invalid" do
it 'returns the original content' do
unsanitized = "ssh-foo any content=="
sanitized = described_class.sanitize(unsanitized)
expect(sanitized).to eq(unsanitized)
end
end
end
describe '#valid?' do describe '#valid?' do
subject { public_key } subject { public_key }
......
...@@ -156,10 +156,14 @@ describe Gitlab::UsageData do ...@@ -156,10 +156,14 @@ describe Gitlab::UsageData do
subject { described_class.license_usage_data } subject { described_class.license_usage_data }
it "gathers license data" do it "gathers license data" do
<<<<<<< HEAD
license = ::License.current license = ::License.current
expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid) expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid)
expect(subject[:license_md5]).to eq(Digest::MD5.hexdigest(license.data)) expect(subject[:license_md5]).to eq(Digest::MD5.hexdigest(license.data))
=======
expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid)
>>>>>>> upstream/master
expect(subject[:version]).to eq(Gitlab::VERSION) expect(subject[:version]).to eq(Gitlab::VERSION)
expect(subject[:licensee]).to eq(license.licensee) expect(subject[:licensee]).to eq(license.licensee)
expect(subject[:active_user_count]).to eq(User.active.count) expect(subject[:active_user_count]).to eq(User.active.count)
......
...@@ -57,6 +57,15 @@ describe Gitlab::VisibilityLevel do ...@@ -57,6 +57,15 @@ describe Gitlab::VisibilityLevel do
expect(described_class.allowed_levels) expect(described_class.allowed_levels)
.to contain_exactly(described_class::PRIVATE, described_class::PUBLIC) .to contain_exactly(described_class::PRIVATE, described_class::PUBLIC)
end end
it 'returns all levels when no visibility level was set' do
allow(described_class)
.to receive_message_chain('current_application_settings.restricted_visibility_levels')
.and_return(nil)
expect(described_class.allowed_levels)
.to contain_exactly(described_class::PRIVATE, described_class::INTERNAL, described_class::PUBLIC)
end
end end
describe '.closest_allowed_level' do describe '.closest_allowed_level' do
......
...@@ -72,15 +72,52 @@ describe Key, :mailer do ...@@ -72,15 +72,52 @@ describe Key, :mailer do
expect(build(:key)).to be_valid expect(build(:key)).to be_valid
end end
it 'accepts a key with newline charecters after stripping them' do it 'rejects the unfingerprintable key (not a key)' do
key = build(:key) expect(build(:key, key: 'ssh-rsa an-invalid-key==')).not_to be_valid
key.key = key.key.insert(100, "\n") end
key.key = key.key.insert(40, "\r\n")
where(:factory, :chars, :expected_sections) do
[
[:key, ["\n", "\r\n"], 3],
[:key, [' ', ' '], 3],
[:key_without_comment, [' ', ' '], 2]
]
end
with_them do
let!(:key) { create(factory) }
let!(:original_fingerprint) { key.fingerprint }
it 'accepts a key with blank space characters after stripping them' do
modified_key = key.key.insert(100, chars.first).insert(40, chars.last)
_, content = modified_key.split
key.update!(key: modified_key)
expect(key).to be_valid expect(key).to be_valid
expect(key.key.split.size).to eq(expected_sections)
expect(content).not_to match(/\s/)
expect(original_fingerprint).to eq(key.fingerprint)
end
end
end end
it 'rejects the unfingerprintable key (not a key)' do context 'validate size' do
expect(build(:key, key: 'ssh-rsa an-invalid-key==')).not_to be_valid where(:key_content, :result) do
[
[Spec::Support::Helpers::KeyGeneratorHelper.new(512).generate, false],
[Spec::Support::Helpers::KeyGeneratorHelper.new(8192).generate, false],
[Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate, true]
]
end
with_them do
it 'validates the size of the key' do
key = build(:key, key: key_content)
expect(key.valid?).to eq(result)
end
end end
end end
......
...@@ -36,6 +36,10 @@ describe Repository do ...@@ -36,6 +36,10 @@ describe Repository do
end end
describe '#branch_names_contains' do describe '#branch_names_contains' do
shared_examples '#branch_names_contains' do
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.to include('master') }
...@@ -51,13 +55,32 @@ describe Repository do ...@@ -51,13 +55,32 @@ describe Repository do
end 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 describe '#tag_names_contains' do
shared_examples '#tag_names_contains' do
subject { repository.tag_names_contains(sample_commit.id) } subject { repository.tag_names_contains(sample_commit.id) }
it { is_expected.to include('v1.1.0') } it { is_expected.to include('v1.1.0') }
it { is_expected.not_to include('v1.0.0') } it { is_expected.not_to include('v1.0.0') }
end end
context 'when gitaly is enabled' do
it_behaves_like '#tag_names_contains'
end
context 'when gitaly is enabled', :skip_gitaly_mock do
it_behaves_like '#tag_names_contains'
end
end
describe 'tags_sorted_by' do describe 'tags_sorted_by' do
context 'name_desc' do context 'name_desc' do
subject { repository.tags_sorted_by('name_desc').map(&:name) } subject { repository.tags_sorted_by('name_desc').map(&:name) }
...@@ -991,19 +1014,19 @@ describe Repository do ...@@ -991,19 +1014,19 @@ describe Repository do
end end
describe '#find_branch' do describe '#find_branch' do
it 'loads a branch with a fresh repo' do context 'fresh_repo is true' do
expect(Gitlab::Git::Repository).to receive(:new).twice.and_call_original it 'delegates the call to raw_repository' do
expect(repository.raw_repository).to receive(:find_branch).with('master', true)
2.times do repository.find_branch('master', fresh_repo: true)
expect(repository.find_branch('feature')).not_to be_nil
end end
end end
it 'loads a branch with a cached repo' do context 'fresh_repo is false' do
expect(Gitlab::Git::Repository).to receive(:new).once.and_call_original it 'delegates the call to raw_repository' do
expect(repository.raw_repository).to receive(:find_branch).with('master', false)
2.times do repository.find_branch('master', fresh_repo: false)
expect(repository.find_branch('feature', fresh_repo: false)).not_to be_nil
end end
end end
end end
......
...@@ -199,6 +199,27 @@ module MarkdownMatchers ...@@ -199,6 +199,27 @@ module MarkdownMatchers
expect(video['src']).to end_with('/assets/videos/gitlab-demo.mp4') expect(video['src']).to end_with('/assets/videos/gitlab-demo.mp4')
end end
end end
# ColorFilter
matcher :parse_colors do
set_default_markdown_messages
match do |actual|
color_chips = actual.css('code > span.gfm-color_chip > span')
expect(color_chips.count).to eq(9)
[
'#F00', '#F00A', '#FF0000', '#FF0000AA', 'RGB(0,255,0)',
'RGB(0%,100%,0%)', 'RGBA(0,255,0,0.7)', 'HSL(540,70%,50%)',
'HSLA(540,70%,50%,0.7)'
].each_with_index do |color, i|
parsed_color = Banzai::ColorParser.parse(color)
expect(color_chips[i]['style']).to match("background-color: #{parsed_color};")
expect(color_chips[i].parent.parent.content).to match(color)
end
end
end
end end
# Monkeypatch the matcher DSL so that we can reduce some noisy duplication for # Monkeypatch the matcher DSL so that we can reduce some noisy duplication for
......
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