Merge remote-tracking branch 'origin/master' into rename-ci-commit

This commit is contained in:
Kamil Trzcinski 2016-06-03 13:10:01 +02:00
commit 0a51c95464
40 changed files with 270 additions and 204 deletions

0
.vagrant_enabled Normal file
View file

View file

@ -7,6 +7,7 @@ v 8.9.0 (unreleased)
- Fix issue todo not remove when leave project !4150 (Long Nguyen)
- Allow forking projects with restricted visibility level
- Improve note validation to prevent errors when creating invalid note via API
- Reduce number of fog gem dependencies
- Remove project notification settings associated with deleted projects
- Fix 404 page when viewing TODOs that contain milestones or labels in different projects
- Redesign navigation for project pages
@ -27,15 +28,30 @@ v 8.9.0 (unreleased)
- Measure queue duration between gitlab-workhorse and Rails
- Make authentication service for Container Registry to be compatible with < Docker 1.11
- Add Application Setting to configure Container Registry token expire delay (default 5min)
- Cache assigned issue and merge request counts in sidebar nav
- Cache project build count in sidebar nav
- Reduce number of queries needed to render issue labels in the sidebar
- Improve error handling importing projects
- Put project Files and Commits tabs under Code tab
v 8.8.3
- Fix incorrect links on pipeline page when merge request created from fork
- Fix gitlab importer failing to import new projects due to missing credentials
- Fix serious performance bug with rendering Markdown with InlineDiffFilter
- Fix import URL migration not rescuing with the correct Error
- In search results, only show notes on confidential issues that the user has access to
- Fix health check access token changing due to old application settings being used
- Fix wiki project clone address error (chujinjin)
- Fix 404 page when viewing TODOs that contain milestones or labels in different projects. !4312
- Fixed JS error when trying to remove discussion form. !4303
- Fixed issue with button color when no CI enabled. !4287
- Fixed potential issue with 2 CI status polling events happening. !3869
- Improve design of Pipeline view. !4230
- Fix gitlab importer failing to import new projects due to missing credentials. !4301
- Fix import URL migration not rescuing with the correct Error. !4321
- Fix health check access token changing due to old application settings being used. !4332
- Make authentication service for Container Registry to be compatible with Docker versions before 1.11. !4363
- Add Application Setting to configure Container Registry token expire delay (default 5 min). !4364
- Pass the "Remember me" value to the 2FA token form. !4369
- Fix incorrect links on pipeline page when merge request created from fork. !4376
- Use downcased path to container repository as this is expected path by Docker. !4420
- Fix wiki project clone address error (chujinjin). !4429
- Fix serious performance bug with rendering Markdown with InlineDiffFilter. !4392
- Fix missing number on generated ordered list element. !4437
- Prevent disclosure of notes on confidential issues in search results.
v 8.8.2
- Added remove due date button. !4209

View file

@ -83,8 +83,14 @@ gem "carrierwave", '~> 0.10.0'
# Drag and Drop UI
gem 'dropzonejs-rails', '~> 0.7.1'
# for backups
gem 'fog-aws', '~> 0.9'
gem 'fog-core', '~> 1.40'
gem 'fog-local', '~> 0.3'
gem 'fog-google', '~> 0.3'
gem 'fog-openstack', '~> 0.1'
# for aws storage
gem "fog", "~> 1.36.0"
gem "unf", '~> 0.1.4'
# Authorization

View file

@ -1,7 +1,6 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (2.3.2)
RedCloth (4.2.9)
ace-rails-ap (4.0.2)
actionmailer (4.2.6)
@ -183,7 +182,7 @@ GEM
erubis (2.7.0)
escape_utils (1.1.1)
eventmachine (1.0.8)
excon (0.45.4)
excon (0.49.0)
execjs (2.6.0)
expression_parser (0.9.0)
factory_girl (4.5.0)
@ -200,8 +199,6 @@ GEM
multi_json
ffaker (2.0.0)
ffi (1.9.10)
fission (0.5.0)
CFPropertyList (~> 2.2)
flay (2.6.1)
ruby_parser (~> 3.0)
sexp_processor (~> 4.0)
@ -211,109 +208,28 @@ GEM
flowdock (0.7.1)
httparty (~> 0.7)
multi_json
fog (1.36.0)
fog-aliyun (>= 0.1.0)
fog-atmos
fog-aws (>= 0.6.0)
fog-brightbox (~> 0.4)
fog-core (~> 1.32)
fog-dynect (~> 0.0.2)
fog-ecloud (~> 0.1)
fog-google (<= 0.1.0)
fog-json
fog-local
fog-powerdns (>= 0.1.1)
fog-profitbricks
fog-radosgw (>= 0.0.2)
fog-riakcs
fog-sakuracloud (>= 0.0.4)
fog-serverlove
fog-softlayer
fog-storm_on_demand
fog-terremark
fog-vmfusion
fog-voxel
fog-xenserver
fog-xml (~> 0.1.1)
ipaddress (~> 0.5)
nokogiri (~> 1.5, >= 1.5.11)
fog-aliyun (0.1.0)
fog-core (~> 1.27)
fog-json (~> 1.0)
ipaddress (~> 0.8)
xml-simple (~> 1.1)
fog-atmos (0.1.0)
fog-core
fog-xml
fog-aws (0.8.1)
fog-aws (0.9.2)
fog-core (~> 1.27)
fog-json (~> 1.0)
fog-xml (~> 0.1)
ipaddress (~> 0.8)
fog-brightbox (0.10.1)
fog-core (~> 1.22)
fog-json
inflecto (~> 0.0.2)
fog-core (1.35.0)
fog-core (1.40.0)
builder
excon (~> 0.45)
excon (~> 0.49)
formatador (~> 0.2)
fog-dynect (0.0.2)
fog-core
fog-json
fog-xml
fog-ecloud (0.3.0)
fog-core
fog-xml
fog-google (0.1.0)
fog-google (0.3.2)
fog-core
fog-json
fog-xml
fog-json (1.0.2)
fog-core (~> 1.0)
multi_json (~> 1.10)
fog-local (0.2.1)
fog-local (0.3.0)
fog-core (~> 1.27)
fog-powerdns (0.1.1)
fog-core (~> 1.27)
fog-json (~> 1.0)
fog-xml (~> 0.1)
fog-profitbricks (0.0.5)
fog-core
fog-xml
nokogiri
fog-radosgw (0.0.5)
fog-core (>= 1.21.0)
fog-json
fog-xml (>= 0.0.1)
fog-riakcs (0.1.0)
fog-core
fog-json
fog-xml
fog-sakuracloud (1.7.5)
fog-core
fog-json
fog-serverlove (0.1.2)
fog-core
fog-json
fog-softlayer (1.0.3)
fog-core
fog-json
fog-storm_on_demand (0.1.1)
fog-core
fog-json
fog-terremark (0.1.0)
fog-core
fog-xml
fog-vmfusion (0.1.0)
fission
fog-core
fog-voxel (0.1.0)
fog-core
fog-xml
fog-xenserver (0.2.2)
fog-core
fog-xml
fog-openstack (0.1.6)
fog-core (>= 1.39)
fog-json (>= 1.0)
ipaddress (>= 0.8)
fog-xml (0.1.2)
fog-core
nokogiri (~> 1.5, >= 1.5.11)
@ -422,11 +338,10 @@ GEM
httpclient (2.7.0.1)
i18n (0.7.0)
ice_nine (0.11.1)
inflecto (0.0.2)
influxdb (0.2.3)
cause
json
ipaddress (0.8.2)
ipaddress (0.8.3)
jquery-atwho-rails (1.3.2)
jquery-rails (4.1.1)
rails-dom-testing (>= 1, < 3)
@ -873,7 +788,6 @@ GEM
builder
expression_parser
rinku
xml-simple (1.1.5)
xpath (2.0.0)
nokogiri (~> 1.3)
@ -927,7 +841,11 @@ DEPENDENCIES
ffaker (~> 2.0.0)
flay
flog
fog (~> 1.36.0)
fog-aws (~> 0.9)
fog-core (~> 1.40)
fog-google (~> 0.3)
fog-local (~> 0.3)
fog-openstack (~> 0.1)
font-awesome-rails (~> 4.2)
foreman
fuubar (~> 2.0.0)

View file

@ -20,8 +20,7 @@ class @SearchAutocomplete
@dropdown = @wrap.find('.dropdown')
@dropdownContent = @dropdown.find('.dropdown-content')
@locationBadgeEl = @getElement('.search-location-badge')
@locationText = @getElement('.location-text')
@locationBadgeEl = @getElement('.location-badge')
@scopeInputEl = @getElement('#scope')
@searchInput = @getElement('.search-input')
@projectInputEl = @getElement('#search_project_id')
@ -133,7 +132,7 @@ class @SearchAutocomplete
scope: @scopeInputEl.val()
# Location badge
_location: @locationText.text()
_location: @locationBadgeEl.text()
}
bindEvents: ->
@ -143,12 +142,14 @@ class @SearchAutocomplete
@searchInput.on 'click', @onSearchInputClick
@searchInput.on 'focus', @onSearchInputFocus
@clearInput.on 'click', @onClearInputClick
@locationBadgeEl.on 'click', =>
@searchInput.focus()
onDocumentClick: (e) =>
# If clicking outside the search box
# And search input is not focused
# And we are not clicking inside a suggestion
if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).parents('ul').length
if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).closest('.search-form').length
@onSearchInputBlur()
enableAutocomplete: ->
@ -221,10 +222,8 @@ class @SearchAutocomplete
category = if item.category? then "#{item.category}: " else ''
value = if item.value? then item.value else ''
html = "<span class='location-badge'>
<i class='location-text'>#{category}#{value}</i>
</span>"
@locationBadgeEl.html(html)
badgeText = "#{category}#{value}"
@locationBadgeEl.text(badgeText).show()
@wrap.addClass('has-location-badge')
restoreOriginalState: ->
@ -233,9 +232,8 @@ class @SearchAutocomplete
for input in inputs
@getElement("##{input}").val(@originalState[input])
if @originalState._location is ''
@locationBadgeEl.empty()
@locationBadgeEl.hide()
else
@addLocationBadge(
value: @originalState._location
@ -244,7 +242,7 @@ class @SearchAutocomplete
@dropdown.removeClass 'open'
badgePresent: ->
@locationBadgeEl.children().length
@locationBadgeEl.length
resetSearchState: ->
inputs = Object.keys @originalState
@ -257,7 +255,7 @@ class @SearchAutocomplete
@getElement("##{input}").val('')
removeLocationBadge: ->
@locationBadgeEl.empty()
@locationBadgeEl.hide()
# Reset state
@resetSearchState()

View file

@ -29,8 +29,6 @@
margin-top: 6px;
p {
overflow-x: auto;
&:last-child {
margin-bottom: 0;
}

View file

@ -28,6 +28,7 @@
}
.search-input {
padding-right: 20px;
border: none;
font-size: 14px;
outline: none;
@ -47,6 +48,7 @@
display: inline-block;
background-color: $location-badge-bg;
vertical-align: top;
cursor: default;
}
.search-input-container {
@ -55,7 +57,7 @@
position: relative;
}
.search-location-badge, .search-input-wrap {
.search-input-wrap {
// Fallback if flexbox is not supported
display: inline-block;
}

View file

@ -50,7 +50,7 @@ class Projects::BranchesController < Projects::ApplicationController
redirect_to namespace_project_branches_path(@project.namespace,
@project), status: 303
end
format.js { render status: status[:return_code] }
format.js { render nothing: true, status: status[:return_code] }
end
end

View file

@ -17,7 +17,9 @@ module TodosHelper
def todo_target_link(todo)
target = todo.target_type.titleize.downcase
link_to "#{target} #{todo.target_reference}", todo_target_path(todo), { title: todo.target.title }
link_to "#{target} #{todo.target_reference}", todo_target_path(todo),
class: 'has-tooltip',
title: todo.target.title
end
def todo_target_path(todo)

View file

@ -313,6 +313,7 @@ module Ci
build_data = Gitlab::BuildDataBuilder.build(self)
project.execute_hooks(build_data.dup, :build_hooks)
project.execute_services(build_data.dup, :build_hooks)
project.running_or_pending_build_count(force: true)
end
def artifacts?

View file

@ -68,6 +68,14 @@ module Issuable
strip_attributes :title
acts_as_paranoid
after_save :update_assignee_cache_counts, if: :assignee_id_changed?
def update_assignee_cache_counts
# make sure we flush the cache for both the old *and* new assignee
User.find(assignee_id_was).update_cache_counts if assignee_id_was
assignee.update_cache_counts if assignee
end
end
module ClassMethods
@ -205,6 +213,10 @@ module Issuable
hook_data
end
def labels_array
labels.to_a
end
def label_names
labels.order('title ASC').pluck(:title)
end

View file

@ -1011,4 +1011,22 @@ class Project < ActiveRecord::Base
update_attribute(:pending_delete, true)
end
def running_or_pending_build_count(force: false)
Rails.cache.fetch(['projects', id, 'running_or_pending_build_count'], force: force) do
builds.running_or_pending.count(:all)
end
end
def mark_import_as_failed(error_message)
original_errors = errors.dup
sanitized_message = Gitlab::UrlSanitizer.sanitize(error_message)
import_fail
update_column(:import_error, sanitized_message)
rescue ActiveRecord::ActiveRecordError => e
Rails.logger.error("Error setting import status to failed: #{e.message}. Original error: #{sanitized_message}")
ensure
@errors = original_errors
end
end

View file

@ -776,6 +776,23 @@ class User < ActiveRecord::Base
notification_settings.find_or_initialize_by(source: source)
end
def assigned_open_merge_request_count(force: false)
Rails.cache.fetch(['users', id, 'assigned_open_merge_request_count'], force: force) do
assigned_merge_requests.opened.count
end
end
def assigned_open_issues_count(force: false)
Rails.cache.fetch(['users', id, 'assigned_open_issues_count'], force: force) do
assigned_issues.opened.count
end
end
def update_cache_counts
assigned_open_merge_request_count(force: true)
assigned_open_issues_count(force: true)
end
private
def projects_union

View file

@ -56,14 +56,14 @@ module Projects
after_create_actions if @project.persisted?
@project.add_import_job if @project.import?
if @project.errors.empty?
@project.add_import_job if @project.import?
else
fail(error: @project.errors.full_messages.join(', '))
end
@project
rescue => e
message = "Unable to save project: #{e.message}"
Rails.logger.error(message)
@project.errors.add(:base, message) if @project
@project
fail(error: e.message)
end
protected
@ -103,5 +103,19 @@ module Projects
end
end
end
def fail(error:)
message = "Unable to save project. Error: #{error}"
message << "Project ID: #{@project.id}" if @project && @project.id
Rails.logger.error(message)
if @project && @project.import?
@project.errors.add(:base, message)
@project.mark_import_as_failed(message)
end
@project
end
end
end

View file

@ -39,7 +39,7 @@ module Projects
begin
gitlab_shell.import_repository(project.path_with_namespace, project.import_url)
rescue Gitlab::Shell::Error => e
raise Error, e.message
raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}"
end
end

View file

@ -6,11 +6,8 @@
.search.search-form{class: "#{'has-location-badge' if label.present?}"}
= form_tag search_path, method: :get, class: 'navbar-form' do |f|
.search-input-container
.search-location-badge
- if label.present?
%span.location-badge
%i.location-text
= label
- if label.present?
.location-badge= label
.search-input-wrap
.dropdown{ data: {url: search_autocomplete_path } }
= search_field_tag "search", nil, placeholder: 'Search', class: "search-input dropdown-menu-toggle", spellcheck: false, tabindex: "1", autocomplete: 'off', data: { toggle: 'dropdown' }

View file

@ -30,13 +30,13 @@
= icon('exclamation-circle fw')
%span
Issues
%span.count= number_with_delimiter(current_user.assigned_issues.opened.count)
%span.count= number_with_delimiter(current_user.assigned_open_issues_count)
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
= icon('tasks fw')
%span
Merge Requests
%span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count)
%span.count= number_with_delimiter(current_user.assigned_open_merge_request_count)
= nav_link(controller: :snippets) do
= link_to dashboard_snippets_path, title: 'Snippets' do
= icon('clipboard fw')

View file

@ -33,18 +33,11 @@
%span
Activity
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare repositories tags branches releases network)) do
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
= icon('files-o fw')
= icon('code fw')
%span
Files
- if project_nav_tab? :commits
= nav_link(controller: %w(commit commits compare repositories tags branches releases network)) do
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
= icon('history fw')
%span
Commits
Code
- if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do
@ -129,4 +122,10 @@
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
Builds
-# Shortcut to commits page
- if project_nav_tab? :commits
%li.hidden
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
Commits
.fade-right

View file

@ -1 +0,0 @@
$('.js-totalbranch-count').html("#{@repository.branch_count}")

View file

@ -1,9 +1,11 @@
%ul.nav-links
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_files_path(@project) do
Files
= nav_link(controller: [:commit, :commits]) do
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
Commits
%span.badge
= number_with_delimiter(@repository.commit_count)
= nav_link(controller: %w(network)) do
= link_to namespace_project_network_path(@project.namespace, @project, current_ref) do
@ -16,9 +18,7 @@
= nav_link(html_options: {class: branches_tab_class}) do
= link_to namespace_project_branches_path(@project.namespace, @project) do
Branches
%span.badge.js-totalbranch-count= @repository.branch_count
= nav_link(controller: [:tags, :releases]) do
= link_to namespace_project_tags_path(@project.namespace, @project) do
Tags
%span.badge.js-totaltags-count= @repository.tag_count

View file

@ -11,4 +11,4 @@
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
%span
Builds
%span.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
%span.badge.count.builds_counter= number_with_delimiter(@project.running_or_pending_build_count)

View file

@ -1,3 +1,2 @@
$('.js-totaltags-count').html("#{@repository.tags.size}");
- if @repository.tags.empty?
$('.tags').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000)

View file

@ -3,6 +3,7 @@
- if current_user
= auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits")
= render 'projects/last_push'
= render "projects/commits/head"
.tree-controls
= render 'projects/find_file_link'

View file

@ -114,20 +114,20 @@
.sidebar-collapsed-icon
= icon('tags')
%span
= issuable.labels.count
= issuable.labels_array.size
.title.hide-collapsed
Labels
= icon('spinner spin', class: 'block-loading')
- if can_edit_issuable
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.bold.issuable-show-labels.hide-collapsed{ class: ("has-labels" if issuable.labels.any?) }
- if issuable.labels.any?
- issuable.labels.each do |label|
.value.bold.issuable-show-labels.hide-collapsed{ class: ("has-labels" if issuable.labels_array.any?) }
- if issuable.labels_array.any?
- issuable.labels_array.each do |label|
= link_to_label(label, type: issuable.to_ability_name)
- else
.light None
.selectbox.hide-collapsed
- issuable.labels.each do |label|
- issuable.labels_array.each do |label|
= hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil
.dropdown
%button.dropdown-menu-toggle.js-label-select.js-multiselect{type: "button", data: {toggle: "dropdown", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", project_id: (@project.id if @project), issue_update: issuable_json_path(issuable), labels: (namespace_project_labels_path(@project.namespace, @project, :json) if @project)}}

View file

@ -15,8 +15,7 @@ class RepositoryForkWorker
result = gitlab_shell.fork_repository(source_path, target_path)
unless result
logger.error("Unable to fork project #{project_id} for repository #{source_path} -> #{target_path}")
project.update(import_error: "The project could not be forked.")
project.import_fail
project.mark_import_as_failed('The project could not be forked.')
return
end
@ -24,8 +23,7 @@ class RepositoryForkWorker
unless project.valid_repo?
logger.error("Project #{project_id} had an invalid repository after fork")
project.update(import_error: "The forked repository is invalid.")
project.import_fail
project.mark_import_as_failed('The forked repository is invalid.')
return
end

View file

@ -13,8 +13,7 @@ class RepositoryImportWorker
result = Projects::ImportService.new(project, current_user).execute
if result[:status] == :error
project.update(import_error: Gitlab::UrlSanitizer.sanitize(result[:message]))
project.import_fail
project.mark_import_as_failed(result[:message])
return
end

View file

@ -33,4 +33,24 @@ be under 'Wiki' tab and so on and so forth.
We want GitLab to work well on small mobile screens as well. Size limitations make it is impossible to fit everything on a mobile screen. In this case it is OK to hide
part of the UI for smaller resolutions in favor of a better user experience.
However core functionality like browsing files, creating issues, writing comments, should
be available on all resolutions.
be available on all resolutions.
## Icons
* `trash` icon for button or link that does destructive action like removing
information from database or file system
* `x` icon for closing/hiding UI element. For example close modal window
* `pencil` icon for edit button or link
* `eye` icon for subscribe action
* `rss` for rss/atom feed
* `plus` for link or dropdown that lead to page where you create new object (For example new issue page)
## Buttons
* Button should contain icon or text. Exceptions should be approved by UX designer.
* Use gray button on white background or white button on gray background.
* Use red button for destructive actions (not revertable). For example removing issue.
* Use green or blue button for primary action. Primary button should be only one.
Do not use both green and blue button in one form.

View file

@ -10,14 +10,9 @@ Feature: Project Active Tab
Then the active main tab should be Home
And no other main tabs should be active
Scenario: On Project Files
Scenario: On Project Code
Given I visit my project's files page
Then the active main tab should be Files
And no other main tabs should be active
Scenario: On Project Commits
Given I visit my project's commits page
Then the active main tab should be Commits
Then the active main tab should be Code
And no other main tabs should be active
Scenario: On Project Issues
@ -64,40 +59,46 @@ Feature: Project Active Tab
And no other sub navs should be active
And the active main tab should be Settings
# Sub Tabs: Commits
# Sub Tabs: Code
Scenario: On Project Commits/Commits
Scenario: On Project Code/Files
Given I visit my project's files page
Then the active sub tab should be Files
And no other sub tabs should be active
And the active main tab should be Code
Scenario: On Project Code/Commits
Given I visit my project's commits page
Then the active sub tab should be Commits
And no other sub tabs should be active
And the active main tab should be Commits
And the active main tab should be Code
Scenario: On Project Commits/Network
Scenario: On Project Code/Network
Given I visit my project's network page
Then the active sub tab should be Network
And no other sub tabs should be active
And the active main tab should be Commits
And the active main tab should be Code
Scenario: On Project Commits/Compare
Scenario: On Project Code/Compare
Given I visit my project's commits page
And I click the "Compare" tab
Then the active sub tab should be Compare
And no other sub tabs should be active
And the active main tab should be Commits
And the active main tab should be Code
Scenario: On Project Commits/Branches
Scenario: On Project Code/Branches
Given I visit my project's commits page
And I click the "Branches" tab
Then the active sub tab should be Branches
And no other sub tabs should be active
And the active main tab should be Commits
And the active main tab should be Code
Scenario: On Project Commits/Tags
Scenario: On Project Code/Tags
Given I visit my project's commits page
And I click the "Tags" tab
Then the active sub tab should be Tags
And no other sub tabs should be active
And the active main tab should be Commits
And the active main tab should be Code
Scenario: On Project Issues/Browse
Given I visit my project's issues page

View file

@ -24,3 +24,4 @@ Feature: Project Builds Summary
Then recent build has been erased
And recent build summary does not have artifacts widget
And recent build summary contains information saying that build has been erased
And the build count cache is updated

View file

@ -8,19 +8,21 @@ Feature: Project Shortcuts
@javascript
Scenario: Navigate to files tab
Given I press "g" and "f"
Then the active main tab should be Files
Then the active main tab should be Code
Then the active sub tab should be Files
@javascript
Scenario: Navigate to commits tab
Given I visit my project's files page
Given I press "g" and "c"
Then the active main tab should be Commits
Then the active main tab should be Code
Then the active sub tab should be Commits
@javascript
Scenario: Navigate to network tab
Given I press "g" and "n"
Then the active sub tab should be Network
And the active main tab should be Commits
And the active main tab should be Code
@javascript
Scenario: Navigate to graphs tab

View file

@ -63,10 +63,6 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
click_link('Tags')
end
step 'the active sub tab should be Commits' do
ensure_active_sub_tab('Commits')
end
step 'the active sub tab should be Compare' do
ensure_active_sub_tab('Compare')
end

View file

@ -36,4 +36,8 @@ class Spinach::Features::ProjectBuildsSummary < Spinach::FeatureSteps
expect(page).to have_content 'Build has been erased'
end
end
step 'the build count cache is updated' do
expect(@build.project.running_or_pending_build_count).to eq @build.project.builds.running_or_pending.count(:all)
end
end

View file

@ -13,12 +13,12 @@ class Spinach::Features::ProjectFindFile < Spinach::FeatureSteps
end
step 'I should see "find file" page' do
ensure_active_main_tab('Files')
ensure_active_main_tab('Code')
expect(page).to have_selector('.file-finder-holder', count: 1)
end
step 'I fill in Find by path with "git"' do
ensure_active_main_tab('Files')
ensure_active_main_tab('Code')
expect(page).to have_selector('.file-finder-holder', count: 1)
end

View file

@ -8,12 +8,8 @@ module SharedProjectTab
ensure_active_main_tab('Project')
end
step 'the active main tab should be Files' do
ensure_active_main_tab('Files')
end
step 'the active main tab should be Commits' do
ensure_active_main_tab('Commits')
step 'the active main tab should be Code' do
ensure_active_main_tab('Code')
end
step 'the active main tab should be Graphs' do
@ -51,4 +47,12 @@ module SharedProjectTab
step 'the active sub tab should be Network' do
ensure_active_sub_tab('Network')
end
step 'the active sub tab should be Files' do
ensure_active_sub_tab('Files')
end
step 'the active sub tab should be Commits' do
ensure_active_sub_tab('Commits')
end
end

View file

@ -122,27 +122,23 @@ describe Projects::BranchesController do
let(:branch) { "feature" }
it { expect(response.status).to eq(200) }
it { expect(subject).to render_template('destroy') }
end
context "valid branch name with unencoded slashes" do
let(:branch) { "improve/awesome" }
it { expect(response.status).to eq(200) }
it { expect(subject).to render_template('destroy') }
end
context "valid branch name with encoded slashes" do
let(:branch) { "improve%2Fawesome" }
it { expect(response.status).to eq(200) }
it { expect(subject).to render_template('destroy') }
end
context "invalid branch name, valid ref" do
let(:branch) { "no-branch" }
it { expect(response.status).to eq(404) }
it { expect(subject).to render_template('destroy') }
end
end
end

View file

@ -227,6 +227,20 @@ describe Issue, "Issuable" do
end
end
describe '#labels_array' do
let(:project) { create(:project) }
let(:bug) { create(:label, project: project, title: 'bug') }
let(:issue) { create(:issue, project: project) }
before(:each) do
issue.labels << bug
end
it 'loads the association and returns it as an array' do
expect(issue.reload.labels_array).to eq([bug])
end
end
describe "votes" do
let(:project) { issue.project }

View file

@ -269,4 +269,21 @@ describe Issue, models: true do
end
end
end
describe 'cached counts' do
it 'updates when assignees change' do
user1 = create(:user)
user2 = create(:user)
issue = create(:issue, assignee: user1)
expect(user1.assigned_open_issues_count).to eq(1)
expect(user2.assigned_open_issues_count).to eq(0)
issue.assignee = user2
issue.save
expect(user1.assigned_open_issues_count).to eq(0)
expect(user2.assigned_open_issues_count).to eq(1)
end
end
end

View file

@ -438,4 +438,21 @@ describe MergeRequest, models: true do
expect(mr.participants).to include(note1.author, note2.author)
end
end
describe 'cached counts' do
it 'updates when assignees change' do
user1 = create(:user)
user2 = create(:user)
mr = create(:merge_request, assignee: user1)
expect(user1.assigned_open_merge_request_count).to eq(1)
expect(user2.assigned_open_merge_request_count).to eq(0)
mr.assignee = user2
mr.save
expect(user1.assigned_open_merge_request_count).to eq(0)
expect(user2.assigned_open_merge_request_count).to eq(1)
end
end
end

View file

@ -49,7 +49,7 @@ describe Projects::ImportService, services: true do
result = subject.execute
expect(result[:status]).to eq :error
expect(result[:message]).to eq 'Failed to import the repository'
expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Failed to import the repository"
end
end