summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Edwards-Jones <jamedjo@gmail.com>2017-06-30 08:33:05 +0000
committerJames Edwards-Jones <jamedjo@gmail.com>2017-06-30 08:33:05 +0000
commitb4b9d3dc3816000920f583f717adcb7c58c11508 (patch)
tree88d84c9b1b8da129abaeed6f5d4706dd5e45057b
parent254b4892f9df9bb40e720417f9c16a849ac00e90 (diff)
parenteaa818a7d67634becba2fa0e110d2b8a548e35e6 (diff)
downloadgitlab-ce-b4b9d3dc3816000920f583f717adcb7c58c11508.tar.gz
Merge branch '9-3-stable-patch-3-mysql' into '9-3-stable'
Prepare 9.3.3 Release See merge request !12508
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_user.js4
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js7
-rw-r--r--app/assets/javascripts/lib/utils/dom_utils.js7
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js4
-rw-r--r--app/assets/javascripts/notes.js2
-rw-r--r--app/assets/javascripts/right_sidebar.js8
-rw-r--r--app/assets/stylesheets/pages/builds.scss1
-rw-r--r--app/models/project.rb27
-rw-r--r--app/services/boards/issues/list_service.rb12
-rw-r--r--app/views/projects/show.html.haml2
-rw-r--r--changelogs/unreleased/dm-dependency-linker-newlines.yml5
-rw-r--r--changelogs/unreleased/fix-34417.yml4
-rw-r--r--changelogs/unreleased/fix-head-pipeline-for-commit-status.yml4
-rw-r--r--changelogs/unreleased/highest-return-on-diff-investment.yml4
-rw-r--r--changelogs/unreleased/issue-boards-closed-list-all.yml4
-rw-r--r--changelogs/unreleased/issue-form-multiple-line-markdown.yml4
-rw-r--r--doc/update/9.2-to-9.3.md6
-rw-r--r--lib/api/commit_statuses.rb3
-rw-r--r--lib/gitlab/dependency_linker/base_linker.rb2
-rw-r--r--lib/gitlab/git.rb4
-rw-r--r--lib/gitlab/git/repository.rb4
-rw-r--r--lib/gitlab/gitaly_client/ref.rb23
-rw-r--r--spec/javascripts/filtered_search/dropdown_user_spec.js34
-rw-r--r--spec/javascripts/lib/utils/dom_utils_spec.js35
-rw-r--r--spec/javascripts/vue_shared/components/markdown/field_spec.js109
-rw-r--r--spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb4
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb24
-rw-r--r--spec/models/project_spec.rb34
-rw-r--r--spec/requests/api/commit_statuses_spec.rb27
-rw-r--r--spec/services/boards/issues/list_service_spec.rb2
31 files changed, 322 insertions, 90 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b442e48a3d0..1139c4419cf 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -63,7 +63,7 @@ stages:
.only-master-and-ee-or-mysql: &only-master-and-ee-or-mysql
only:
- /mysql/
- - /-stable$/
+ - /-stable/
- master@gitlab-org/gitlab-ce
- master@gitlab/gitlabhq
- tags@gitlab-org/gitlab-ce
diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js b/app/assets/javascripts/filtered_search/dropdown_user.js
index 65c1b2050ac..19fed771197 100644
--- a/app/assets/javascripts/filtered_search/dropdown_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_user.js
@@ -2,6 +2,7 @@
import AjaxFilter from '~/droplab/plugins/ajax_filter';
import './filtered_search_dropdown';
+import { addClassIfElementExists } from '../lib/utils/dom_utils';
class DropdownUser extends gl.FilteredSearchDropdown {
constructor(droplab, dropdown, input, tokenKeys, filter) {
@@ -32,8 +33,7 @@ class DropdownUser extends gl.FilteredSearchDropdown {
}
hideCurrentUser() {
- const currenUserItem = this.dropdown.querySelector('.js-current-user');
- currenUserItem.classList.add('hidden');
+ addClassIfElementExists(this.dropdown.querySelector('.js-current-user'), 'hidden');
}
itemClicked(e) {
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index c7c8d42e677..637a94a42b0 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -3,6 +3,7 @@ import RecentSearchesRoot from './recent_searches_root';
import RecentSearchesStore from './stores/recent_searches_store';
import RecentSearchesService from './services/recent_searches_service';
import eventHub from './event_hub';
+import { addClassIfElementExists } from '../lib/utils/dom_utils';
class FilteredSearchManager {
constructor(page) {
@@ -223,11 +224,7 @@ class FilteredSearchManager {
}
addInputContainerFocus() {
- const inputContainer = this.filteredSearchInput.closest('.filtered-search-box');
-
- if (inputContainer) {
- inputContainer.classList.add('focus');
- }
+ addClassIfElementExists(this.filteredSearchInput.closest('.filtered-search-box'), 'focus');
}
removeInputContainerFocus(e) {
diff --git a/app/assets/javascripts/lib/utils/dom_utils.js b/app/assets/javascripts/lib/utils/dom_utils.js
new file mode 100644
index 00000000000..de65ea15a60
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/dom_utils.js
@@ -0,0 +1,7 @@
+/* eslint-disable import/prefer-default-export */
+
+export const addClassIfElementExists = (element, className) => {
+ if (element) {
+ element.classList.add(className);
+ }
+};
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index 601d01e1be1..021f936a4fa 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -94,8 +94,8 @@ gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) {
startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : '';
- if (selectedSplit.length > 1 && (!wrap || (blockTag != null))) {
- if (blockTag != null) {
+ if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) {
+ if (blockTag != null && blockTag !== '') {
insertText = this.blockTagText(text, textArea, blockTag, selected);
} else {
insertText = selectedSplit.map(function(val) {
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 2a999dd61ba..e0a30d2648a 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -1502,7 +1502,7 @@ const normalizeNewlines = function(str) {
const cachedNoteBodyText = $noteBodyText.html();
// Show updated comment content temporarily
- $noteBodyText.html(_.escape(formContent));
+ $noteBodyText.html(formContent);
$editingNote.removeClass('is-editing fade-in-full').addClass('being-posted fade-in-half');
$editingNote.find('.note-headline-meta a').html('<i class="fa fa-spinner fa-spin" aria-label="Comment is being updated" aria-hidden="true"></i>');
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 322162afdb8..b5cd01044a3 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -10,6 +10,8 @@ import Cookies from 'js-cookie';
this.$sidebarInner = this.sidebar.find('.issuable-sidebar');
this.$navGitlab = $('.navbar-gitlab');
+ this.$layoutNav = $('.layout-nav');
+ this.$subScroll = $('.sub-nav-scroll');
this.$rightSidebar = $('.js-right-sidebar');
this.removeListeners();
@@ -27,14 +29,14 @@ import Cookies from 'js-cookie';
Sidebar.prototype.addEventListeners = function() {
const $document = $(document);
const throttledSetSidebarHeight = _.throttle(this.setSidebarHeight.bind(this), 20);
- const debouncedSetSidebarHeight = _.debounce(this.setSidebarHeight.bind(this), 200);
+ const slowerThrottledSetSidebarHeight = _.throttle(this.setSidebarHeight.bind(this), 200);
this.sidebar.on('click', '.sidebar-collapsed-icon', this, this.sidebarCollapseClicked);
$('.dropdown').on('hidden.gl.dropdown', this, this.onSidebarDropdownHidden);
$('.dropdown').on('loading.gl.dropdown', this.sidebarDropdownLoading);
$('.dropdown').on('loaded.gl.dropdown', this.sidebarDropdownLoaded);
$(window).on('resize', () => throttledSetSidebarHeight());
- $document.on('scroll', () => debouncedSetSidebarHeight());
+ $document.on('scroll', () => slowerThrottledSetSidebarHeight());
$document.on('click', '.js-sidebar-toggle', function(e, triggered) {
var $allGutterToggleIcons, $this, $thisIcon;
e.preventDefault();
@@ -213,7 +215,7 @@ import Cookies from 'js-cookie';
};
Sidebar.prototype.setSidebarHeight = function() {
- const $navHeight = this.$navGitlab.outerHeight();
+ const $navHeight = this.$navGitlab.outerHeight() + this.$layoutNav.outerHeight() + (this.$subScroll ? this.$subScroll.outerHeight() : 0);
const diff = $navHeight - $(window).scrollTop();
if (diff > 0) {
this.$rightSidebar.outerHeight($(window).height() - diff);
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index a5a876d167b..68c8f111454 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -402,6 +402,7 @@
.build-light-text {
color: $gl-text-color-secondary;
+ word-wrap: break-word;
}
.build-gutter-toggle {
diff --git a/app/models/project.rb b/app/models/project.rb
index 4b289d15ae7..cf6515b9fa3 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -352,7 +352,16 @@ class Project < ActiveRecord::Base
after_transition started: :finished do |project, _|
project.reset_cache_and_import_attrs
- project.perform_housekeeping
+
+ if Gitlab::ImportSources.importer_names.include?(project.import_type) && project.repo_exists?
+ project.run_after_commit do
+ begin
+ Projects::HousekeepingService.new(project).execute
+ rescue Projects::HousekeepingService::LeaseTaken => e
+ Rails.logger.info("Could not perform housekeeping for project #{project.path_with_namespace} (#{project.id}): #{e}")
+ end
+ end
+ end
end
end
@@ -510,22 +519,6 @@ class Project < ActiveRecord::Base
ProjectCacheWorker.perform_async(self.id)
end
- remove_import_data
- end
-
- def perform_housekeeping
- return unless repo_exists?
-
- run_after_commit do
- begin
- Projects::HousekeepingService.new(self).execute
- rescue Projects::HousekeepingService::LeaseTaken => e
- Rails.logger.info("Could not perform housekeeping for project #{self.path_with_namespace} (#{self.id}): #{e}")
- end
- end
- end
-
- def remove_import_data
import_data&.destroy
end
diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb
index 418fa9afd6e..a1d67cbc244 100644
--- a/app/services/boards/issues/list_service.rb
+++ b/app/services/boards/issues/list_service.rb
@@ -3,7 +3,7 @@ module Boards
class ListService < BaseService
def execute
issues = IssuesFinder.new(current_user, filter_params).execute
- issues = without_board_labels(issues) unless movable_list?
+ issues = without_board_labels(issues) unless movable_list? || closed_list?
issues = with_list_label(issues) if movable_list?
issues.order_by_position_and_priority
end
@@ -21,7 +21,15 @@ module Boards
end
def movable_list?
- @movable_list ||= list.present? && list.movable?
+ return @movable_list if defined?(@movable_list)
+
+ @movable_list = list.present? && list.movable?
+ end
+
+ def closed_list?
+ return @closed_list if defined?(@closed_list)
+
+ @closed_list = list.present? && list.closed?
end
def filter_params
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 7447197ed89..e1e70a53709 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -21,7 +21,7 @@
%li
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
#{n_('Commit', 'Commits', @project.statistics.commit_count)} (#{number_with_delimiter(@project.statistics.commit_count)})
- %l
+ %li
= link_to namespace_project_branches_path(@project.namespace, @project) do
#{n_('Branch', 'Branches', @repository.branch_count)} (#{number_with_delimiter(@repository.branch_count)})
%li
diff --git a/changelogs/unreleased/dm-dependency-linker-newlines.yml b/changelogs/unreleased/dm-dependency-linker-newlines.yml
new file mode 100644
index 00000000000..5631095fcb7
--- /dev/null
+++ b/changelogs/unreleased/dm-dependency-linker-newlines.yml
@@ -0,0 +1,5 @@
+---
+title: Fix diff of requirements.txt file by not matching newlines as part of package
+ names
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-34417.yml b/changelogs/unreleased/fix-34417.yml
new file mode 100644
index 00000000000..5f012ad0c81
--- /dev/null
+++ b/changelogs/unreleased/fix-34417.yml
@@ -0,0 +1,4 @@
+---
+title: Perform housekeeping only when an import of a fresh project is completed
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-head-pipeline-for-commit-status.yml b/changelogs/unreleased/fix-head-pipeline-for-commit-status.yml
new file mode 100644
index 00000000000..f12e7b53790
--- /dev/null
+++ b/changelogs/unreleased/fix-head-pipeline-for-commit-status.yml
@@ -0,0 +1,4 @@
+---
+title: Fix head pipeline stored in merge request for external pipelines
+merge_request: 12478
+author:
diff --git a/changelogs/unreleased/highest-return-on-diff-investment.yml b/changelogs/unreleased/highest-return-on-diff-investment.yml
new file mode 100644
index 00000000000..c8be1e0ff8f
--- /dev/null
+++ b/changelogs/unreleased/highest-return-on-diff-investment.yml
@@ -0,0 +1,4 @@
+---
+title: Bring back branches badge to main project page
+merge_request: 12548
+author:
diff --git a/changelogs/unreleased/issue-boards-closed-list-all.yml b/changelogs/unreleased/issue-boards-closed-list-all.yml
new file mode 100644
index 00000000000..7643864150d
--- /dev/null
+++ b/changelogs/unreleased/issue-boards-closed-list-all.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed issue boards closed list not showing all closed issues
+merge_request:
+author:
diff --git a/changelogs/unreleased/issue-form-multiple-line-markdown.yml b/changelogs/unreleased/issue-form-multiple-line-markdown.yml
new file mode 100644
index 00000000000..23128f346bc
--- /dev/null
+++ b/changelogs/unreleased/issue-form-multiple-line-markdown.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed multi-line markdown tooltip buttons in issue edit form
+merge_request:
+author:
diff --git a/doc/update/9.2-to-9.3.md b/doc/update/9.2-to-9.3.md
index 0c32e4db53f..8fbcc892fd5 100644
--- a/doc/update/9.2-to-9.3.md
+++ b/doc/update/9.2-to-9.3.md
@@ -117,7 +117,7 @@ cd /home/git/gitlab
sudo -u git -H git checkout 9-3-stable-ee
```
-### 5. Update gitlab-shell
+### 7. Update gitlab-shell
```bash
cd /home/git/gitlab-shell
@@ -127,7 +127,7 @@ sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_SHELL_VERSION)
sudo -u git -H bin/compile
```
-### 6. Update gitlab-workhorse
+### 8. Update gitlab-workhorse
Install and compile gitlab-workhorse. This requires
[Go 1.5](https://golang.org/dl) which should already be on your system from
@@ -143,7 +143,7 @@ sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_WORKHORSE_VERSION)
sudo -u git -H make
```
-### 7. Update Gitaly
+### 9. Update Gitaly
If you have not yet set up Gitaly then follow [Gitaly section of the installation
guide](../install/installation.md#install-gitaly).
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 10f2d5ef6a3..485b680cd5f 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -108,6 +108,9 @@ module API
render_api_error!('invalid state', 400)
end
+ MergeRequest.where(source_project: @project, source_branch: ref)
+ .update_all(head_pipeline_id: pipeline) if pipeline.latest?
+
present status, with: Entities::CommitStatus
rescue StateMachines::InvalidTransition => e
render_api_error!(e.message, 400)
diff --git a/lib/gitlab/dependency_linker/base_linker.rb b/lib/gitlab/dependency_linker/base_linker.rb
index 7bbd154eb03..d2360583741 100644
--- a/lib/gitlab/dependency_linker/base_linker.rb
+++ b/lib/gitlab/dependency_linker/base_linker.rb
@@ -52,7 +52,7 @@ module Gitlab
# # Will link `user/repo` in `github: "user/repo"` or `:github => "user/repo"`
def link_regex(regex, &url_proc)
highlighted_lines.map!.with_index do |rich_line, i|
- marker = StringRegexMarker.new(plain_lines[i], rich_line.html_safe)
+ marker = StringRegexMarker.new(plain_lines[i].chomp, rich_line.html_safe)
marker.mark(regex, group: :name) do |text, left:, right:|
url = yield(text)
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 936606152e9..4175746be39 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -7,8 +7,10 @@ module Gitlab
CommandError = Class.new(StandardError)
class << self
+ include Gitlab::EncodingHelper
+
def ref_name(ref)
- ref.sub(/\Arefs\/(tags|heads)\//, '')
+ encode! ref.sub(/\Arefs\/(tags|heads)\//, '')
end
def branch_name(ref)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 85695d0a4df..e3ec2c84c48 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -113,9 +113,7 @@ module Gitlab
def local_branches(sort_by: nil)
gitaly_migrate(:local_branches) do |is_enabled|
if is_enabled
- gitaly_ref_client.local_branches(sort_by: sort_by).map do |gitaly_branch|
- Gitlab::Git::Branch.new(self, gitaly_branch.name, gitaly_branch)
- end
+ gitaly_ref_client.local_branches(sort_by: sort_by)
else
branches(filter: :local, sort_by: sort_by)
end
diff --git a/lib/gitlab/gitaly_client/ref.rb b/lib/gitlab/gitaly_client/ref.rb
index 227fe45642e..4ab7def12a8 100644
--- a/lib/gitlab/gitaly_client/ref.rb
+++ b/lib/gitlab/gitaly_client/ref.rb
@@ -1,10 +1,13 @@
module Gitlab
module GitalyClient
class Ref
+ include Gitlab::EncodingHelper
+
attr_accessor :stub
# 'repository' is a Gitlab::Git::Repository
def initialize(repository)
+ @repository = repository
@gitaly_repo = repository.gitaly_repository
@stub = GitalyClient.stub(:ref, repository.storage)
end
@@ -18,12 +21,12 @@ module Gitlab
def branch_names
request = Gitaly::FindAllBranchNamesRequest.new(repository: @gitaly_repo)
- consume_refs_response(stub.find_all_branch_names(request), prefix: 'refs/heads/')
+ consume_refs_response(stub.find_all_branch_names(request)) { |name| Gitlab::Git.branch_name(name) }
end
def tag_names
request = Gitaly::FindAllTagNamesRequest.new(repository: @gitaly_repo)
- consume_refs_response(stub.find_all_tag_names(request), prefix: 'refs/tags/')
+ consume_refs_response(stub.find_all_tag_names(request)) { |name| Gitlab::Git.tag_name(name) }
end
def find_ref_name(commit_id, ref_prefix)
@@ -52,10 +55,8 @@ module Gitlab
private
- def consume_refs_response(response, prefix:)
- response.flat_map do |r|
- r.names.map { |name| name.sub(/\A#{Regexp.escape(prefix)}/, '') }
- end
+ def consume_refs_response(response)
+ response.flat_map { |message| message.names.map { |name| yield(name) } }
end
def sort_by_param(sort_by)
@@ -65,7 +66,15 @@ module Gitlab
end
def consume_branches_response(response)
- response.flat_map { |r| r.branches }
+ response.flat_map do |message|
+ message.branches.map do |gitaly_branch|
+ Gitlab::Git::Branch.new(
+ @repository,
+ encode!(gitaly_branch.name.dup),
+ gitaly_branch.commit_id
+ )
+ end
+ end
end
end
end
diff --git a/spec/javascripts/filtered_search/dropdown_user_spec.js b/spec/javascripts/filtered_search/dropdown_user_spec.js
index f7708301b6e..0132f4b7c93 100644
--- a/spec/javascripts/filtered_search/dropdown_user_spec.js
+++ b/spec/javascripts/filtered_search/dropdown_user_spec.js
@@ -66,4 +66,38 @@ describe('Dropdown User', () => {
window.gon = {};
});
});
+
+ describe('hideCurrentUser', () => {
+ const fixtureTemplate = 'issues/issue_list.html.raw';
+ preloadFixtures(fixtureTemplate);
+
+ let dropdown;
+ let authorFilterDropdownElement;
+
+ beforeEach(() => {
+ loadFixtures(fixtureTemplate);
+ authorFilterDropdownElement = document.querySelector('#js-dropdown-author');
+ const dummyInput = document.createElement('div');
+ dropdown = new gl.DropdownUser(null, authorFilterDropdownElement, dummyInput);
+ });
+
+ const findCurrentUserElement = () => authorFilterDropdownElement.querySelector('.js-current-user');
+
+ it('hides the current user from dropdown', () => {
+ const currentUserElement = findCurrentUserElement();
+ expect(currentUserElement).not.toBe(null);
+
+ dropdown.hideCurrentUser();
+
+ expect(currentUserElement.classList).toContain('hidden');
+ });
+
+ it('does nothing if no user is logged in', () => {
+ const currentUserElement = findCurrentUserElement();
+ currentUserElement.parentNode.removeChild(currentUserElement);
+ expect(findCurrentUserElement()).toBe(null);
+
+ dropdown.hideCurrentUser();
+ });
+ });
});
diff --git a/spec/javascripts/lib/utils/dom_utils_spec.js b/spec/javascripts/lib/utils/dom_utils_spec.js
new file mode 100644
index 00000000000..867bf5912d1
--- /dev/null
+++ b/spec/javascripts/lib/utils/dom_utils_spec.js
@@ -0,0 +1,35 @@
+import { addClassIfElementExists } from '~/lib/utils/dom_utils';
+
+describe('DOM Utils', () => {
+ describe('addClassIfElementExists', () => {
+ const className = 'biology';
+ const fixture = `
+ <div class="parent">
+ <div class="child"></div>
+ </div>
+ `;
+
+ let parentElement;
+
+ beforeEach(() => {
+ setFixtures(fixture);
+ parentElement = document.querySelector('.parent');
+ });
+
+ it('adds class if element exists', () => {
+ const childElement = parentElement.querySelector('.child');
+ expect(childElement).not.toBe(null);
+
+ addClassIfElementExists(childElement, className);
+
+ expect(childElement.classList).toContain(className);
+ });
+
+ it('does not throw if element does not exist', () => {
+ const childElement = parentElement.querySelector('.other-child');
+ expect(childElement).toBe(null);
+
+ addClassIfElementExists(childElement, className);
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/markdown/field_spec.js b/spec/javascripts/vue_shared/components/markdown/field_spec.js
index 4bbaff561fc..52f7ae8b3b1 100644
--- a/spec/javascripts/vue_shared/components/markdown/field_spec.js
+++ b/spec/javascripts/vue_shared/components/markdown/field_spec.js
@@ -2,49 +2,43 @@ import Vue from 'vue';
import fieldComponent from '~/vue_shared/components/markdown/field.vue';
describe('Markdown field component', () => {
+ let el;
let vm;
- beforeEach(() => {
+ beforeEach((done) => {
+ el = document.createElement('div');
+ document.body.appendChild(el);
+
vm = new Vue({
- render(createElement) {
- return createElement(
- fieldComponent,
- {
- props: {
- markdownPreviewUrl: '/preview',
- markdownDocs: '/docs',
- },
- },
- [
- createElement('textarea', {
- slot: 'textarea',
- }),
- ],
- );
+ data() {
+ return {
+ text: 'testing\n123',
+ };
},
- });
+ components: {
+ fieldComponent,
+ },
+ template: `
+ <field-component
+ marodown-preview-url="/preview"
+ markdown-docs="/docs"
+ >
+ <textarea
+ slot="textarea"
+ v-model="text">
+ </textarea>
+ </field-component>
+ `,
+ }).$mount(el);
+
+ Vue.nextTick(done);
});
- it('creates a new instance of GL form', (done) => {
- spyOn(gl, 'GLForm');
- vm.$mount();
-
- Vue.nextTick(() => {
- expect(
- gl.GLForm,
- ).toHaveBeenCalled();
-
- done();
- });
+ afterEach(() => {
+ vm.$destroy();
});
describe('mounted', () => {
- beforeEach((done) => {
- vm.$mount();
-
- Vue.nextTick(done);
- });
-
it('renders textarea inside backdrop', () => {
expect(
vm.$el.querySelector('.zen-backdrop textarea'),
@@ -117,5 +111,52 @@ describe('Markdown field component', () => {
});
});
});
+
+ describe('markdown buttons', () => {
+ it('converts single words', (done) => {
+ const textarea = vm.$el.querySelector('textarea');
+
+ textarea.setSelectionRange(0, 7);
+ vm.$el.querySelector('.js-md').click();
+
+ Vue.nextTick(() => {
+ expect(
+ textarea.value,
+ ).toContain('**testing**');
+
+ done();
+ });
+ });
+
+ it('converts a line', (done) => {
+ const textarea = vm.$el.querySelector('textarea');
+
+ textarea.setSelectionRange(0, 0);
+ vm.$el.querySelectorAll('.js-md')[4].click();
+
+ Vue.nextTick(() => {
+ expect(
+ textarea.value,
+ ).toContain('* testing');
+
+ done();
+ });
+ });
+
+ it('converts multiple lines', (done) => {
+ const textarea = vm.$el.querySelector('textarea');
+
+ textarea.setSelectionRange(0, 50);
+ vm.$el.querySelectorAll('.js-md')[4].click();
+
+ Vue.nextTick(() => {
+ expect(
+ textarea.value,
+ ).toContain('* testing\n* 123');
+
+ done();
+ });
+ });
+ });
});
});
diff --git a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
index 7e32770f95d..64b233f3e68 100644
--- a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
@@ -87,5 +87,9 @@ describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do
it 'links URLs' do
expect(subject).to include(link('http://wxpython.org/Phoenix/snapshot-builds/wxPython_Phoenix-3.0.3.dev1820+49a8884-cp34-none-win_amd64.whl', 'http://wxpython.org/Phoenix/snapshot-builds/wxPython_Phoenix-3.0.3.dev1820+49a8884-cp34-none-win_amd64.whl'))
end
+
+ it 'does not contain link with a newline as package name' do
+ expect(subject).not_to include(link("\n", "https://pypi.python.org/pypi/\n"))
+ end
end
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index e1e4aa9fde9..daf5e5e2044 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -24,6 +24,10 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ it 'returns UTF-8' do
+ expect(repository.root_ref.encoding).to eq(Encoding.find('UTF-8'))
+ end
+
context 'with gitaly enabled' do
before { stub_gitaly }
after { Gitlab::GitalyClient.clear_stubs! }
@@ -116,6 +120,11 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'has SeedRepo::Repo::BRANCHES.size elements' do
expect(subject.size).to eq(SeedRepo::Repo::BRANCHES.size)
end
+
+ it 'returns UTF-8' do
+ expect(subject.first.encoding).to eq(Encoding.find('UTF-8'))
+ end
+
it { is_expected.to include("master") }
it { is_expected.not_to include("branch-from-space") }
@@ -146,10 +155,15 @@ describe Gitlab::Git::Repository, seed_helper: true do
subject { repository.tag_names }
it { is_expected.to be_kind_of Array }
+
it 'has SeedRepo::Repo::TAGS.size elements' do
expect(subject.size).to eq(SeedRepo::Repo::TAGS.size)
end
+ it 'returns UTF-8' do
+ expect(subject.first.encoding).to eq(Encoding.find('UTF-8'))
+ end
+
describe '#last' do
subject { super().last }
it { is_expected.to eq("v1.2.1") }
@@ -1283,6 +1297,16 @@ describe Gitlab::Git::Repository, seed_helper: true do
before { stub_gitaly }
after { Gitlab::GitalyClient.clear_stubs! }
+ it 'returns a Branch with UTF-8 fields' do
+ branches = @repo.local_branches.to_a
+ expect(branches.size).to be > 0
+ utf_8 = Encoding.find('utf-8')
+ branches.each do |branch|
+ expect(branch.name.encoding).to eq(utf_8)
+ expect(branch.target.encoding).to eq(utf_8) unless branch.target.nil?
+ end
+ end
+
it 'gets the branches from GitalyClient' do
expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:local_branches).
and_return([])
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 820c6edd36f..d97866d695d 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1466,6 +1466,40 @@ describe Project, models: true do
end
end
+ describe 'project import state transitions' do
+ context 'state transition: [:started] => [:finished]' do
+ let(:housekeeping_service) { spy }
+
+ before do
+ allow(Projects::HousekeepingService).to receive(:new) { housekeeping_service }
+ end
+
+ it 'performs housekeeping when an import of a fresh project is completed' do
+ project = create(:project_empty_repo, :import_started, import_type: :github)
+
+ project.import_finish
+
+ expect(housekeeping_service).to have_received(:execute)
+ end
+
+ it 'does not perform housekeeping when project repository does not exist' do
+ project = create(:empty_project, :import_started, import_type: :github)
+
+ project.import_finish
+
+ expect(housekeeping_service).not_to have_received(:execute)
+ end
+
+ it 'does not perform housekeeping when project does not have a valid import type' do
+ project = create(:empty_project, :import_started, import_type: nil)
+
+ project.import_finish
+
+ expect(housekeeping_service).not_to have_received(:execute)
+ end
+ end
+ end
+
describe '#latest_successful_builds_for' do
def create_pipeline(status = 'success')
create(:ci_pipeline, project: project,
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index 6b637a03b6f..5be25937c35 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -150,25 +150,40 @@ describe API::CommitStatuses do
context 'with all optional parameters' do
context 'when creating a commit status' do
- it 'creates commit status' do
+ subject do
post api(post_url, developer), {
state: 'success',
context: 'coverage',
- ref: 'develop',
+ ref: 'master',
description: 'test',
coverage: 80.0,
target_url: 'http://gitlab.com/status'
}
+ end
+
+ it 'creates commit status' do
+ subject
expect(response).to have_http_status(201)
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
expect(json_response['name']).to eq('coverage')
- expect(json_response['ref']).to eq('develop')
+ expect(json_response['ref']).to eq('master')
expect(json_response['coverage']).to eq(80.0)
expect(json_response['description']).to eq('test')
expect(json_response['target_url']).to eq('http://gitlab.com/status')
end
+
+ context 'when merge request exists for given branch' do
+ let!(:merge_request) { create(:merge_request, source_project: project, source_branch: 'master', target_branch: 'develop') }
+
+ it 'sets head pipeline' do
+ subject
+
+ expect(response).to have_http_status(201)
+ expect(merge_request.reload.head_pipeline).not_to be_nil
+ end
+ end
end
context 'when updatig a commit status' do
@@ -176,7 +191,7 @@ describe API::CommitStatuses do
post api(post_url, developer), {
state: 'running',
context: 'coverage',
- ref: 'develop',
+ ref: 'master',
description: 'coverage test',
coverage: 0.0,
target_url: 'http://gitlab.com/status'
@@ -185,7 +200,7 @@ describe API::CommitStatuses do
post api(post_url, developer), {
state: 'success',
name: 'coverage',
- ref: 'develop',
+ ref: 'master',
description: 'new description',
coverage: 90.0
}
@@ -196,7 +211,7 @@ describe API::CommitStatuses do
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
expect(json_response['name']).to eq('coverage')
- expect(json_response['ref']).to eq('develop')
+ expect(json_response['ref']).to eq('master')
expect(json_response['coverage']).to eq(90.0)
expect(json_response['description']).to eq('new description')
expect(json_response['target_url']).to eq('http://gitlab.com/status')
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index a1e220c2322..a66cc2cd6e9 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -67,7 +67,7 @@ describe Boards::Issues::ListService, services: true do
issues = described_class.new(project, user, params).execute
- expect(issues).to eq [closed_issue4, closed_issue2, closed_issue3, closed_issue1]
+ expect(issues).to eq [closed_issue4, closed_issue2, closed_issue5, closed_issue3, closed_issue1]
end
it 'returns opened issues that have label list applied when listing issues from a label list' do