summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock2
-rw-r--r--app/assets/javascripts/gl_form.js6
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js131
-rw-r--r--app/models/ci/build.rb9
-rw-r--r--changelogs/unreleased/42880-loss-of-input-text-on-comments-after-preview.yml5
-rw-r--r--changelogs/unreleased/44232-docs-for-runner-ip-address.yml5
-rw-r--r--changelogs/unreleased/44388-update-rack-protection-to-2-0-1.yml5
-rw-r--r--changelogs/unreleased/fix-ci-job-auto-retry.yml5
-rw-r--r--doc/ci/runners/README.md33
-rw-r--r--doc/ci/runners/img/shared_runner_ip_address.pngbin0 -> 69821 bytes
-rw-r--r--doc/ci/runners/img/specific_runner_ip_address.pngbin0 -> 42055 bytes
-rw-r--r--doc/install/kubernetes/index.md4
-rw-r--r--doc/user/project/merge_requests/maintainer_access.md13
-rw-r--r--qa/qa/page/merge_request/show.rb17
-rw-r--r--spec/javascripts/lib/utils/text_markdown_spec.js10
-rw-r--r--spec/lib/gitlab/ci/trace_spec.rb22
-rw-r--r--spec/models/ci/build_spec.rb29
17 files changed, 195 insertions, 101 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 1c6c7edb1a0..2c4984d494f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -656,7 +656,7 @@ GEM
httpclient (>= 2.4)
multi_json (>= 1.3.6)
rack (>= 1.1)
- rack-protection (1.5.3)
+ rack-protection (2.0.1)
rack
rack-proxy (0.6.0)
rack
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index 184c98813f1..9f5eba353d7 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -2,7 +2,7 @@ import $ from 'jquery';
import autosize from 'autosize';
import GfmAutoComplete from './gfm_auto_complete';
import dropzoneInput from './dropzone_input';
-import textUtils from './lib/utils/text_markdown';
+import { addMarkdownListeners, removeMarkdownListeners } from './lib/utils/text_markdown';
export default class GLForm {
constructor(form, enableGFM = false) {
@@ -47,7 +47,7 @@ export default class GLForm {
}
// form and textarea event listeners
this.addEventListeners();
- textUtils.init(this.form);
+ addMarkdownListeners(this.form);
// hide discard button
this.form.find('.js-note-discard').hide();
this.form.show();
@@ -86,7 +86,7 @@ export default class GLForm {
clearEventListeners() {
this.textarea.off('focus');
this.textarea.off('blur');
- textUtils.removeListeners(this.form);
+ removeMarkdownListeners(this.form);
}
addEventListeners() {
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index 470e3e5c52e..5a16adea4dc 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -1,28 +1,25 @@
/* eslint-disable import/prefer-default-export, func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */
-
import $ from 'jquery';
+import { insertText } from '~/lib/utils/common_utils';
-const textUtils = {};
-
-textUtils.selectedText = function(text, textarea) {
+function selectedText(text, textarea) {
return text.substring(textarea.selectionStart, textarea.selectionEnd);
-};
+}
-textUtils.lineBefore = function(text, textarea) {
+function lineBefore(text, textarea) {
var split;
split = text.substring(0, textarea.selectionStart).trim().split('\n');
return split[split.length - 1];
-};
+}
-textUtils.lineAfter = function(text, textarea) {
+function lineAfter(text, textarea) {
return text.substring(textarea.selectionEnd).trim().split('\n')[0];
-};
+}
-textUtils.blockTagText = function(text, textArea, blockTag, selected) {
- var lineAfter, lineBefore;
- lineBefore = this.lineBefore(text, textArea);
- lineAfter = this.lineAfter(text, textArea);
- if (lineBefore === blockTag && lineAfter === blockTag) {
+function blockTagText(text, textArea, blockTag, selected) {
+ const before = lineBefore(text, textArea);
+ const after = lineAfter(text, textArea);
+ if (before === blockTag && after === blockTag) {
// To remove the block tag we have to select the line before & after
if (blockTag != null) {
textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1);
@@ -32,10 +29,30 @@ textUtils.blockTagText = function(text, textArea, blockTag, selected) {
} else {
return blockTag + "\n" + selected + "\n" + blockTag;
}
-};
+}
-textUtils.insertText = function(textArea, text, tag, blockTag, selected, wrap) {
- var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine;
+function moveCursor(textArea, tag, wrapped, removedLastNewLine) {
+ var pos;
+ if (!textArea.setSelectionRange) {
+ return;
+ }
+ if (textArea.selectionStart === textArea.selectionEnd) {
+ if (wrapped) {
+ pos = textArea.selectionStart - tag.length;
+ } else {
+ pos = textArea.selectionStart;
+ }
+
+ if (removedLastNewLine) {
+ pos -= 1;
+ }
+
+ return textArea.setSelectionRange(pos, pos);
+ }
+}
+
+export function insertMarkdownText(textArea, text, tag, blockTag, selected, wrap) {
+ var textToInsert, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine;
removedLastNewLine = false;
removedFirstNewLine = false;
currentLineEmpty = false;
@@ -67,9 +84,9 @@ textUtils.insertText = function(textArea, text, tag, blockTag, selected, wrap) {
if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) {
if (blockTag != null && blockTag !== '') {
- insertText = this.blockTagText(text, textArea, blockTag, selected);
+ textToInsert = blockTagText(text, textArea, blockTag, selected);
} else {
- insertText = selectedSplit.map(function(val) {
+ textToInsert = selectedSplit.map(function(val) {
if (val.indexOf(tag) === 0) {
return "" + (val.replace(tag, ''));
} else {
@@ -78,78 +95,42 @@ textUtils.insertText = function(textArea, text, tag, blockTag, selected, wrap) {
}).join('\n');
}
} else {
- insertText = "" + startChar + tag + selected + (wrap ? tag : ' ');
+ textToInsert = "" + startChar + tag + selected + (wrap ? tag : ' ');
}
if (removedFirstNewLine) {
- insertText = '\n' + insertText;
+ textToInsert = '\n' + textToInsert;
}
if (removedLastNewLine) {
- insertText += '\n';
+ textToInsert += '\n';
}
- if (document.queryCommandSupported('insertText')) {
- inserted = document.execCommand('insertText', false, insertText);
- }
- if (!inserted) {
- try {
- document.execCommand("ms-beginUndoUnit");
- } catch (error) {}
- textArea.value = this.replaceRange(text, textArea.selectionStart, textArea.selectionEnd, insertText);
- try {
- document.execCommand("ms-endUndoUnit");
- } catch (error) {}
- }
- return this.moveCursor(textArea, tag, wrap, removedLastNewLine);
-};
+ insertText(textArea, textToInsert);
+ return moveCursor(textArea, tag, wrap, removedLastNewLine);
+}
-textUtils.moveCursor = function(textArea, tag, wrapped, removedLastNewLine) {
- var pos;
- if (!textArea.setSelectionRange) {
- return;
- }
- if (textArea.selectionStart === textArea.selectionEnd) {
- if (wrapped) {
- pos = textArea.selectionStart - tag.length;
- } else {
- pos = textArea.selectionStart;
- }
-
- if (removedLastNewLine) {
- pos -= 1;
- }
-
- return textArea.setSelectionRange(pos, pos);
- }
-};
-
-textUtils.updateText = function(textArea, tag, blockTag, wrap) {
+function updateText(textArea, tag, blockTag, wrap) {
var $textArea, selected, text;
$textArea = $(textArea);
textArea = $textArea.get(0);
text = $textArea.val();
- selected = this.selectedText(text, textArea);
+ selected = selectedText(text, textArea);
$textArea.focus();
- return this.insertText(textArea, text, tag, blockTag, selected, wrap);
-};
+ return insertMarkdownText(textArea, text, tag, blockTag, selected, wrap);
+}
-textUtils.init = function(form) {
- var self;
- self = this;
+function replaceRange(s, start, end, substitute) {
+ return s.substring(0, start) + substitute + s.substring(end);
+}
+
+export function addMarkdownListeners(form) {
return $('.js-md', form).off('click').on('click', function() {
- var $this;
- $this = $(this);
- return self.updateText($this.closest('.md-area').find('textarea'), $this.data('mdTag'), $this.data('mdBlock'), !$this.data('mdPrepend'));
+ const $this = $(this);
+ return updateText($this.closest('.md-area').find('textarea'), $this.data('mdTag'), $this.data('mdBlock'), !$this.data('mdPrepend'));
});
-};
+}
-textUtils.removeListeners = function(form) {
+export function removeMarkdownListeners(form) {
return $('.js-md', form).off('click');
-};
-
-textUtils.replaceRange = function(s, start, end, substitute) {
- return s.substring(0, start) + substitute + s.substring(end);
-};
-
-export default textUtils;
+}
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index c1da2081465..1e066b69c6e 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -140,7 +140,11 @@ module Ci
next if build.retries_max.zero?
if build.retries_count < build.retries_max
- Ci::Build.retry(build, build.user)
+ begin
+ Ci::Build.retry(build, build.user)
+ rescue Gitlab::Access::AccessDeniedError => ex
+ Rails.logger.error "Unable to auto-retry job #{build.id}: #{ex}"
+ end
end
end
@@ -328,8 +332,7 @@ module Ci
end
def erase_old_trace!
- write_attribute(:trace, nil)
- save
+ update_column(:trace, nil)
end
def needs_touch?
diff --git a/changelogs/unreleased/42880-loss-of-input-text-on-comments-after-preview.yml b/changelogs/unreleased/42880-loss-of-input-text-on-comments-after-preview.yml
new file mode 100644
index 00000000000..0e892a51bc5
--- /dev/null
+++ b/changelogs/unreleased/42880-loss-of-input-text-on-comments-after-preview.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Firefox stealing formatting characters on issue notes
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/44232-docs-for-runner-ip-address.yml b/changelogs/unreleased/44232-docs-for-runner-ip-address.yml
new file mode 100644
index 00000000000..82485d31b24
--- /dev/null
+++ b/changelogs/unreleased/44232-docs-for-runner-ip-address.yml
@@ -0,0 +1,5 @@
+---
+title: Add documentation for runner IP address (#44232)
+merge_request: 17837
+author:
+type: other
diff --git a/changelogs/unreleased/44388-update-rack-protection-to-2-0-1.yml b/changelogs/unreleased/44388-update-rack-protection-to-2-0-1.yml
new file mode 100644
index 00000000000..c21d02d4d87
--- /dev/null
+++ b/changelogs/unreleased/44388-update-rack-protection-to-2-0-1.yml
@@ -0,0 +1,5 @@
+---
+title: Update rack-protection to 2.0.1
+merge_request: 17835
+author: Takuya Noguchi
+type: security
diff --git a/changelogs/unreleased/fix-ci-job-auto-retry.yml b/changelogs/unreleased/fix-ci-job-auto-retry.yml
new file mode 100644
index 00000000000..442126461f0
--- /dev/null
+++ b/changelogs/unreleased/fix-ci-job-auto-retry.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent auto-retry AccessDenied error from stopping transition to failed
+merge_request: 17862
+author:
+type: fixed
diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md
index f879ed62010..9f2538b9c9f 100644
--- a/doc/ci/runners/README.md
+++ b/doc/ci/runners/README.md
@@ -280,3 +280,36 @@ We're always looking for contributions that can mitigate these
[register]: http://docs.gitlab.com/runner/register/
[protected branches]: ../../user/project/protected_branches.md
[protected tags]: ../../user/project/protected_tags.md
+
+## Determining the IP address of a Runner
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/17286) in GitLab 10.6.
+
+It may be useful to know the IP address of a Runner so you can troubleshoot
+issues with that Runner. GitLab stores and displays the IP address by viewing
+the source of the HTTP requests it makes to GitLab when polling for jobs. The
+IP address is always kept up to date so if the Runner IP changes it will be
+automatically updated in GitLab.
+
+The IP address for shared Runners and specific Runners can be found in
+different places.
+
+### Shared Runners
+
+To view the IP address of a shared Runner you must have admin access to
+the GitLab instance. To determine this:
+
+1. Visit **Admin area ➔ Overview ➔ Runners**
+1. Look for the Runner in the table and you should see a column for "IP Address"
+
+![shared Runner IP address](img/shared_runner_ip_address.png)
+
+### Specific Runners
+
+You can find the IP address of a Runner for a specific project by:
+
+1. Visit your project's **Settings ➔ CI/CD**
+1. Find the Runner and click on it's ID which links you to the details page
+1. On the details page you should see a row for "IP Address"
+
+![specific Runner IP address](img/specific_runner_ip_address.png)
diff --git a/doc/ci/runners/img/shared_runner_ip_address.png b/doc/ci/runners/img/shared_runner_ip_address.png
new file mode 100644
index 00000000000..3b1542d59d3
--- /dev/null
+++ b/doc/ci/runners/img/shared_runner_ip_address.png
Binary files differ
diff --git a/doc/ci/runners/img/specific_runner_ip_address.png b/doc/ci/runners/img/specific_runner_ip_address.png
new file mode 100644
index 00000000000..3b4c3e9f2eb
--- /dev/null
+++ b/doc/ci/runners/img/specific_runner_ip_address.png
Binary files differ
diff --git a/doc/install/kubernetes/index.md b/doc/install/kubernetes/index.md
index 3a1707a54a1..aa9b8777359 100644
--- a/doc/install/kubernetes/index.md
+++ b/doc/install/kubernetes/index.md
@@ -10,7 +10,7 @@ should be deployed, upgraded, and configured.
## Chart Overview
* **[GitLab-Omnibus](gitlab_omnibus.md)**: The best way to run GitLab on Kubernetes today, suited for small deployments. The chart is in beta and will be deprecated by the [cloud native GitLab chart](#cloud-native-gitlab-chart).
-* **[Cloud Native GitLab Chart](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md)**: The next generation GitLab chart, currently in development. Will support large deployments with horizontal scaling of individual GitLab components.
+* **[Cloud Native GitLab Chart](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md)**: The next generation GitLab chart, currently in alpha. Will support large deployments with horizontal scaling of individual GitLab components.
* Other Charts
* [GitLab Runner Chart](gitlab_runner_chart.md): For deploying just the GitLab Runner.
* [Advanced GitLab Installation](gitlab_chart.md): Deprecated, being replaced by the [cloud native GitLab chart](#cloud-native-gitlab-chart). Provides additional deployment options, but provides less functionality out-of-the-box.
@@ -35,7 +35,7 @@ By offering individual containers and charts, we will be able to provide a numbe
* Potential for rolling updates and canaries within a service,
* and plenty more.
-This is a large project and will be worked on over the span of multiple releases. For the most up-to-date status and release information, please see our [tracking issue](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2420). We are planning to launch this chart in beta by the end of 2017.
+Presently this chart is available in alpha for testing, and not recommended for production use.
Learn more about the [cloud native GitLab chart here ](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md) and [here [Video]](https://youtu.be/Z6jWR8Z8dv8).
diff --git a/doc/user/project/merge_requests/maintainer_access.md b/doc/user/project/merge_requests/maintainer_access.md
index 7feccc28f6b..c9763a3fe02 100644
--- a/doc/user/project/merge_requests/maintainer_access.md
+++ b/doc/user/project/merge_requests/maintainer_access.md
@@ -1,12 +1,17 @@
# Allow maintainer pushes for merge requests across forks
+> [Introduced][ce-17395] in GitLab 10.6.
+
This feature is available for merge requests across forked projects that are
-publicly accessible. It makes it easier for maintainers of projects to collaborate
-on merge requests across forks.
+publicly accessible. It makes it easier for maintainers of projects to
+collaborate on merge requests across forks.
-When enabling this feature for a merge request, you give can give members with push access to the target project rights to edit files on the source branch of the merge request.
+When enabled for a merge request, members with merge access to the target
+branch of the project will be granted write permissions to the source branch
+of the merge request.
-The feature can only be enabled by users who already have push access to the source project. And only lasts while the merge request is open.
+The feature can only be enabled by users who already have push access to the
+source project, and only lasts while the merge request is open.
Enable this functionality while creating a merge request:
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 35875487da8..2f2506f08fb 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -4,6 +4,7 @@ module QA
class Show < Page::Base
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js' do
element :merge_button
+ element :fast_forward_message, 'Fast-forward merge without a merge commit'
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do
@@ -12,19 +13,19 @@ module QA
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue' do
element :mr_rebase_button
- element :fast_forward_nessage, "Fast-forward merge is not possible"
+ element :no_fast_forward_message, 'Fast-forward merge is not possible'
end
def rebase!
- wait(reload: false) do
- click_element :mr_rebase_button
+ click_element :mr_rebase_button
- has_text?("The source branch HEAD has recently changed.")
+ wait(reload: false) do
+ has_text?('Fast-forward merge without a merge commit')
end
end
def fast_forward_possible?
- !has_text?("Fast-forward merge is not possible")
+ !has_text?('Fast-forward merge is not possible')
end
def has_merge_button?
@@ -34,10 +35,10 @@ module QA
end
def merge!
- wait(reload: false) do
- click_element :merge_button
+ click_element :merge_button
- has_text?("The changes were merged into")
+ wait(reload: false) do
+ has_text?('The changes were merged into')
end
end
end
diff --git a/spec/javascripts/lib/utils/text_markdown_spec.js b/spec/javascripts/lib/utils/text_markdown_spec.js
index a95a7e2a5be..ca0e7c395a0 100644
--- a/spec/javascripts/lib/utils/text_markdown_spec.js
+++ b/spec/javascripts/lib/utils/text_markdown_spec.js
@@ -1,4 +1,4 @@
-import textUtils from '~/lib/utils/text_markdown';
+import { insertMarkdownText } from '~/lib/utils/text_markdown';
describe('init markdown', () => {
let textArea;
@@ -21,7 +21,7 @@ describe('init markdown', () => {
textArea.selectionStart = 0;
textArea.selectionEnd = 0;
- textUtils.insertText(textArea, textArea.value, '*', null, '', false);
+ insertMarkdownText(textArea, textArea.value, '*', null, '', false);
expect(textArea.value).toEqual(`${initialValue}* `);
});
@@ -32,7 +32,7 @@ describe('init markdown', () => {
textArea.value = initialValue;
textArea.setSelectionRange(initialValue.length, initialValue.length);
- textUtils.insertText(textArea, textArea.value, '*', null, '', false);
+ insertMarkdownText(textArea, textArea.value, '*', null, '', false);
expect(textArea.value).toEqual(`${initialValue}\n* `);
});
@@ -43,7 +43,7 @@ describe('init markdown', () => {
textArea.value = initialValue;
textArea.setSelectionRange(initialValue.length, initialValue.length);
- textUtils.insertText(textArea, textArea.value, '*', null, '', false);
+ insertMarkdownText(textArea, textArea.value, '*', null, '', false);
expect(textArea.value).toEqual(`${initialValue}* `);
});
@@ -54,7 +54,7 @@ describe('init markdown', () => {
textArea.value = initialValue;
textArea.setSelectionRange(initialValue.length, initialValue.length);
- textUtils.insertText(textArea, textArea.value, '*', null, '', false);
+ insertMarkdownText(textArea, textArea.value, '*', null, '', false);
expect(textArea.value).toEqual(`${initialValue}* `);
});
diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb
index 448c6fb57dd..3a9371ed2e8 100644
--- a/spec/lib/gitlab/ci/trace_spec.rb
+++ b/spec/lib/gitlab/ci/trace_spec.rb
@@ -510,6 +510,28 @@ describe Gitlab::Ci::Trace do
it_behaves_like 'source trace in database stays intact', error: ActiveRecord::RecordInvalid
end
+
+ context 'when there is a validation error on Ci::Build' do
+ before do
+ allow_any_instance_of(Ci::Build).to receive(:save).and_return(false)
+ allow_any_instance_of(Ci::Build).to receive_message_chain(:errors, :full_messages)
+ .and_return(%w[Error Error])
+ end
+
+ context "when erase old trace with 'save'" do
+ before do
+ build.send(:write_attribute, :trace, nil)
+ build.save
+ end
+
+ it 'old trace is not deleted' do
+ build.reload
+ expect(build.trace.raw).to eq(trace_content)
+ end
+ end
+
+ it_behaves_like 'archive trace in database'
+ end
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 9da3de7a828..30a352fd090 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -2101,6 +2101,35 @@ describe Ci::Build do
subject.drop!
end
+
+ context 'when retry service raises Gitlab::Access::AccessDeniedError exception' do
+ let(:retry_service) { Ci::RetryBuildService.new(subject.project, subject.user) }
+
+ before do
+ allow_any_instance_of(Ci::RetryBuildService)
+ .to receive(:execute)
+ .with(subject)
+ .and_raise(Gitlab::Access::AccessDeniedError)
+ allow(Rails.logger).to receive(:error)
+ end
+
+ it 'handles raised exception' do
+ expect { subject.drop! }.not_to raise_exception(Gitlab::Access::AccessDeniedError)
+ end
+
+ it 'logs the error' do
+ subject.drop!
+
+ expect(Rails.logger)
+ .to have_received(:error)
+ .with(a_string_matching("Unable to auto-retry job #{subject.id}"))
+ end
+
+ it 'fails the job' do
+ subject.drop!
+ expect(subject.failed?).to be_truthy
+ end
+ end
end
context 'when build is not configured to be retried' do