Commit c454dec1 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'master' into go-go-gadget-webpack

* master: (33 commits)
  Improved code style on the issue_sidebar_spec.rb
  add CHAGELOG.md entry for !8831
  remove assets:compile step from relative_url docs
  update scripts and docs to reference the newly namespaced rake task
  namespace assets rake tasks to gitlab:assets:*
  correct gzip files if they exist as well
  automatically correct CSS urls on assets:precompile
  remove hard-coded assets path for ace editor modules
  Fixed cancel button in the services form not redirecting back to the integrations settings view
  Fix search bar search param encoding
  Fix a transient failure in the `Explore::ProjectsController` spec
  Fix filtering with multiple words
  Fix project name label's for reference in project settings
  Fixed merge request tabs extra margin
  Don't call `#uniq` on a relation
  Move Gitlab::Shell and Gitlab::ShellAdapter files to lib/
  Move ApplicationSetting DEFAULTS to `.defaults` instead
  Move a begin/rescue clause to ApplicationSetting.expire
  Use badge partial as single source of truth instead of having 2 partials doing the same
  Changes after review
  ...
parents a5f79344 b78d06b7
...@@ -109,7 +109,7 @@ setup-test-env: ...@@ -109,7 +109,7 @@ setup-test-env:
script: script:
- npm install - npm install
- bundle exec rake webpack:compile - bundle exec rake webpack:compile
- bundle exec rake assets:precompile 2>/dev/null - bundle exec rake gitlab:assets:compile 2>/dev/null
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
artifacts: artifacts:
expire_in: 7d expire_in: 7d
......
...@@ -280,6 +280,7 @@ group :development, :test do ...@@ -280,6 +280,7 @@ group :development, :test do
gem 'rspec-retry', '~> 0.4.5' gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1' gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2' gem 'spinach-rerun-reporter', '~> 0.0.2'
gem 'rspec_profiling'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.7.0' gem 'minitest', '~> 5.7.0'
......
...@@ -638,6 +638,11 @@ GEM ...@@ -638,6 +638,11 @@ GEM
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-support (3.5.0) rspec-support (3.5.0)
rspec_profiling (0.0.4)
activerecord
pg
rails
sqlite3
rubocop (0.46.0) rubocop (0.46.0)
parser (>= 2.3.1.1, < 3.0) parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1) powerpack (~> 0.1)
...@@ -733,6 +738,7 @@ GEM ...@@ -733,6 +738,7 @@ GEM
actionpack (>= 4.0) actionpack (>= 4.0)
activesupport (>= 4.0) activesupport (>= 4.0)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
sqlite3 (1.3.11)
stackprof (0.2.10) stackprof (0.2.10)
state_machines (0.4.0) state_machines (0.4.0)
state_machines-activemodel (0.4.0) state_machines-activemodel (0.4.0)
...@@ -953,6 +959,7 @@ DEPENDENCIES ...@@ -953,6 +959,7 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0) rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rspec_profiling
rubocop (~> 0.46.0) rubocop (~> 0.46.0)
rubocop-rspec (~> 1.9.1) rubocop-rspec (~> 1.9.1)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
......
...@@ -81,7 +81,6 @@ window.ES6Promise.polyfill(); ...@@ -81,7 +81,6 @@ window.ES6Promise.polyfill();
var $sidebarGutterToggle = $('.js-sidebar-toggle'); var $sidebarGutterToggle = $('.js-sidebar-toggle');
var $flash = $('.flash-container'); var $flash = $('.flash-container');
var bootstrapBreakpoint = bp.getBreakpointSize(); var bootstrapBreakpoint = bp.getBreakpointSize();
var checkInitialSidebarSize;
var fitSidebarForSize; var fitSidebarForSize;
// Set the default path for all cookies to GitLab's root directory // Set the default path for all cookies to GitLab's root directory
...@@ -243,19 +242,11 @@ window.ES6Promise.polyfill(); ...@@ -243,19 +242,11 @@ window.ES6Promise.polyfill();
return $document.trigger('breakpoint:change', [bootstrapBreakpoint]); return $document.trigger('breakpoint:change', [bootstrapBreakpoint]);
} }
}; };
checkInitialSidebarSize = function () {
bootstrapBreakpoint = bp.getBreakpointSize();
if (bootstrapBreakpoint === 'xs' || 'sm') {
return $document.trigger('breakpoint:change', [bootstrapBreakpoint]);
}
};
$window.off('resize.app').on('resize.app', function () { $window.off('resize.app').on('resize.app', function () {
return fitSidebarForSize(); return fitSidebarForSize();
}); });
gl.awardsHandler = new AwardsHandler(); gl.awardsHandler = new AwardsHandler();
checkInitialSidebarSize();
new Aside(); new Aside();
// bind sidebar events // bind sidebar events
new gl.Sidebar(); new gl.Sidebar();
}); });
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
(function() { (function() {
this.CommitsList = (function() { this.CommitsList = (function() {
function CommitsList() {} var CommitsList = {};
CommitsList.timer = null; CommitsList.timer = null;
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
}); });
this.content = $("#commits-list"); this.content = $("#commits-list");
this.searchField = $("#commits-search"); this.searchField = $("#commits-search");
this.lastSearch = this.searchField.val();
return this.initSearch(); return this.initSearch();
}; };
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
var commitsUrl, form, search; var commitsUrl, form, search;
form = $(".commits-search-form"); form = $(".commits-search-form");
search = CommitsList.searchField.val(); search = CommitsList.searchField.val();
if (search === CommitsList.lastSearch) return;
commitsUrl = form.attr("action") + '?' + form.serialize(); commitsUrl = form.attr("action") + '?' + form.serialize();
CommitsList.content.fadeTo('fast', 0.5); CommitsList.content.fadeTo('fast', 0.5);
return $.ajax({ return $.ajax({
...@@ -47,12 +49,16 @@ ...@@ -47,12 +49,16 @@
return CommitsList.content.fadeTo('fast', 1.0); return CommitsList.content.fadeTo('fast', 1.0);
}, },
success: function(data) { success: function(data) {
CommitsList.lastSearch = search;
CommitsList.content.html(data.html); CommitsList.content.html(data.html);
return history.replaceState({ return history.replaceState({
page: commitsUrl page: commitsUrl
// Change url so if user reload a page - search results are saved // Change url so if user reload a page - search results are saved
}, document.title, commitsUrl); }, document.title, commitsUrl);
}, },
error: function() {
CommitsList.lastSearch = null;
},
dataType: "json" dataType: "json"
}); });
}; };
......
...@@ -28,7 +28,12 @@ ...@@ -28,7 +28,12 @@
if (lastToken !== searchToken) { if (lastToken !== searchToken) {
const title = updatedItem.title.toLowerCase(); const title = updatedItem.title.toLowerCase();
let value = lastToken.value.toLowerCase(); let value = lastToken.value.toLowerCase();
value = value.replace(/"(.*?)"/g, str => str.slice(1).slice(0, -1));
// Removes the first character if it is a quotation so that we can search
// with multiple words
if ((value[0] === '"' || value[0] === '\'') && title.indexOf(' ') !== -1) {
value = value.slice(1);
}
// Eg. filterSymbol = ~ for labels // Eg. filterSymbol = ~ for labels
const matchWithoutSymbol = lastToken.symbol === filterSymbol && title.indexOf(value) !== -1; const matchWithoutSymbol = lastToken.symbol === filterSymbol && title.indexOf(value) !== -1;
...@@ -83,8 +88,9 @@ ...@@ -83,8 +88,9 @@
const selectionStart = input.selectionStart; const selectionStart = input.selectionStart;
let inputValue = input.value; let inputValue = input.value;
// Replace all spaces inside quote marks with underscores // Replace all spaces inside quote marks with underscores
// (will continue to match entire string until an end quote is found if any)
// This helps with matching the beginning & end of a token:key // This helps with matching the beginning & end of a token:key
inputValue = inputValue.replace(/("(.*?)"|:\s+)/g, str => str.replace(/\s/g, '_')); inputValue = inputValue.replace(/(('[^']*'{0,1})|("[^"]*"{0,1})|:\s+)/g, str => str.replace(/\s/g, '_'));
// Get the right position for the word selected // Get the right position for the word selected
// Regex matches first space // Regex matches first space
......
...@@ -196,7 +196,8 @@ ...@@ -196,7 +196,8 @@
}); });
if (searchToken) { if (searchToken) {
paths.push(`search=${encodeURIComponent(searchToken)}`); const sanitized = searchToken.split(' ').map(t => encodeURIComponent(t)).join('+');
paths.push(`search=${sanitized}`);
} }
Turbolinks.visit(`?scope=all&utf8=✓&${paths.join('&')}`); Turbolinks.visit(`?scope=all&utf8=✓&${paths.join('&')}`);
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, max-len */ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, max-len */
/* global UsersSelect */ /* global UsersSelect */
/* global Cookies */
/* global bp */
(function() { (function() {
this.IssuableContext = (function() { this.IssuableContext = (function() {
...@@ -37,6 +39,13 @@ ...@@ -37,6 +39,13 @@
}, 0); }, 0);
} }
}); });
window.addEventListener('beforeunload', function() {
// collapsed_gutter cookie hides the sidebar
var bpBreakpoint = bp.getBreakpointSize();
if (bpBreakpoint === 'xs' || bpBreakpoint === 'sm') {
Cookies.set('collapsed_gutter', true);
}
});
$(".right-sidebar").niceScroll(); $(".right-sidebar").niceScroll();
} }
......
/*= require ace-rails-ap */ /*= require ace/ace */
/*= require ace/ext-searchbox */ /*= require ace/ext-searchbox */
/*= require ./ace/ace_config_paths */
<%
ace_gem_path = Bundler.rubygems.find_name('ace-rails-ap').first.full_gem_path
ace_workers = Dir[ace_gem_path + '/vendor/assets/javascripts/ace/worker-*.js'].sort.map do |file|
File.basename(file, '.js').sub(/^worker-/, '')
end
ace_modes = Dir[ace_gem_path + '/vendor/assets/javascripts/ace/mode-*.js'].sort.map do |file|
File.basename(file, '.js').sub(/^mode-/, '')
end
%>
(function() {
window.gon = window.gon || {};
var basePath = (window.gon.relative_url_root || '').replace(/\/$/, '') + '/assets/ace';
ace.config.set('basePath', basePath);
// configure paths for all worker modules
<% ace_workers.each do |worker| %>
ace.config.setModuleUrl('ace/mode/<%= worker %>_worker', basePath + '/worker-<%= worker %>.js');
<% end %>
// configure paths for all mode modules
<% ace_modes.each do |mode| %>
ace.config.setModuleUrl('ace/mode/<%= mode %>', basePath + '/mode-<%= mode %>.js');
<% end %>
})();
...@@ -158,7 +158,7 @@ ...@@ -158,7 +158,7 @@
}; };
Calendar.prototype.renderMonths = function() { Calendar.prototype.renderMonths = function() {
return this.svg.append('g').selectAll('text').data(this.months).enter().append('text').attr('x', function(date) { return this.svg.append('g').attr('direction', 'ltr').selectAll('text').data(this.months).enter().append('text').attr('x', function(date) {
return date.x; return date.x;
}).attr('y', 10).attr('class', 'user-contrib-text').text((function(_this) { }).attr('y', 10).attr('class', 'user-contrib-text').text((function(_this) {
return function(date) { return function(date) {
......
.calender-block { .calender-block {
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
direction: rtl;
@media (min-width: $screen-sm-min) and (max-width: $screen-md-max) { @media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
overflow-x: scroll; overflow-x: scroll;
......
...@@ -71,7 +71,7 @@ header { ...@@ -71,7 +71,7 @@ header {
&:focus, &:focus,
&:active { &:active {
background-color: $gray-light; background-color: $gray-light;
color: darken($gl-text-color-secondary, 30%); color: $gl-text-color;
.todos-pending-count { .todos-pending-count {
background: darken($todo-alert-blue, 10%); background: darken($todo-alert-blue, 10%);
......
...@@ -178,7 +178,7 @@ $count-arrow-border: #dce0e5; ...@@ -178,7 +178,7 @@ $count-arrow-border: #dce0e5;
$save-project-loader-color: #555; $save-project-loader-color: #555;
$divergence-graph-bar-bg: #ccc; $divergence-graph-bar-bg: #ccc;
$divergence-graph-separator-bg: #ccc; $divergence-graph-separator-bg: #ccc;
$general-hover-transition-duration: 150ms; $general-hover-transition-duration: 100ms;
$general-hover-transition-curve: linear; $general-hover-transition-curve: linear;
......
...@@ -26,10 +26,6 @@ ...@@ -26,10 +26,6 @@
border: 0; border: 0;
} }
} }
.container-fluid {
@extend .fixed-width-container;
}
} }
} }
......
...@@ -420,10 +420,6 @@ ...@@ -420,10 +420,6 @@
.merge-request-tabs-holder { .merge-request-tabs-holder {
background-color: $white-light; background-color: $white-light;
.container-limited {
max-width: $limited-layout-width;
}
&.affix { &.affix {
top: 100px; top: 100px;
left: 0; left: 0;
...@@ -433,10 +429,26 @@ ...@@ -433,10 +429,26 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
right: 0; right: 0;
} }
.merge-request-tabs-container {
padding-left: $gl-padding;
padding-right: $gl-padding;
}
} }
}
&:not(.affix) .container-fluid { .limit-container-width {
padding-left: 0; .merge-request-tabs-container {
padding-right: 0; max-width: $limited-layout-width;
margin-left: auto;
margin-right: auto;
}
}
.limit-container-width:not(.container-limited) {
.merge-request-tabs-holder:not(.affix) {
.merge-request-tabs-container {
max-width: $limited-layout-width - ($gl-padding * 2);
}
} }
} }
...@@ -198,7 +198,7 @@ ...@@ -198,7 +198,7 @@
margin: 15px 5px 0 0; margin: 15px 5px 0 0;
input { input {
height: 27px; height: 28px;
} }
} }
...@@ -523,7 +523,7 @@ a.deploy-project-label { ...@@ -523,7 +523,7 @@ a.deploy-project-label {
&:hover, &:hover,
&:focus { &:focus {
color: darken($notes-light-color, 15%); color: $gl-text-color;
} }
} }
......
...@@ -18,15 +18,14 @@ class AutocompleteController < ApplicationController ...@@ -18,15 +18,14 @@ class AutocompleteController < ApplicationController
if params[:search].blank? if params[:search].blank?
# Include current user if available to filter by "Me" # Include current user if available to filter by "Me"
if params[:current_user].present? && current_user if params[:current_user].present? && current_user
@users = @users.where.not(id: current_user.id)
@users = [current_user, *@users] @users = [current_user, *@users]
end end
if params[:author_id].present? if params[:author_id].present?
author = User.find_by_id(params[:author_id]) author = User.find_by_id(params[:author_id])
@users = [author, *@users] if author @users = [author, *@users].uniq if author
end end
@users.uniq!
end end
render json: @users, only: [:name, :username, :id], methods: [:avatar_url] render json: @users, only: [:name, :username, :id], methods: [:avatar_url]
......
...@@ -13,49 +13,6 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -13,49 +13,6 @@ class ApplicationSetting < ActiveRecord::Base
[\r\n] # any number of newline characters [\r\n] # any number of newline characters
}x }x
DEFAULTS_CE = {
after_sign_up_text: nil,
akismet_enabled: false,
container_registry_token_expire_delay: 5,
default_branch_protection: Settings.gitlab['default_branch_protection'],
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_projects_limit: Settings.gitlab['default_projects_limit'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
disabled_oauth_sign_in_sources: [],
domain_whitelist: Settings.gitlab['domain_whitelist'],
gravatar_enabled: Settings.gravatar['enabled'],
help_page_text: nil,
housekeeping_bitmaps_enabled: true,
housekeeping_enabled: true,
housekeeping_full_repack_period: 50,
housekeeping_gc_period: 200,
housekeeping_incremental_repack_period: 10,
import_sources: Gitlab::ImportSources.values,
koding_enabled: false,
koding_url: nil,
max_artifacts_size: Settings.artifacts['max_size'],
max_attachment_size: Settings.gitlab['max_attachment_size'],
plantuml_enabled: false,
plantuml_url: nil,
recaptcha_enabled: false,
repository_checks_enabled: true,
repository_storages: ['default'],
require_two_factor_authentication: false,
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
session_expire_delay: Settings.gitlab['session_expire_delay'],
send_user_confirmation_email: false,
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
shared_runners_text: nil,
sidekiq_throttling_enabled: false,
sign_in_text: nil,
signin_enabled: Settings.gitlab['signin_enabled'],
signup_enabled: Settings.gitlab['signup_enabled'],
two_factor_grace_period: 48,
user_default_external: false
}
DEFAULTS = DEFAULTS_CE
serialize :restricted_visibility_levels serialize :restricted_visibility_levels
serialize :import_sources serialize :import_sources
serialize :disabled_oauth_sign_in_sources, Array serialize :disabled_oauth_sign_in_sources, Array
...@@ -199,14 +156,64 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -199,14 +156,64 @@ class ApplicationSetting < ActiveRecord::Base
def self.expire def self.expire
Rails.cache.delete(CACHE_KEY) Rails.cache.delete(CACHE_KEY)
rescue
# Gracefully handle when Redis is not available. For example,
# omnibus may fail here during gitlab:assets:compile.
end end
def self.cached def self.cached
Rails.cache.fetch(CACHE_KEY) Rails.cache.fetch(CACHE_KEY)
end end
def self.defaults_ce
{
after_sign_up_text: nil,
akismet_enabled: false,
container_registry_token_expire_delay: 5,
default_branch_protection: Settings.gitlab['default_branch_protection'],
default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
default_projects_limit: Settings.gitlab['default_projects_limit'],
default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'],
disabled_oauth_sign_in_sources: [],
domain_whitelist: Settings.gitlab['domain_whitelist'],
gravatar_enabled: Settings.gravatar['enabled'],
help_page_text: nil,
housekeeping_bitmaps_enabled: true,
housekeeping_enabled: true,
housekeeping_full_repack_period: 50,
housekeeping_gc_period: 200,
housekeeping_incremental_repack_period: 10,
import_sources: Gitlab::ImportSources.values,
koding_enabled: false,
koding_url: nil,
max_artifacts_size: Settings.artifacts['max_size'],
max_attachment_size: Settings.gitlab['max_attachment_size'],
plantuml_enabled: false,
plantuml_url: nil,
recaptcha_enabled: false,
repository_checks_enabled: true,
repository_storages: ['default'],
require_two_factor_authentication: false,
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
session_expire_delay: Settings.gitlab['session_expire_delay'],
send_user_confirmation_email: false,
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
shared_runners_text: nil,
sidekiq_throttling_enabled: false,
sign_in_text: nil,
signin_enabled: Settings.gitlab['signin_enabled'],
signup_enabled: Settings.gitlab['signup_enabled'],
two_factor_grace_period: 48,
user_default_external: false
}
end
def self.defaults
defaults_ce
end
def self.create_from_defaults def self.create_from_defaults
create(DEFAULTS) create(defaults)
end end
def home_page_url_column_exist def home_page_url_column_exist
......
- status = local_assigns.fetch(:status) - status = local_assigns.fetch(:status)
- link = local_assigns.fetch(:link, true)
- css_classes = "ci-status ci-#{status.group}" - css_classes = "ci-status ci-#{status.group}"
- if status.has_details? - if link && status.has_details?
= link_to status.details_path, class: css_classes do = link_to status.details_path, class: css_classes do
= custom_icon(status.icon) = custom_icon(status.icon)
= status.text = status.text
......
.content-block.build-header .content-block.build-header
.header-content .header-content
= render 'ci/status/badge', status: @build.detailed_status(current_user) = render 'ci/status/badge', status: @build.detailed_status(current_user), link: false
Build Build
%strong ##{@build.id} %strong.js-build-id ##{@build.id}
in pipeline in pipeline
= link_to pipeline_path(@build.pipeline) do = link_to pipeline_path(@build.pipeline) do
%strong ##{@build.pipeline.id} %strong ##{@build.pipeline.id}
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
%fieldset.append-bottom-0 %fieldset.append-bottom-0
.row .row
.form-group.col-md-9 .form-group.col-md-9
= f.label :name, class: 'label-light' do = f.label :name, class: 'label-light', for: 'project_name_edit' do
Project name Project name
= f.text_field :name, class: "form-control", id: "project_name_edit" = f.text_field :name, class: "form-control", id: "project_name_edit"
......
...@@ -19,10 +19,8 @@ ...@@ -19,10 +19,8 @@
= render 'shared/issuable/nav', type: :issues = render 'shared/issuable/nav', type: :issues
.nav-controls .nav-controls
- if current_user - if current_user
= link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn append-right-10' do = link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn append-right-10 has-tooltip', title: 'Subscribe' do
= icon('rss') = icon('rss')
%span.icon-label
Subscribe
- if can? current_user, :create_issue, @project - if can? current_user, :create_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace, = link_to new_namespace_project_issue_path(@project.namespace,
@project, @project,
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true = render 'award_emoji/awards_block', awardable: @merge_request, inline: true
.merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') } .merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
%div{ class: container_class } .merge-request-tabs-container
%ul.merge-request-tabs.nav-links.no-top.no-bottom %ul.merge-request-tabs.nav-links.no-top.no-bottom
%li.notes-tab %li.notes-tab
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
......
...@@ -17,4 +17,4 @@ ...@@ -17,4 +17,4 @@
- disabled_title = @service.disabled_title - disabled_title = @service.disabled_title
= link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service), class: "btn #{disabled_class}", title: disabled_title = link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service), class: "btn #{disabled_class}", title: disabled_title
= link_to "Cancel", namespace_project_services_path(@project.namespace, @project), class: "btn btn-cancel" = link_to "Cancel", namespace_project_settings_integrations_path(@project.namespace, @project), class: "btn btn-cancel"
---
title: Add link verification to badge partial in order to render a badge without a link
merge_request: 8740
author:
---
title: Fix filtering with multiple words
merge_request: 8830
author:
---
title: Fix project name label's for reference in project settings
merge_request: 8795
author:
---
title: contribution calendar scrolls from right to left
merge_request:
author:
---
title: Fixed services form cancel not redirecting back the integrations settings view
merge_request: 8843
author:
---
title: Fix search bar search param encoding
merge_request: 8753
author:
---
title: Fixed Issuable sidebar not closing on smaller/mobile sized screens
merge_request:
author:
---
title: Fixed merge requests tab extra margin when fixed to window
merge_request:
author:
---
title: allow relative url change without recompiling frontend assets
merge_request: 8831
author:
...@@ -419,10 +419,4 @@ if Rails.env.test? ...@@ -419,10 +419,4 @@ if Rails.env.test?
end end
# Force a refresh of application settings at startup # Force a refresh of application settings at startup
begin ApplicationSetting.expire
ApplicationSetting.expire
Ci::ApplicationSetting.expire
rescue
# Gracefully handle when Redis is not available. For example,
# omnibus may fail here during assets:precompile.
end
# GIT over SSH
require_dependency Rails.root.join('lib/gitlab/backend/shell')
# GitLab shell adapter
require_dependency Rails.root.join('lib/gitlab/backend/shell_adapter')
required_version = Gitlab::VersionInfo.parse(Gitlab::Shell.version_required) required_version = Gitlab::VersionInfo.parse(Gitlab::Shell.version_required)
current_version = Gitlab::VersionInfo.parse(Gitlab::Shell.new.version) current_version = Gitlab::VersionInfo.parse(Gitlab::Shell.new.version)
......
module RspecProfilingConnection
def establish_connection
::RspecProfiling::Collectors::PSQL::Result.establish_connection(ENV['RSPEC_PROFILING_POSTGRES_URL'])
end
end
if Rails.env.test?
RspecProfiling.configure do |config|
if ENV['RSPEC_PROFILING_POSTGRES_URL']
RspecProfiling::Collectors::PSQL.prepend(RspecProfilingConnection)
config.collector = RspecProfiling::Collectors::PSQL
end
end
end
...@@ -172,14 +172,14 @@ Omnibus packages. ...@@ -172,14 +172,14 @@ Omnibus packages.
``` ```
cd /home/git/gitlab cd /home/git/gitlab
sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production
``` ```
For omnibus versions, the unoptimized assets (JavaScript, CSS) are frozen at For omnibus versions, the unoptimized assets (JavaScript, CSS) are frozen at
the release of upstream GitLab. The omnibus version includes optimized versions the release of upstream GitLab. The omnibus version includes optimized versions
of those assets. Unless you are modifying the JavaScript / CSS code on your of those assets. Unless you are modifying the JavaScript / CSS code on your
production machine after installing the package, there should be no reason to redo production machine after installing the package, there should be no reason to redo
rake assets:precompile on the production machine. If you suspect that assets rake gitlab:assets:compile on the production machine. If you suspect that assets
have been corrupted, you should reinstall the omnibus package. have been corrupted, you should reinstall the omnibus package.
## Tracking Deployments ## Tracking Deployments
......
...@@ -245,7 +245,7 @@ Example response: ...@@ -245,7 +245,7 @@ Example response:
```json ```json
[ [
{ {
"diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files", "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files",
"new_path": "doc/update/5.4-to-6.0.md", "new_path": "doc/update/5.4-to-6.0.md",
"old_path": "doc/update/5.4-to-6.0.md", "old_path": "doc/update/5.4-to-6.0.md",
"a_mode": null, "a_mode": null,
......
...@@ -211,6 +211,41 @@ suite first. See the ...@@ -211,6 +211,41 @@ suite first. See the
[StackProf documentation](https://github.com/tmm1/stackprof/blob/master/README.md) [StackProf documentation](https://github.com/tmm1/stackprof/blob/master/README.md)
for details. for details.
## RSpec profiling
GitLab's development environment also includes the
[rspec_profiling](https://github.com/foraker/rspec_profiling) gem, which is used
to collect data on spec execution times. This is useful for analyzing the
performance of the test suite itself, or seeing how the performance of a spec
may have changed over time.
To activate profiling in your local environment, run the following:
```
$ export RSPEC_PROFILING=yes
$ rake rspec_profiling:install
```
This creates an SQLite3 database in `tmp/rspec_profiling`, into which statistics
are saved every time you run specs with the `RSPEC_PROFILING` environment
variable set.
Ad-hoc investigation of the collected results can be performed in an interactive
shell:
```
$ rake rspec_profiling:console
irb(main):001:0> results.count
=> 231
irb(main):002:0> results.last.attributes.keys
=> ["id", "commit", "date", "file", "line_number", "description", "time", "status", "exception", "query_count", "query_time", "request_count", "request_time", "created_at", "updated_at"]
irb(main):003:0> results.where(status: "passed").average(:time).to_s
=> "0.211340155844156"
```
These results can also be placed into a PostgreSQL database by setting the
`RSPEC_PROFILING_POSTGRES_URL` variable. This is used to profile the test suite
when running in the CI environment.
## Importance of Changes ## Importance of Changes
When working on performance improvements, it's important to always ask yourself When working on performance improvements, it's important to always ask yourself
......
...@@ -448,7 +448,7 @@ Check if GitLab and its environment are configured correctly: ...@@ -448,7 +448,7 @@ Check if GitLab and its environment are configured correctly:
### Compile Assets ### Compile Assets
sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production
### Start Your GitLab Instance ### Start Your GitLab Instance
......
...@@ -113,14 +113,6 @@ Make sure to follow all steps below: ...@@ -113,14 +113,6 @@ Make sure to follow all steps below:
If you are using a custom init script, make sure to edit the above If you are using a custom init script, make sure to edit the above
gitlab-workhorse setting as needed. gitlab-workhorse setting as needed.
1. After all the above changes recompile the assets. This is an important task
and will take some time to complete depending on the server resources:
```
cd /home/git/gitlab
sudo -u git -H bundle exec rake assets:clean assets:precompile RAILS_ENV=production
```
1. [Restart GitLab][] for the changes to take effect. 1. [Restart GitLab][] for the changes to take effect.
### Disable relative URL in GitLab ### Disable relative URL in GitLab
......
...@@ -57,7 +57,7 @@ sudo -u git -H bundle clean ...@@ -57,7 +57,7 @@ sudo -u git -H bundle clean
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Clean up assets and cache # Clean up assets and cache
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:assets:clean gitlab:assets:compile cache:clear RAILS_ENV=production
``` ```
### 4. Update gitlab-workhorse to the corresponding version ### 4. Update gitlab-workhorse to the corresponding version
......
...@@ -30,7 +30,7 @@ module Gitlab ...@@ -30,7 +30,7 @@ module Gitlab
end end
def in_memory_application_settings def in_memory_application_settings
@in_memory_application_settings ||= ::ApplicationSetting.new(::ApplicationSetting::DEFAULTS) @in_memory_application_settings ||= ::ApplicationSetting.new(::ApplicationSetting.defaults)
# In case migrations the application_settings table is not created yet, # In case migrations the application_settings table is not created yet,
# we fallback to a simple OpenStruct # we fallback to a simple OpenStruct
rescue ActiveRecord::StatementInvalid, ActiveRecord::UnknownAttributeError rescue ActiveRecord::StatementInvalid, ActiveRecord::UnknownAttributeError
...@@ -38,7 +38,7 @@ module Gitlab ...@@ -38,7 +38,7 @@ module Gitlab
end end
def fake_application_settings def fake_application_settings
OpenStruct.new(::ApplicationSetting::DEFAULTS) OpenStruct.new(::ApplicationSetting.defaults)
end end
private private
......
...@@ -61,7 +61,7 @@ module Gitlab ...@@ -61,7 +61,7 @@ module Gitlab
"Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}), "Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}),
"Install gems" => %W(bundle), "Install gems" => %W(bundle),
"Migrate DB" => %W(bundle exec rake db:migrate), "Migrate DB" => %W(bundle exec rake db:migrate),
"Recompile assets" => %W(bundle exec rake assets:clean assets:precompile), "Recompile assets" => %W(bundle exec rake gitlab:assets:clean gitlab:assets:compile),
"Clear cache" => %W(bundle exec rake cache:clear) "Clear cache" => %W(bundle exec rake cache:clear)
} }
end end
......
...@@ -31,8 +31,8 @@ echo 'Deploy: Bundle and migrate' ...@@ -31,8 +31,8 @@ echo 'Deploy: Bundle and migrate'
sudo -u git -H bundle --without aws development test mysql --deployment sudo -u git -H bundle --without aws development test mysql --deployment
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
sudo -u git -H bundle exec rake assets:clean RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:assets:clean RAILS_ENV=production
sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production
sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
# return stashed changes (if necessary) # return stashed changes (if necessary)
......
namespace :gitlab do
namespace :assets do
desc 'GitLab | Assets | Compile all frontend assets'
task :compile do
Rake::Task['assets:precompile'].invoke
Rake::Task['gitlab:assets:fix_urls'].invoke
end
desc 'GitLab | Assets | Clean up old compiled frontend assets'
task :clean do
Rake::Task['assets:clean'].invoke
end
desc 'GitLab | Assets | Remove all compiled frontend assets'
task :purge do
Rake::Task['assets:clobber'].invoke
end
desc 'GitLab | Assets | Fix all absolute url references in CSS'
task :fix_urls do
css_files = Dir['public/assets/*.css']
css_files.each do | file |
# replace url(/assets/*) with url(./*)
puts "Fixing #{file}"
system "sed", "-i", "-e", 's/url(\([\"\']\?\)\/assets\//url(\1.\//g', file
# rewrite the corresponding gzip file (if it exists)
gzip = "#{file}.gz"
if File.exist?(gzip)
puts "Fixing #{gzip}"
FileUtils.rm(gzip)
mtime = File.stat(file).mtime
File.open(gzip, 'wb+') do |f|
gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
gz.mtime = mtime
gz.write IO.binread(file)
gz.close
File.utime(mtime, mtime, f.path)
end
end
end
end
end
end
require 'spec_helper' require 'spec_helper'
describe Explore::ProjectsController do describe Explore::ProjectsController do
let(:user) { create(:user) }
let(:visibility) { :public }
describe 'GET #trending' do describe 'GET #trending' do
let!(:project_1) { create(:project, visibility, ci_id: 1) } context 'sorting by update date' do
let!(:project_2) { create(:project, visibility, ci_id: 2) } let(:project1) { create(:empty_project, :public, updated_at: 3.days.ago) }
let(:project2) { create(:empty_project, :public, updated_at: 1.day.ago) }
let!(:trending_project_1) { create(:trending_project, project: project_1) }
let!(:trending_project_2) { create(:trending_project, project: project_2) }
before do before do
sign_in(user) create(:trending_project, project: project1)
end create(:trending_project, project: project2)
end
context 'sorting by update date' do
it 'sorts by last updated' do it 'sorts by last updated' do
get :trending, sort: 'updated_desc' get :trending, sort: 'updated_desc'
expect(assigns(:projects)).to eq [project_2, project_1]
expect(assigns(:projects)).to eq [project2, project1]
end end
it 'sorts by oldest updated' do it 'sorts by oldest updated' do
get :trending, sort: 'updated_asc' get :trending, sort: 'updated_asc'
expect(assigns(:projects)).to eq [project_1, project_2]
expect(assigns(:projects)).to eq [project1, project2]
end end
end end
end end
......
...@@ -773,7 +773,7 @@ describe 'Filter issues', js: true, feature: true do ...@@ -773,7 +773,7 @@ describe 'Filter issues', js: true, feature: true do
describe 'RSS feeds' do describe 'RSS feeds' do
it 'updates atom feed link for project issues' do it 'updates atom feed link for project issues' do
visit namespace_project_issues_path(project.namespace, project, milestone_title: milestone.title, assignee_id: user.id) visit namespace_project_issues_path(project.namespace, project, milestone_title: milestone.title, assignee_id: user.id)
link = find('.nav-controls a', text: 'Subscribe') link = find_link('Subscribe')
params = CGI.parse(URI.parse(link[:href]).query) params = CGI.parse(URI.parse(link[:href]).query)
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false) auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query) auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
......
...@@ -2,6 +2,7 @@ require 'rails_helper' ...@@ -2,6 +2,7 @@ require 'rails_helper'
feature 'Issue Sidebar', feature: true do feature 'Issue Sidebar', feature: true do
include WaitForAjax include WaitForAjax
include MobileHelpers
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
...@@ -59,6 +60,23 @@ feature 'Issue Sidebar', feature: true do ...@@ -59,6 +60,23 @@ feature 'Issue Sidebar', feature: true do
end end
end end
context 'sidebar', js: true do
it 'changes size when the screen size is smaller' do
sidebar_selector = 'aside.right-sidebar.right-sidebar-collapsed'
# Resize the window
resize_screen_sm
# Make sure the sidebar is collapsed
expect(page).to have_css(sidebar_selector)
# Once is collapsed let's open the sidebard and reload
open_issue_sidebar
refresh
expect(page).to have_css(sidebar_selector)
# Restore the window size as it was including the sidebar
restore_window_size
open_issue_sidebar
end
end
context 'creating a new label', js: true do context 'creating a new label', js: true do
it 'shows option to crate a new label is present' do it 'shows option to crate a new label is present' do
page.within('.block.labels') do page.within('.block.labels') do
...@@ -109,4 +127,11 @@ feature 'Issue Sidebar', feature: true do ...@@ -109,4 +127,11 @@ feature 'Issue Sidebar', feature: true do
def visit_issue(project, issue) def visit_issue(project, issue)
visit namespace_project_issue_path(project.namespace, project, issue) visit namespace_project_issue_path(project.namespace, project, issue)
end end
def open_issue_sidebar
page.within('aside.right-sidebar.right-sidebar-collapsed') do
find('.js-sidebar-toggle').click
sleep 1
end
end
end end
...@@ -37,7 +37,7 @@ describe 'Edit Project Settings', feature: true do ...@@ -37,7 +37,7 @@ describe 'Edit Project Settings', feature: true do
it 'shows errors for invalid project path/name' do it 'shows errors for invalid project path/name' do
visit edit_namespace_project_path(project.namespace, project) visit edit_namespace_project_path(project.namespace, project)
fill_in 'Project name', with: 'foo&bar' fill_in 'project_name', with: 'foo&bar'
fill_in 'Path', with: 'foo&bar' fill_in 'Path', with: 'foo&bar'
click_button 'Rename project' click_button 'Rename project'
...@@ -53,7 +53,7 @@ describe 'Edit Project Settings', feature: true do ...@@ -53,7 +53,7 @@ describe 'Edit Project Settings', feature: true do
it 'shows error for invalid project name' do it 'shows error for invalid project name' do
visit edit_namespace_project_path(project.namespace, project) visit edit_namespace_project_path(project.namespace, project)
fill_in 'Project name', with: '🚀 foo bar ☁️' fill_in 'project_name', with: '🚀 foo bar ☁️'
click_button 'Rename project' click_button 'Rename project'
......
/* global CommitsList */
//= require jquery.endless-scroll
//= require pager
//= require commits
(() => {
describe('Commits List', () => {
beforeEach(() => {
setFixtures(`
<form class="commits-search-form" action="/h5bp/html5-boilerplate/commits/master">
<input id="commits-search">
</form>
<ol id="commits-list"></ol>
`);
});
it('should be defined', () => {
expect(CommitsList).toBeDefined();
});
describe('on entering input', () => {
let ajaxSpy;
beforeEach(() => {
CommitsList.init(25);
CommitsList.searchField.val('');
spyOn(history, 'replaceState').and.stub();
ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => {
req.success({
data: '<li>Result</li>',
});
});
});
it('should save the last search string', () => {
CommitsList.searchField.val('GitLab');
CommitsList.filterResults();
expect(ajaxSpy).toHaveBeenCalled();
expect(CommitsList.lastSearch).toEqual('GitLab');
});
it('should not make ajax call if the input does not change', () => {
CommitsList.filterResults();
expect(ajaxSpy).not.toHaveBeenCalled();
expect(CommitsList.lastSearch).toEqual('');
});
});
});
})();
...@@ -64,6 +64,68 @@ require('~/filtered_search/filtered_search_dropdown_manager'); ...@@ -64,6 +64,68 @@ require('~/filtered_search/filtered_search_dropdown_manager');
const updatedItem = gl.DropdownUtils.filterWithSymbol('@', input, item); const updatedItem = gl.DropdownUtils.filterWithSymbol('@', input, item);
expect(updatedItem.droplab_hidden).toBe(false); expect(updatedItem.droplab_hidden).toBe(false);
}); });
describe('filters multiple word title', () => {
const multipleWordItem = {
title: 'Community Contributions',
};
it('should filter with double quote', () => {
input.value = 'label:"';
const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should filter with double quote and symbol', () => {
input.value = 'label:~"';
const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should filter with double quote and multiple words', () => {
input.value = 'label:"community con';
const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should filter with double quote, symbol and multiple words', () => {
input.value = 'label:~"community con';
const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should filter with single quote', () => {
input.value = 'label:\'';
const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should filter with single quote and symbol', () => {
input.value = 'label:~\'';
const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should filter with single quote and multiple words', () => {
input.value = 'label:\'community con';
const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should filter with single quote, symbol and multiple words', () => {
input.value = 'label:~\'community con';
const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem);
expect(updatedItem.droplab_hidden).toBe(false);
});
});
}); });
describe('filterHint', () => { describe('filterHint', () => {
...@@ -130,5 +192,99 @@ require('~/filtered_search/filtered_search_dropdown_manager'); ...@@ -130,5 +192,99 @@ require('~/filtered_search/filtered_search_dropdown_manager');
expect(result).toBe(false); expect(result).toBe(false);
}); });
}); });
describe('getInputSelectionPosition', () => {
describe('word with trailing spaces', () => {
const value = 'label:none ';
it('should return selectionStart when cursor is at the trailing space', () => {
const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
selectionStart: 11,
value,
});
expect(left).toBe(11);
expect(right).toBe(11);
});
it('should return input when cursor is at the start of input', () => {
const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
selectionStart: 0,
value,
});
expect(left).toBe(0);
expect(right).toBe(10);
});
it('should return input when cursor is at the middle of input', () => {
const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
selectionStart: 7,
value,
});
expect(left).toBe(0);
expect(right).toBe(10);
});
it('should return input when cursor is at the end of input', () => {
const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
selectionStart: 10,
value,
});
expect(left).toBe(0);
expect(right).toBe(10);
});
});
describe('multiple words', () => {
const value = 'label:~"Community Contribution"';
it('should return input when cursor is after the first word', () => {
const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
selectionStart: 17,
value,
});
expect(left).toBe(0);
expect(right).toBe(31);
});
it('should return input when cursor is before the second word', () => {
const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
selectionStart: 18,
value,
});
expect(left).toBe(0);
expect(right).toBe(31);
});
});
describe('incomplete multiple words', () => {
const value = 'label:~"Community Contribution';
it('should return entire input when cursor is at the start of input', () => {
const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
selectionStart: 0,
value,
});
expect(left).toBe(0);
expect(right).toBe(30);
});
it('should return entire input when cursor is at the end of input', () => {
const { left, right } = gl.DropdownUtils.getInputSelectionPosition({
selectionStart: 30,
value,
});
expect(left).toBe(0);
expect(right).toBe(30);
});
});
});
}); });
})(); })();
/* global Turbolinks */
//= require turbolinks
//= require lib/utils/common_utils
//= require filtered_search/filtered_search_token_keys
//= require filtered_search/filtered_search_tokenizer
//= require filtered_search/filtered_search_dropdown_manager
//= require filtered_search/filtered_search_manager
(() => {
describe('Filtered Search Manager', () => {
describe('search', () => {
let manager;
const defaultParams = '?scope=all&utf8=✓&state=opened';
function getInput() {
return document.querySelector('.filtered-search');
}
beforeEach(() => {
setFixtures(`
<input type='text' class='filtered-search' />
`);
spyOn(gl.FilteredSearchManager.prototype, 'bindEvents').and.callFake(() => {});
spyOn(gl.FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {});
spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {});
spyOn(gl.utils, 'getParameterByName').and.returnValue(null);
manager = new gl.FilteredSearchManager();
});
afterEach(() => {
getInput().outerHTML = '';
});
it('should search with a single word', () => {
getInput().value = 'searchTerm';
spyOn(Turbolinks, 'visit').and.callFake((url) => {
expect(url).toEqual(`${defaultParams}&search=searchTerm`);
});
manager.search();
});
it('should search with multiple words', () => {
getInput().value = 'awesome search terms';
spyOn(Turbolinks, 'visit').and.callFake((url) => {
expect(url).toEqual(`${defaultParams}&search=awesome+search+terms`);
});
manager.search();
});
it('should search with special characters', () => {
getInput().value = '~!@#$%^&*()_+{}:<>,.?/';
spyOn(Turbolinks, 'visit').and.callFake((url) => {
expect(url).toEqual(`${defaultParams}&search=~!%40%23%24%25%5E%26*()_%2B%7B%7D%3A%3C%3E%2C.%3F%2F`);
});
manager.search();
});
});
});
})();
...@@ -9,6 +9,10 @@ require 'rspec/rails' ...@@ -9,6 +9,10 @@ require 'rspec/rails'
require 'shoulda/matchers' require 'shoulda/matchers'
require 'rspec/retry' require 'rspec/retry'
if ENV['RSPEC_PROFILING_POSTGRES_URL'] || ENV['RSPEC_PROFILING']
require 'rspec_profiling/rspec'
end
if ENV['CI'] && !ENV['NO_KNAPSACK'] if ENV['CI'] && !ENV['NO_KNAPSACK']
require 'knapsack' require 'knapsack'
Knapsack::Adapters::RSpecAdapter.bind Knapsack::Adapters::RSpecAdapter.bind
......
module MobileHelpers
def resize_screen_sm
resize_window(900, 768)
end
def restore_window_size
resize_window(1366, 768)
end
def resize_window(width, height)
page.driver.resize_window width, height
end
end
...@@ -15,6 +15,36 @@ describe 'projects/builds/show', :view do ...@@ -15,6 +15,36 @@ describe 'projects/builds/show', :view do
allow(view).to receive(:can?).and_return(true) allow(view).to receive(:can?).and_return(true)
end end
describe 'build information in header' do
let(:build) do
create(:ci_build, :success, environment: 'staging')
end
before do
render
end
it 'shows status name' do
expect(rendered).to have_css('.ci-status.ci-success', text: 'passed')
end
it 'does not render a link to the build' do
expect(rendered).not_to have_link('passed')
end
it 'shows build id' do
expect(rendered).to have_css('.js-build-id', text: build.id)
end
it 'shows a link to the pipeline' do
expect(rendered).to have_link(build.pipeline.id)
end
it 'shows a link to the commit' do
expect(rendered).to have_link(build.pipeline.short_sha)
end
end
describe 'environment info in build view' do describe 'environment info in build view' do
context 'build with latest deployment' do context 'build with latest deployment' do
let(:build) do let(:build) do
......
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