summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--app/assets/javascripts/behaviors/copy_as_gfm.js7
-rw-r--r--app/assets/javascripts/deploy_keys/components/app.vue1
-rw-r--r--changelogs/unreleased/32546-cannot-copy-paste-on-ios.yml5
-rw-r--r--doc/development/fe_guide/axios.md2
-rw-r--r--lib/gitlab/gitaly_client/conflicts_service.rb5
-rw-r--r--qa/qa/factory/resource/deploy_key.rb6
-rw-r--r--qa/qa/page/project/settings/deploy_keys.rb7
-rw-r--r--qa/qa/specs/features/project/add_deploy_key_spec.rb12
-rwxr-xr-xscripts/gitaly-test-build16
-rw-r--r--scripts/prepare_build.sh2
-rw-r--r--spec/javascripts/blob/notebook/index_spec.js6
-rw-r--r--spec/javascripts/boards/board_card_spec.js2
-rw-r--r--spec/javascripts/boards/board_list_spec.js2
-rw-r--r--spec/javascripts/boards/board_new_issue_spec.js2
-rw-r--r--spec/javascripts/boards/boards_store_spec.js2
-rw-r--r--spec/javascripts/boards/list_spec.js2
-rw-r--r--spec/javascripts/issue_show/components/app_spec.js2
-rw-r--r--spec/javascripts/jobs/job_details_mediator_spec.js8
-rw-r--r--spec/javascripts/monitoring/dashboard_spec.js2
-rw-r--r--spec/models/repository_spec.rb8
21 files changed, 69 insertions, 32 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f9c5ebe7a35..bb1c84ab918 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,7 +6,7 @@ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.6-golang-1.9-git
- gitlab-org
.default-cache: &default-cache
- key: "ruby-235-with-yarn"
+ key: "ruby-2.3.6-with-yarn"
paths:
- vendor/ruby
- .yarn-cache/
diff --git a/app/assets/javascripts/behaviors/copy_as_gfm.js b/app/assets/javascripts/behaviors/copy_as_gfm.js
index c6eca72c51b..ffe90595b5d 100644
--- a/app/assets/javascripts/behaviors/copy_as_gfm.js
+++ b/app/assets/javascripts/behaviors/copy_as_gfm.js
@@ -299,6 +299,13 @@ const gfmRules = {
export class CopyAsGFM {
constructor() {
+ // iOS currently does not support clipboardData.setData(). This bug should
+ // be fixed in iOS 12, but for now we'll disable this for all iOS browsers
+ // ref: https://trac.webkit.org/changeset/222228/webkit
+ const userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || '';
+ const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);
+ if (isIOS) return;
+
$(document).on('copy', '.md, .wiki', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection); });
$(document).on('copy', 'pre.code.highlight, .diff-content .line_content', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformCodeSelection); });
$(document).on('paste', '.js-gfm-input', CopyAsGFM.pasteGFM);
diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue
index 7b68b19de75..5a782237b7d 100644
--- a/app/assets/javascripts/deploy_keys/components/app.vue
+++ b/app/assets/javascripts/deploy_keys/components/app.vue
@@ -87,6 +87,7 @@
<div v-else-if="hasKeys">
<keys-panel
title="Enabled deploy keys for this project"
+ class="qa-project-deploy-keys"
:keys="keys.enabled_keys"
:store="store"
:endpoint="endpoint"
diff --git a/changelogs/unreleased/32546-cannot-copy-paste-on-ios.yml b/changelogs/unreleased/32546-cannot-copy-paste-on-ios.yml
new file mode 100644
index 00000000000..f4c44983736
--- /dev/null
+++ b/changelogs/unreleased/32546-cannot-copy-paste-on-ios.yml
@@ -0,0 +1,5 @@
+---
+title: Fix copy/paste on iOS devices due to a bug in webkit
+merge_request: 15804
+author:
+type: fixed
diff --git a/doc/development/fe_guide/axios.md b/doc/development/fe_guide/axios.md
index dcd8f5cb839..0d9397c3bd5 100644
--- a/doc/development/fe_guide/axios.md
+++ b/doc/development/fe_guide/axios.md
@@ -63,7 +63,7 @@ We have also decided against using [axios interceptors] because they are not sui
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
```
diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb
index 2565d537aff..e14734495a8 100644
--- a/lib/gitlab/gitaly_client/conflicts_service.rb
+++ b/lib/gitlab/gitaly_client/conflicts_service.rb
@@ -25,6 +25,11 @@ module Gitlab
def conflicts?
list_conflict_files.any?
+ rescue GRPC::FailedPrecondition
+ # The server raises this exception when it encounters ConflictSideMissing, which
+ # means a conflict exists but its `theirs` or `ours` data is nil due to a non-existent
+ # file in one of the trees.
+ true
end
def resolve_conflicts(target_repository, resolution, source_branch, target_branch)
diff --git a/qa/qa/factory/resource/deploy_key.rb b/qa/qa/factory/resource/deploy_key.rb
index 7c58e70bcc4..671114d38b1 100644
--- a/qa/qa/factory/resource/deploy_key.rb
+++ b/qa/qa/factory/resource/deploy_key.rb
@@ -4,6 +4,12 @@ module QA
class DeployKey < Factory::Base
attr_accessor :title, :key
+ product :title do
+ Page::Project::Settings::Repository.act do
+ expand_deploy_keys(&:key_title)
+ end
+ end
+
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-to-deploy'
project.description = 'project for adding deploy key test'
diff --git a/qa/qa/page/project/settings/deploy_keys.rb b/qa/qa/page/project/settings/deploy_keys.rb
index bf42767c707..f9e40bf4252 100644
--- a/qa/qa/page/project/settings/deploy_keys.rb
+++ b/qa/qa/page/project/settings/deploy_keys.rb
@@ -10,6 +10,7 @@ module QA
view 'app/assets/javascripts/deploy_keys/components/app.vue' do
element :deploy_keys_section, /class=".*deploy\-keys.*"/
+ element :project_deploy_keys, 'class="qa-project-deploy-keys"'
end
view 'app/assets/javascripts/deploy_keys/components/key.vue' do
@@ -29,9 +30,9 @@ module QA
click_on 'Add key'
end
- def has_key_title?(title)
- page.within('.deploy-keys') do
- page.find('.title', text: title)
+ def key_title
+ page.within('.qa-project-deploy-keys') do
+ page.find('.title').text
end
end
end
diff --git a/qa/qa/specs/features/project/add_deploy_key_spec.rb b/qa/qa/specs/features/project/add_deploy_key_spec.rb
index 43a85213501..7a123e539e1 100644
--- a/qa/qa/specs/features/project/add_deploy_key_spec.rb
+++ b/qa/qa/specs/features/project/add_deploy_key_spec.rb
@@ -7,16 +7,12 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
- Factory::Resource::DeployKey.fabricate! do |deploy_key|
- deploy_key.title = deploy_key_title
- deploy_key.key = deploy_key_value
+ deploy_key = Factory::Resource::DeployKey.fabricate! do |resource|
+ resource.title = deploy_key_title
+ resource.key = deploy_key_value
end
- Page::Project::Settings::Repository.perform do |setting|
- setting.expand_deploy_keys do |page|
- expect(page).to have_key_title(deploy_key_title)
- end
- end
+ expect(deploy_key.title).to eq(deploy_key_title)
end
end
end
diff --git a/scripts/gitaly-test-build b/scripts/gitaly-test-build
index 95d9fe0f176..b42ae2a2595 100755
--- a/scripts/gitaly-test-build
+++ b/scripts/gitaly-test-build
@@ -9,11 +9,21 @@ require 'fileutils'
# called 'bundle install' using a different Gemfile, as happens with
# gitlab-ce and gitaly.
-dir = 'tmp/tests/gitaly'
+tmp_tests_gitaly_dir = File.expand_path('../tmp/tests/gitaly', __dir__)
-abort 'gitaly build failed' unless system('make', chdir: dir)
+# Use the top-level bundle vendor folder so that we don't reinstall gems twice
+bundle_vendor_path = File.expand_path('../vendor', __dir__)
+
+env = {
+ # This ensure the `clean` config set in `scripts/prepare_build.sh` isn't taken into account
+ 'BUNDLE_IGNORE_CONFIG' => 'true',
+ 'BUNDLE_GEMFILE' => File.join(tmp_tests_gitaly_dir, 'ruby', 'Gemfile'),
+ 'BUNDLE_FLAGS' => "--jobs=4 --path=#{bundle_vendor_path} --retry=3"
+}
+
+abort 'gitaly build failed' unless system(env, 'make', chdir: tmp_tests_gitaly_dir)
# Make the 'gitaly' executable look newer than 'GITALY_SERVER_VERSION'.
# Without this a gitaly executable created in the setup-test-env job
# will look stale compared to GITALY_SERVER_VERSION.
-FileUtils.touch(File.join(dir, 'gitaly'), mtime: Time.now + (1 << 24))
+FileUtils.touch(File.join(tmp_tests_gitaly_dir, 'gitaly'), mtime: Time.now + (1 << 24))
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index ea406aadf39..206d62dbc78 100644
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -3,7 +3,7 @@
export SETUP_DB=${SETUP_DB:-true}
export CREATE_DB_USER=${CREATE_DB_USER:-$SETUP_DB}
export USE_BUNDLE_INSTALL=${USE_BUNDLE_INSTALL:-true}
-export BUNDLE_INSTALL_FLAGS="--without production --jobs $(nproc) --path vendor --retry 3 --quiet"
+export BUNDLE_INSTALL_FLAGS="--without=production --jobs=$(nproc) --path=vendor --retry=3 --quiet"
if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
bundle install --clean $BUNDLE_INSTALL_FLAGS && bundle check
diff --git a/spec/javascripts/blob/notebook/index_spec.js b/spec/javascripts/blob/notebook/index_spec.js
index df1b2c9960b..a143fc827d5 100644
--- a/spec/javascripts/blob/notebook/index_spec.js
+++ b/spec/javascripts/blob/notebook/index_spec.js
@@ -45,7 +45,7 @@ describe('iPython notebook renderer', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('does not show loading icon', () => {
@@ -96,7 +96,7 @@ describe('iPython notebook renderer', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('does not show loading icon', () => {
@@ -127,7 +127,7 @@ describe('iPython notebook renderer', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('does not show loading icon', () => {
diff --git a/spec/javascripts/boards/board_card_spec.js b/spec/javascripts/boards/board_card_spec.js
index 4e73fa1fe87..80a598e63bd 100644
--- a/spec/javascripts/boards/board_card_spec.js
+++ b/spec/javascripts/boards/board_card_spec.js
@@ -55,7 +55,7 @@ describe('Board card', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('returns false when detailIssue is empty', () => {
diff --git a/spec/javascripts/boards/board_list_spec.js b/spec/javascripts/boards/board_list_spec.js
index 9ffdac9be97..a5fcb10b9dd 100644
--- a/spec/javascripts/boards/board_list_spec.js
+++ b/spec/javascripts/boards/board_list_spec.js
@@ -60,7 +60,7 @@ describe('Board list component', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('renders component', () => {
diff --git a/spec/javascripts/boards/board_new_issue_spec.js b/spec/javascripts/boards/board_new_issue_spec.js
index c62c537841c..e204985f039 100644
--- a/spec/javascripts/boards/board_new_issue_spec.js
+++ b/spec/javascripts/boards/board_new_issue_spec.js
@@ -58,7 +58,7 @@ describe('Issue boards new issue form', () => {
afterEach(() => {
vm.$destroy();
- mock.reset();
+ mock.restore();
});
it('calls submit if submit button is clicked', (done) => {
diff --git a/spec/javascripts/boards/boards_store_spec.js b/spec/javascripts/boards/boards_store_spec.js
index 49fb20f4c84..8411f4dd8a6 100644
--- a/spec/javascripts/boards/boards_store_spec.js
+++ b/spec/javascripts/boards/boards_store_spec.js
@@ -35,7 +35,7 @@ describe('Store', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('starts with a blank state', () => {
diff --git a/spec/javascripts/boards/list_spec.js b/spec/javascripts/boards/list_spec.js
index e5e7b48228b..34964b20b05 100644
--- a/spec/javascripts/boards/list_spec.js
+++ b/spec/javascripts/boards/list_spec.js
@@ -30,7 +30,7 @@ describe('List model', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('gets issues when created', (done) => {
diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js
index 9280db072b3..1c9f48028f2 100644
--- a/spec/javascripts/issue_show/components/app_spec.js
+++ b/spec/javascripts/issue_show/components/app_spec.js
@@ -59,7 +59,7 @@ describe('Issuable output', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
realtimeRequestCount = 0;
vm.poll.stop();
diff --git a/spec/javascripts/jobs/job_details_mediator_spec.js b/spec/javascripts/jobs/job_details_mediator_spec.js
index 3069a0cd60e..ca5c9cf87e4 100644
--- a/spec/javascripts/jobs/job_details_mediator_spec.js
+++ b/spec/javascripts/jobs/job_details_mediator_spec.js
@@ -12,6 +12,10 @@ describe('JobMediator', () => {
mock = new MockAdapter(axios);
});
+ afterEach(() => {
+ mock.restore();
+ });
+
it('should set defaults', () => {
expect(mediator.store).toBeDefined();
expect(mediator.service).toBeDefined();
@@ -24,10 +28,6 @@ describe('JobMediator', () => {
mock.onGet().reply(200, job, {});
});
- afterEach(() => {
- mock.restore();
- });
-
it('should store received data', (done) => {
mediator.fetchJob();
setTimeout(() => {
diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js
index 9885b8a790f..eb8f6bbe50d 100644
--- a/spec/javascripts/monitoring/dashboard_spec.js
+++ b/spec/javascripts/monitoring/dashboard_spec.js
@@ -38,7 +38,7 @@ describe('Dashboard', () => {
});
afterEach(() => {
- mock.reset();
+ mock.restore();
});
it('shows up a loading state', (done) => {
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index baaa9e3ef44..8f406253f39 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -365,12 +365,18 @@ describe Repository do
it { is_expected.to be_truthy }
end
- context 'non-mergeable branches' do
+ context 'non-mergeable branches without conflict sides missing' do
subject { repository.can_be_merged?('bb5206fee213d983da88c47f9cf4cc6caf9c66dc', 'feature') }
it { is_expected.to be_falsey }
end
+ context 'non-mergeable branches with conflict sides missing' do
+ subject { repository.can_be_merged?('conflict-missing-side', 'conflict-start') }
+
+ it { is_expected.to be_falsey }
+ end
+
context 'non merged branch' do
subject { repository.merged_to_root_ref?('fix') }