diff options
-rw-r--r-- | Gemfile.lock | 2 | ||||
-rw-r--r-- | app/assets/javascripts/gl_form.js | 6 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/text_markdown.js | 131 | ||||
-rw-r--r-- | app/models/ci/build.rb | 9 | ||||
-rw-r--r-- | changelogs/unreleased/42880-loss-of-input-text-on-comments-after-preview.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/44232-docs-for-runner-ip-address.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/44388-update-rack-protection-to-2-0-1.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/fix-ci-job-auto-retry.yml | 5 | ||||
-rw-r--r-- | doc/ci/runners/README.md | 33 | ||||
-rw-r--r-- | doc/ci/runners/img/shared_runner_ip_address.png | bin | 0 -> 69821 bytes | |||
-rw-r--r-- | doc/ci/runners/img/specific_runner_ip_address.png | bin | 0 -> 42055 bytes | |||
-rw-r--r-- | doc/install/kubernetes/index.md | 4 | ||||
-rw-r--r-- | doc/user/project/merge_requests/maintainer_access.md | 13 | ||||
-rw-r--r-- | qa/qa/page/merge_request/show.rb | 17 | ||||
-rw-r--r-- | spec/javascripts/lib/utils/text_markdown_spec.js | 10 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/trace_spec.rb | 22 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 29 |
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 Binary files differnew file mode 100644 index 00000000000..3b1542d59d3 --- /dev/null +++ b/doc/ci/runners/img/shared_runner_ip_address.png diff --git a/doc/ci/runners/img/specific_runner_ip_address.png b/doc/ci/runners/img/specific_runner_ip_address.png Binary files differnew file mode 100644 index 00000000000..3b4c3e9f2eb --- /dev/null +++ b/doc/ci/runners/img/specific_runner_ip_address.png 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 |