summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop.yml7
-rw-r--r--CHANGELOG4
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/todos.js26
-rw-r--r--app/assets/stylesheets/framework/mixins.scss8
-rw-r--r--app/assets/stylesheets/framework/selects.scss2
-rw-r--r--app/assets/stylesheets/pages/search.scss4
-rw-r--r--app/helpers/issuables_helper.rb13
-rw-r--r--app/helpers/todos_helper.rb34
-rw-r--r--app/models/repository.rb17
-rw-r--r--app/views/dashboard/todos/index.html.haml36
-rw-r--r--app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml1
-rw-r--r--doc/install/installation.md4
-rw-r--r--doc/update/8.11-to-8.12.md2
-rw-r--r--features/dashboard/todos.feature20
-rw-r--r--features/steps/dashboard/todos.rb23
-rw-r--r--spec/features/todos/todos_filtering_spec.rb63
-rw-r--r--spec/models/repository_spec.rb18
19 files changed, 206 insertions, 82 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 282f4539f03..5bd31ccf329 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -5,8 +5,8 @@ require:
inherit_from: .rubocop_todo.yml
AllCops:
- TargetRubyVersion: 2.1
- # Cop names are not displayed in offense messages by default. Change behavior
+ TargetRubyVersion: 2.3
+ # Cop names are not d§splayed in offense messages by default. Change behavior
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names
# option.
DisplayCopNames: true
@@ -192,6 +192,9 @@ Style/FlipFlop:
Style/For:
Enabled: true
+# Checks if there is a magic comment to enforce string literals
+Style/FrozenStringLiteralComment:
+ Enabled: false
# Do not introduce global variables.
Style/GlobalVars:
Enabled: true
diff --git a/CHANGELOG b/CHANGELOG
index 67471b5f8ff..bdc5685ed27 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -24,6 +24,7 @@ v 8.12.0 (unreleased)
- Add `wiki_page_events` to project hook APIs (Ben Boeckel)
- Remove Gitorious import
- Fix inconsistent background color for filter input field (ClemMakesApps)
+ - Remove prefixes from transition CSS property (ClemMakesApps)
- Add Sentry logging to API calls
- Add BroadcastMessage API
- Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling)
@@ -68,6 +69,9 @@ v 8.12.0 (unreleased)
- User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496
- Fixed invisible scroll controls on build page on iPhone
+v 8.11.5 (unreleased)
+ - Optimize branch lookups and force a repository reload for Repository#find_branch
+
v 8.11.4 (unreleased)
- Fix broken gitlab:backup:restore because of bad permissions on repo storage !6098 (Dirk Hörner)
- Fix sorting issues by "last updated" doesn't work after import from GitHub
diff --git a/Gemfile b/Gemfile
index 96841013815..620338e5997 100644
--- a/Gemfile
+++ b/Gemfile
@@ -53,7 +53,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem 'gitlab_git', '~> 10.4.7'
+gem 'gitlab_git', '~> 10.5'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
diff --git a/Gemfile.lock b/Gemfile.lock
index 1d0fcfd3c3a..28ede86b3ba 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -279,7 +279,7 @@ GEM
diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3)
- gitlab_git (10.4.7)
+ gitlab_git (10.5.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
@@ -858,7 +858,7 @@ DEPENDENCIES
github-linguist (~> 4.7.0)
github-markup (~> 1.4)
gitlab-flowdock-git-hook (~> 1.0.1)
- gitlab_git (~> 10.4.7)
+ gitlab_git (~> 10.5)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2)
diff --git a/app/assets/javascripts/todos.js b/app/assets/javascripts/todos.js
index 06605320a35..23eda7d44ca 100644
--- a/app/assets/javascripts/todos.js
+++ b/app/assets/javascripts/todos.js
@@ -13,6 +13,7 @@
this.perPage = this.el.data('perPage');
this.clearListeners();
this.initBtnListeners();
+ this.initFilters();
}
Todos.prototype.clearListeners = function() {
@@ -27,6 +28,31 @@
return $('.todo').on('click', this.goToTodoUrl);
};
+ Todos.prototype.initFilters = function() {
+ new UsersSelect();
+ this.initFilterDropdown($('.js-project-search'), 'project_id', ['text']);
+ this.initFilterDropdown($('.js-type-search'), 'type');
+ this.initFilterDropdown($('.js-action-search'), 'action_id');
+
+ $('form.filter-form').on('submit', function (event) {
+ event.preventDefault();
+ Turbolinks.visit(this.action + '&' + $(this).serialize());
+ });
+ };
+
+ Todos.prototype.initFilterDropdown = function($dropdown, fieldName, searchFields) {
+ $dropdown.glDropdown({
+ selectable: true,
+ filterable: searchFields ? true : false,
+ fieldName: fieldName,
+ search: { fields: searchFields },
+ data: $dropdown.data('data'),
+ clicked: function() {
+ return $dropdown.closest('form.filter-form').submit();
+ }
+ })
+ };
+
Todos.prototype.doneClicked = function(e) {
var $this;
e.preventDefault();
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 396a37bab6e..62dc2cb3fdc 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -9,14 +9,6 @@
border-radius: $radius;
}
-@mixin transition($transition) {
- -webkit-transition: $transition;
- -moz-transition: $transition;
- -ms-transition: $transition;
- -o-transition: $transition;
- transition: $transition;
-}
-
/**
* Prefilled mixins
* Mixins with fixed values
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index b2e22b60440..c75dacf95d9 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -151,7 +151,7 @@
background-position: right 0 bottom 6px;
border: 1px solid $input-border;
@include border-radius($border-radius-default);
- @include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s);
+ transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus {
border-color: $input-border-focus;
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index c9d436d72ba..436fb00ba2e 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -80,7 +80,7 @@
.search-icon {
@extend .fa-search;
- @include transition(color .15s);
+ transition: color 0.15s;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
@@ -125,7 +125,7 @@
}
.location-badge {
- @include transition(all .15s);
+ transition: all 0.15s;
background-color: $location-badge-active-bg;
color: $white-light;
}
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index b9baeb1d6c4..5c04bba323f 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -49,6 +49,19 @@ module IssuablesHelper
end
end
+ def project_dropdown_label(project_id, default_label)
+ return default_label if project_id.nil?
+ return "Any project" if project_id == "0"
+
+ project = Project.find_by(id: project_id)
+
+ if project
+ project.name_with_namespace
+ else
+ default_label
+ end
+ end
+
def milestone_dropdown_label(milestone_title, default_label = "Milestone")
if milestone_title == Milestone::Upcoming.name
milestone_title = Milestone::Upcoming.title
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 0465327060e..1e86f648203 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -78,13 +78,11 @@ module TodosHelper
end
def todo_actions_options
- actions = [
- OpenStruct.new(id: '', title: 'Any Action'),
- OpenStruct.new(id: Todo::ASSIGNED, title: 'Assigned'),
- OpenStruct.new(id: Todo::MENTIONED, title: 'Mentioned')
+ [
+ { id: '', text: 'Any Action' },
+ { id: Todo::ASSIGNED, text: 'Assigned' },
+ { id: Todo::MENTIONED, text: 'Mentioned' }
]
-
- options_from_collection_for_select(actions, 'id', 'title', params[:action_id])
end
def todo_projects_options
@@ -92,22 +90,28 @@ module TodosHelper
projects = projects.includes(:namespace)
projects = projects.map do |project|
- OpenStruct.new(id: project.id, title: project.name_with_namespace)
+ { id: project.id, text: project.name_with_namespace }
end
- projects.unshift(OpenStruct.new(id: '', title: 'Any Project'))
-
- options_from_collection_for_select(projects, 'id', 'title', params[:project_id])
+ projects.unshift({ id: '', text: 'Any Project' }).to_json
end
def todo_types_options
- types = [
- OpenStruct.new(title: 'Any Type', name: ''),
- OpenStruct.new(title: 'Issue', name: 'Issue'),
- OpenStruct.new(title: 'Merge Request', name: 'MergeRequest')
+ [
+ { id: '', text: 'Any Type' },
+ { id: 'Issue', text: 'Issue' },
+ { id: 'MergeRequest', text: 'Merge Request' }
]
+ end
+
+ def todo_actions_dropdown_label(selected_action_id, default_action)
+ selected_action = todo_actions_options.find { |action| action[:id] == selected_action_id.to_i}
+ selected_action ? selected_action[:text] : default_action
+ end
- options_from_collection_for_select(types, 'name', 'title', params[:type])
+ def todo_types_dropdown_label(selected_type, default_type)
+ selected_type = todo_types_options.find { |type| type[:id] == selected_type && type[:id] != '' }
+ selected_type ? selected_type[:text] : default_type
end
private
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 91bdafdac99..f891e8374d2 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -120,8 +120,21 @@ class Repository
commits
end
- def find_branch(name)
- raw_repository.branches.find { |branch| branch.name == name }
+ def find_branch(name, fresh_repo: true)
+ # Since the Repository object may have in-memory index changes, invalidating the memoized Repository object may
+ # 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 =
+ if fresh_repo
+ Gitlab::Git::Repository.new(path_to_repo)
+ else
+ raw_repository
+ end
+
+ raw_repo.find_branch(name)
end
def find_tag(name)
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 6bcc37042ea..9d31f31c639 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -28,21 +28,25 @@
.row-content-block.second-block
= form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form' do
.filter-item.inline
- = select_tag('project_id', todo_projects_options,
- class: 'select2 trigger-submit', include_blank: true,
- data: {placeholder: 'Project'})
+ - if params[:project_id].present?
+ = hidden_field_tag(:project_id, params[:project_id])
+ = dropdown_tag(project_dropdown_label(params[:project_id], 'Project'), options: { toggle_class: 'js-project-search js-filter-submit', title: 'Filter by project', filter: true, filterInput: 'input#project-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
+ placeholder: 'Search projects', data: { data: todo_projects_options } })
.filter-item.inline
- = users_select_tag(:author_id, selected: params[:author_id],
- placeholder: 'Author', class: 'trigger-submit', any_user: "Any Author", first_user: true, current_user: true)
+ - if params[:author_id].present?
+ = hidden_field_tag(:author_id, params[:author_id])
+ = dropdown_tag(user_dropdown_label(params[:author_id], 'Author'), options: { toggle_class: 'js-user-search js-filter-submit js-author-search', title: 'Filter by author', filter: true, filterInput: 'input#author-search', dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit',
+ placeholder: 'Search authors', data: { any_user: 'Any Author', first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), selected: params[:author_id], field_name: 'author_id', default_label: 'Author' } })
.filter-item.inline
- = select_tag('type', todo_types_options,
- class: 'select2 trigger-submit', include_blank: true,
- data: {placeholder: 'Type'})
+ - if params[:type].present?
+ = hidden_field_tag(:type, params[:type])
+ = dropdown_tag(todo_types_dropdown_label(params[:type], 'Type'), options: { toggle_class: 'js-type-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-type js-filter-submit',
+ data: { data: todo_types_options } })
.filter-item.inline.actions-filter
- = select_tag('action_id', todo_actions_options,
- class: 'select2 trigger-submit', include_blank: true,
- data: {placeholder: 'Action'})
-
+ - if params[:action_id].present?
+ = hidden_field_tag(:action_id, params[:action_id])
+ = dropdown_tag(todo_actions_dropdown_label(params[:action_id], 'Action'), options: { toggle_class: 'js-action-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-action js-filter-submit',
+ data: { data: todo_actions_options }})
.pull-right
.dropdown.inline.prepend-left-10
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
@@ -76,11 +80,3 @@
= paginate @todos, theme: "gitlab"
- else
.nothing-here-block You're all done!
-
-:javascript
- new UsersSelect();
-
- $('form.filter-form').on('submit', function (event) {
- event.preventDefault();
- Turbolinks.visit(this.action + '&' + $(this).serialize());
- });
diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml
index 31d40f6ad03..576d0bec51b 100644
--- a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml
+++ b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml
@@ -1,4 +1,5 @@
%li.build
+ .curve
.build-content
- if subject.target_url
- link_to subject.target_url do
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 2d0932d4f04..9522c3e7170 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -268,9 +268,9 @@ sudo usermod -aG redis git
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-11-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-12-stable gitlab
-**Note:** You can change `8-11-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `8-12-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
diff --git a/doc/update/8.11-to-8.12.md b/doc/update/8.11-to-8.12.md
index 953e9d7e74c..c8ca42f97bc 100644
--- a/doc/update/8.11-to-8.12.md
+++ b/doc/update/8.11-to-8.12.md
@@ -82,7 +82,7 @@ GitLab 8.1.
```bash
cd /home/git/gitlab-workhorse
sudo -u git -H git fetch --all
-sudo -u git -H git checkout v0.7.8
+sudo -u git -H git checkout v0.7.11
sudo -u git -H make
```
diff --git a/features/dashboard/todos.feature b/features/dashboard/todos.feature
index 42f5d6d2af7..0b23bbb7951 100644
--- a/features/dashboard/todos.feature
+++ b/features/dashboard/todos.feature
@@ -23,26 +23,6 @@ Feature: Dashboard Todos
Then I should see all todos marked as done
@javascript
- Scenario: I filter by project
- Given I filter by "Enterprise"
- Then I should not see todos
-
- @javascript
- Scenario: I filter by author
- Given I filter by "John Doe"
- Then I should not see todos related to "Mary Jane" in the list
-
- @javascript
- Scenario: I filter by type
- Given I filter by "Issue"
- Then I should not see todos related to "Merge Requests" in the list
-
- @javascript
- Scenario: I filter by action
- Given I filter by "Mentioned"
- Then I should not see todos related to "Assignments" in the list
-
- @javascript
Scenario: I click on a todo row
Given I click on the todo
Then I should be directed to the corresponding page
diff --git a/features/steps/dashboard/todos.rb b/features/steps/dashboard/todos.rb
index 0607086c166..344b6fda9a6 100644
--- a/features/steps/dashboard/todos.rb
+++ b/features/steps/dashboard/todos.rb
@@ -3,7 +3,6 @@ class Spinach::Features::DashboardTodos < Spinach::FeatureSteps
include SharedPaths
include SharedProject
include SharedUser
- include Select2Helper
step '"John Doe" is a developer of project "Shop"' do
project.team << [john_doe, :developer]
@@ -55,7 +54,7 @@ class Spinach::Features::DashboardTodos < Spinach::FeatureSteps
expect(page).to have_content 'To do 0'
expect(page).to have_content 'Done 4'
expect(page).to have_content "You're all done!"
- expect(page).not_to have_link project.name_with_namespace
+ expect('.prepend-top-default').not_to have_link project.name_with_namespace
should_not_see_todo "John Doe assigned you merge request #{merge_request.to_reference}"
should_not_see_todo "John Doe mentioned you on issue #{issue.to_reference}"
should_not_see_todo "John Doe assigned you issue #{issue.to_reference}"
@@ -80,19 +79,31 @@ class Spinach::Features::DashboardTodos < Spinach::FeatureSteps
end
step 'I filter by "Enterprise"' do
- select2(enterprise.id, from: "#project_id")
+ click_button 'Project'
+ page.within '.dropdown-menu-project' do
+ click_link enterprise.name_with_namespace
+ end
end
step 'I filter by "John Doe"' do
- select2(john_doe.id, from: "#author_id")
+ click_button 'Author'
+ page.within '.dropdown-menu-author' do
+ click_link john_doe.username
+ end
end
step 'I filter by "Issue"' do
- select2('Issue', from: "#type")
+ click_button 'Type'
+ page.within '.dropdown-menu-type' do
+ click_link 'Issue'
+ end
end
step 'I filter by "Mentioned"' do
- select2("#{Todo::MENTIONED}", from: '#action_id')
+ click_button 'Action'
+ page.within '.dropdown-menu-action' do
+ click_link 'Mentioned'
+ end
end
step 'I should not see todos' do
diff --git a/spec/features/todos/todos_filtering_spec.rb b/spec/features/todos/todos_filtering_spec.rb
new file mode 100644
index 00000000000..83cf306437d
--- /dev/null
+++ b/spec/features/todos/todos_filtering_spec.rb
@@ -0,0 +1,63 @@
+require 'spec_helper'
+
+describe 'Dashboard > User filters todos', feature: true, js: true do
+ include WaitForAjax
+
+ let(:user_1) { create(:user, username: 'user_1', name: 'user_1') }
+ let(:user_2) { create(:user, username: 'user_2', name: 'user_2') }
+
+ let(:project_1) { create(:empty_project, name: 'project_1') }
+ let(:project_2) { create(:empty_project, name: 'project_2') }
+
+ let(:issue) { create(:issue, title: 'issue', project: project_1) }
+
+ let!(:merge_request) { create(:merge_request, source_project: project_2, title: 'merge_request') }
+
+ before do
+ create(:todo, user: user_1, author: user_2, project: project_1, target: issue, action: 1)
+ create(:todo, user: user_1, author: user_1, project: project_2, target: merge_request, action: 2)
+
+ project_1.team << [user_1, :developer]
+ project_2.team << [user_1, :developer]
+ login_as(user_1)
+ visit dashboard_todos_path
+ end
+
+ it 'filters by project' do
+ click_button 'Project'
+ within '.dropdown-menu-project' do
+ fill_in 'Search projects', with: project_1.name_with_namespace
+ click_link project_1.name_with_namespace
+ end
+ wait_for_ajax
+ expect('.prepend-top-default').not_to have_content project_2.name_with_namespace
+ end
+
+ it 'filters by author' do
+ click_button 'Author'
+ within '.dropdown-menu-author' do
+ fill_in 'Search authors', with: user_1.name
+ click_link user_1.name
+ end
+ wait_for_ajax
+ expect('.prepend-top-default').not_to have_content user_2.name
+ end
+
+ it 'filters by type' do
+ click_button 'Type'
+ within '.dropdown-menu-type' do
+ click_link 'Issue'
+ end
+ wait_for_ajax
+ expect('.prepend-top-default').not_to have_content ' merge request !'
+ end
+
+ it 'filters by action' do
+ click_button 'Action'
+ within '.dropdown-menu-action' do
+ click_link 'Assigned'
+ end
+ wait_for_ajax
+ expect('.prepend-top-default').not_to have_content ' mentioned '
+ end
+end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 1fea50ad42c..812c72c48cb 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -382,6 +382,24 @@ describe Repository, models: true do
end
end
+ describe '#find_branch' do
+ it 'loads a branch with a fresh repo' do
+ expect(Gitlab::Git::Repository).to receive(:new).twice.and_call_original
+
+ 2.times do
+ expect(repository.find_branch('feature')).not_to be_nil
+ end
+ end
+
+ it 'loads a branch with a cached repo' do
+ expect(Gitlab::Git::Repository).to receive(:new).once.and_call_original
+
+ 2.times do
+ expect(repository.find_branch('feature', fresh_repo: false)).not_to be_nil
+ end
+ end
+ end
+
describe '#rm_branch' do
let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
let(:blank_sha) { '0000000000000000000000000000000000000000' }