diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-29 18:06:15 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-29 18:06:15 +0000 |
commit | cb3e6b9c1b020378b5f94b4c38319a2dc961de01 (patch) | |
tree | 7933db817fb945478151685a393420b44fa52f7c | |
parent | dee9315801b5dc49b795d13081086c22622a11ec (diff) | |
download | gitlab-ce-cb3e6b9c1b020378b5f94b4c38319a2dc961de01.tar.gz |
Add latest changes from gitlab-org/gitlab@master
23 files changed, 710 insertions, 105 deletions
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 2514274224d..9236f0d5349 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -54,11 +54,12 @@ export default { showLoadingIcon() { return this.isLoadingCollapsedDiff || (!this.file.renderIt && !this.isCollapsed); }, - hasDiffLines() { + hasDiff() { return ( - this.file.highlighted_diff_lines && - this.file.parallel_diff_lines && - this.file.parallel_diff_lines.length > 0 + (this.file.highlighted_diff_lines && + this.file.parallel_diff_lines && + this.file.parallel_diff_lines.length > 0) || + !this.file.blob.readable_text ); }, isFileTooLarge() { @@ -82,7 +83,7 @@ export default { }, watch: { isCollapsed: function fileCollapsedWatch(newVal, oldVal) { - if (!newVal && oldVal && !this.hasDiffLines) { + if (!newVal && oldVal && !this.hasDiff) { this.handleLoadCollapsedDiff(); } @@ -103,7 +104,7 @@ export default { 'setFileCollapsed', ]), handleToggle() { - if (!this.hasDiffLines) { + if (!this.hasDiff) { this.handleLoadCollapsedDiff(); } else { this.isCollapsed = !this.isCollapsed; diff --git a/changelogs/unreleased/bug-fix-27164-Image-cannot-be-collapsed-on-merge-request-changes-tab.yml b/changelogs/unreleased/bug-fix-27164-Image-cannot-be-collapsed-on-merge-request-changes-tab.yml new file mode 100644 index 00000000000..22956631131 --- /dev/null +++ b/changelogs/unreleased/bug-fix-27164-Image-cannot-be-collapsed-on-merge-request-changes-tab.yml @@ -0,0 +1,5 @@ +--- +title: 'fixed #27164 Image cannot be collapsed on merge request changes tab' +merge_request: 18917 +author: Jannik Lehmann +type: fixed diff --git a/changelogs/unreleased/feature-reduce-cluster-ip-size.yml b/changelogs/unreleased/feature-reduce-cluster-ip-size.yml new file mode 100644 index 00000000000..62bdd3b8592 --- /dev/null +++ b/changelogs/unreleased/feature-reduce-cluster-ip-size.yml @@ -0,0 +1,5 @@ +--- +title: Reduce the allocated IP for Cluster and Services +merge_request: 18341 +author: +type: changed diff --git a/changelogs/unreleased/job-log-support-mac-line-break.yml b/changelogs/unreleased/job-log-support-mac-line-break.yml new file mode 100644 index 00000000000..12be5be687d --- /dev/null +++ b/changelogs/unreleased/job-log-support-mac-line-break.yml @@ -0,0 +1,5 @@ +--- +title: Let ANSI \r code replace the current job log line +merge_request: 18933 +author: +type: fixed diff --git a/changelogs/unreleased/mc-feature-flatten-ci-scripts.yml b/changelogs/unreleased/mc-feature-flatten-ci-scripts.yml new file mode 100644 index 00000000000..3dfcc5e871c --- /dev/null +++ b/changelogs/unreleased/mc-feature-flatten-ci-scripts.yml @@ -0,0 +1,5 @@ +--- +title: Add support for YAML anchors in CI scripts. +merge_request: 18849 +author: +type: changed diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 28c6bc6c418..8449dfec049 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -181,6 +181,25 @@ that the YAML parser knows to interpret the whole thing as a string rather than a "key: value" pair. Be careful when using special characters: `:`, `{`, `}`, `[`, `]`, `,`, `&`, `*`, `#`, `?`, `|`, `-`, `<`, `>`, `=`, `!`, `%`, `@`, `` ` ``. +#### YAML anchors for `script` + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/23005) in GitLab 12.5. + +You can use [YAML anchors](#anchors) with scripts, which makes it possible to +include a predefined list of commands in multiple jobs. + +Example: + +```yaml +.something: &something +- echo 'something' + +job_name: + script: + - *something + - echo 'this is the script' +``` + ### `image` Used to specify [a Docker image](../docker/using_docker_images.md#what-is-an-image) to use for the job. @@ -284,6 +303,33 @@ job: - execute this after my script ``` +#### YAML anchors for `before_script` and `after_script` + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/23005) in GitLab 12.5. + +You can use [YAML anchors](#anchors) with `before_script` and `after_script`, +which makes it possible to include a predefined list of commands in multiple +jobs. + +Example: + +```yaml +.something_before: &something_before +- echo 'something before' + +.something_after: &something_after +- echo 'something after' + + +job_name: + before_script: + - *something_before + script: + - echo 'this is the script' + after_script: + - *something_after +``` + ### `stages` `stages` is used to define stages that can be used by jobs and is defined diff --git a/doc/user/project/clusters/add_remove_clusters.md b/doc/user/project/clusters/add_remove_clusters.md index b1d93577823..84f8da526d7 100644 --- a/doc/user/project/clusters/add_remove_clusters.md +++ b/doc/user/project/clusters/add_remove_clusters.md @@ -175,6 +175,9 @@ NOTE: **Note:** Starting from [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/issues/55902), all GKE clusters created by GitLab are RBAC-enabled. Take a look at the [RBAC section](#rbac-cluster-resources) for more information. +NOTE: **Note:** +Starting from [GitLab 12.5](https://gitlab.com/gitlab-org/gitlab/merge_requests/18341), the cluster's pod address IP range will be set to /16 instead of the regular /14. (/16 is a CIDR notation) + ### Cloud Run on GKE > [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16566) in GitLab 12.4. diff --git a/lib/gitlab/ci/ansi2json/converter.rb b/lib/gitlab/ci/ansi2json/converter.rb index 8d25b66af9c..908e560999e 100644 --- a/lib/gitlab/ci/ansi2json/converter.rb +++ b/lib/gitlab/ci/ansi2json/converter.rb @@ -22,11 +22,11 @@ module Gitlab start_offset = @state.offset - @state.set_current_line!(style: Style.new(@state.inherited_style)) + @state.new_line!( + style: Style.new(@state.inherited_style)) stream.each_line do |line| - s = StringScanner.new(line) - convert_line(s) + consume_line(line) end # This must be assigned before flushing the current line @@ -52,26 +52,43 @@ module Gitlab private - def convert_line(scanner) - until scanner.eos? - - if scanner.scan(Gitlab::Regex.build_trace_section_regex) - handle_section(scanner) - elsif scanner.scan(/\e([@-_])(.*?)([@-~])/) - handle_sequence(scanner) - elsif scanner.scan(/\e(([@-_])(.*?)?)?$/) - break - elsif scanner.scan(/</) - @state.current_line << '<' - elsif scanner.scan(/\r?\n/) - # we advance the offset of the next current line - # so it does not start from \n - flush_current_line(advance_offset: scanner.matched_size) - else - @state.current_line << scanner.scan(/./m) - end - - @state.offset += scanner.matched_size + def consume_line(line) + scanner = StringScanner.new(line) + + consume_token(scanner) until scanner.eos? + end + + def consume_token(scanner) + if scan_token(scanner, Gitlab::Regex.build_trace_section_regex, consume: false) + handle_section(scanner) + elsif scan_token(scanner, /\e([@-_])(.*?)([@-~])/) + handle_sequence(scanner) + elsif scan_token(scanner, /\e(([@-_])(.*?)?)?$/) + # stop scanning + scanner.terminate + elsif scan_token(scanner, /</) + @state.current_line << '<' + elsif scan_token(scanner, /\r?\n/) + flush_current_line + elsif scan_token(scanner, /\r/) + # drop last line + @state.current_line.clear! + elsif scan_token(scanner, /.[^\e<\r\ns]*/m) + # this is a join from all previous tokens and first letters + # it always matches at least one character `.` + # it matches everything that is not start of: + # `\e`, `<`, `\r`, `\n`, `s` (for section_start) + @state.current_line << scanner[0] + else + raise 'invalid parser state' + end + end + + def scan_token(scanner, match, consume: true) + scanner.scan(match).tap do |result| + # we need to move offset as soon + # as we match the token + @state.offset += scanner.matched_size if consume && result end end @@ -96,32 +113,50 @@ module Gitlab section_name = sanitize_section_name(section) if action == "start" - handle_section_start(section_name, timestamp) + handle_section_start(scanner, section_name, timestamp) elsif action == "end" - handle_section_end(section_name, timestamp) + handle_section_end(scanner, section_name, timestamp) + else + raise 'unsupported action' end end - def handle_section_start(section, timestamp) - flush_current_line unless @state.current_line.empty? + def handle_section_start(scanner, section, timestamp) + # We make a new line for new section + flush_current_line + @state.open_section(section, timestamp) + + # we need to consume match after handling + # the open of section, as we want the section + # marker to be refresh on incremental update + @state.offset += scanner.matched_size end - def handle_section_end(section, timestamp) + def handle_section_end(scanner, section, timestamp) return unless @state.section_open?(section) - flush_current_line unless @state.current_line.empty? + # We flush the content to make the end + # of section to be a new line + flush_current_line + @state.close_section(section, timestamp) - # ensure that section end is detached from the last - # line in the section + # we need to consume match before handling + # as we want the section close marker + # not to be refreshed on incremental update + @state.offset += scanner.matched_size + + # this flushes an empty line with `section_duration` flush_current_line end - def flush_current_line(advance_offset: 0) - @lines << @state.current_line.to_h + def flush_current_line + unless @state.current_line.empty? + @lines << @state.current_line.to_h + end - @state.set_current_line!(advance_offset: advance_offset) + @state.new_line! end def sanitize_section_name(section) diff --git a/lib/gitlab/ci/ansi2json/line.rb b/lib/gitlab/ci/ansi2json/line.rb index 173fb1df88e..21aa1f84353 100644 --- a/lib/gitlab/ci/ansi2json/line.rb +++ b/lib/gitlab/ci/ansi2json/line.rb @@ -47,12 +47,17 @@ module Gitlab @current_segment.text << data end + def clear! + @segments.clear + @current_segment = Segment.new(style: style) + end + def style @current_segment.style end def empty? - @segments.empty? && @current_segment.empty? + @segments.empty? && @current_segment.empty? && @section_duration.nil? end def update_style(ansi_commands) diff --git a/lib/gitlab/ci/ansi2json/state.rb b/lib/gitlab/ci/ansi2json/state.rb index db7a9035b8b..7e1a8102a35 100644 --- a/lib/gitlab/ci/ansi2json/state.rb +++ b/lib/gitlab/ci/ansi2json/state.rb @@ -46,9 +46,9 @@ module Gitlab @open_sections.key?(section) end - def set_current_line!(style: nil, advance_offset: 0) + def new_line!(style: nil) new_line = Line.new( - offset: @offset + advance_offset, + offset: @offset, style: style || @current_line.style, sections: @open_sections.keys ) diff --git a/lib/gitlab/ci/config/entry/commands.rb b/lib/gitlab/ci/config/entry/commands.rb index 02e368c1813..7a86fca3056 100644 --- a/lib/gitlab/ci/config/entry/commands.rb +++ b/lib/gitlab/ci/config/entry/commands.rb @@ -11,11 +11,11 @@ module Gitlab include ::Gitlab::Config::Entry::Validatable validations do - validates :config, array_of_strings_or_string: true + validates :config, string_or_nested_array_of_strings: true end def value - Array(@config) + Array(@config).flatten(1) end end end diff --git a/lib/gitlab/ci/config/entry/script.rb b/lib/gitlab/ci/config/entry/script.rb index 9d25a82b521..285e18218b3 100644 --- a/lib/gitlab/ci/config/entry/script.rb +++ b/lib/gitlab/ci/config/entry/script.rb @@ -11,7 +11,11 @@ module Gitlab include ::Gitlab::Config::Entry::Validatable validations do - validates :config, array_of_strings: true + validates :config, nested_array_of_strings: true + end + + def value + config.flatten(1) end end end diff --git a/lib/gitlab/config/entry/validators.rb b/lib/gitlab/config/entry/validators.rb index 8a04cca60d7..d1c23c41d35 100644 --- a/lib/gitlab/config/entry/validators.rb +++ b/lib/gitlab/config/entry/validators.rb @@ -228,6 +228,34 @@ module Gitlab end end + class NestedArrayOfStringsValidator < ArrayOfStringsOrStringValidator + def validate_each(record, attribute, value) + unless validate_nested_array_of_strings(value) + record.errors.add(attribute, 'should be an array containing strings and arrays of strings') + end + end + + private + + def validate_nested_array_of_strings(values) + values.is_a?(Array) && values.all? { |element| validate_array_of_strings_or_string(element) } + end + end + + class StringOrNestedArrayOfStringsValidator < NestedArrayOfStringsValidator + def validate_each(record, attribute, value) + unless validate_string_or_nested_array_of_strings(value) + record.errors.add(attribute, 'should be a string or an array containing strings and arrays of strings') + end + end + + private + + def validate_string_or_nested_array_of_strings(values) + validate_string(values) || validate_nested_array_of_strings(values) + end + end + class TypeValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) type = options[:with] diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb index 9085835dee6..99029b54a69 100644 --- a/lib/google_api/cloud_platform/client.rb +++ b/lib/google_api/cloud_platform/client.rb @@ -12,6 +12,7 @@ module GoogleApi SCOPE = 'https://www.googleapis.com/auth/cloud-platform' LEAST_TOKEN_LIFE_TIME = 10.minutes CLUSTER_MASTER_AUTH_USERNAME = 'admin' + CLUSTER_IPV4_CIDR_BLOCK = '/16' class << self def session_key_for_token @@ -97,7 +98,8 @@ module GoogleApi enabled: legacy_abac }, ip_allocation_policy: { - use_ip_aliases: true + use_ip_aliases: true, + cluster_ipv4_cidr_block: CLUSTER_IPV4_CIDR_BLOCK }, addons_config: enable_addons.each_with_object({}) do |addon, hash| hash[addon] = { disabled: false } diff --git a/spec/javascripts/diffs/components/diff_file_spec.js b/spec/javascripts/diffs/components/diff_file_spec.js index 3ca2d1dc934..6ffdb6ba85d 100644 --- a/spec/javascripts/diffs/components/diff_file_spec.js +++ b/spec/javascripts/diffs/components/diff_file_spec.js @@ -3,14 +3,15 @@ import DiffFileComponent from '~/diffs/components/diff_file.vue'; import { diffViewerModes, diffViewerErrors } from '~/ide/constants'; import { createStore } from 'ee_else_ce/mr_notes/stores'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import diffFileMockData from '../mock_data/diff_file'; +import diffFileMockDataReadable from '../mock_data/diff_file'; +import diffFileMockDataUnreadable from '../mock_data/diff_file_unreadable'; describe('DiffFile', () => { let vm; beforeEach(() => { vm = createComponentWithStore(Vue.extend(DiffFileComponent), createStore(), { - file: JSON.parse(JSON.stringify(diffFileMockData)), + file: JSON.parse(JSON.stringify(diffFileMockDataReadable)), canCurrentUserFork: false, }).$mount(); }); @@ -81,6 +82,24 @@ describe('DiffFile', () => { }); }); + it('should be collapsable for unreadable files', done => { + vm.$destroy(); + vm = createComponentWithStore(Vue.extend(DiffFileComponent), createStore(), { + file: JSON.parse(JSON.stringify(diffFileMockDataUnreadable)), + canCurrentUserFork: false, + }).$mount(); + + vm.renderIt = false; + vm.isCollapsed = true; + + vm.$nextTick(() => { + expect(vm.$el.innerText).toContain('This diff is collapsed'); + expect(vm.$el.querySelectorAll('.js-click-to-expand').length).toEqual(1); + + done(); + }); + }); + it('should be collapsed for renamed files', done => { vm.renderIt = true; vm.isCollapsed = false; @@ -184,5 +203,31 @@ describe('DiffFile', () => { .then(done) .catch(done.fail); }); + + it('does not call handleLoadCollapsedDiff if collapsed changed & file is unreadable', done => { + vm.$destroy(); + vm = createComponentWithStore(Vue.extend(DiffFileComponent), createStore(), { + file: JSON.parse(JSON.stringify(diffFileMockDataUnreadable)), + canCurrentUserFork: false, + }).$mount(); + + spyOn(vm, 'handleLoadCollapsedDiff'); + + vm.file.highlighted_diff_lines = undefined; + vm.file.parallel_diff_lines = []; + vm.isCollapsed = true; + + vm.$nextTick() + .then(() => { + vm.isCollapsed = false; + + return vm.$nextTick(); + }) + .then(() => { + expect(vm.handleLoadCollapsedDiff).not.toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); }); }); diff --git a/spec/javascripts/diffs/mock_data/diff_file_unreadable.js b/spec/javascripts/diffs/mock_data/diff_file_unreadable.js new file mode 100644 index 00000000000..8c2df45988e --- /dev/null +++ b/spec/javascripts/diffs/mock_data/diff_file_unreadable.js @@ -0,0 +1,244 @@ +export default { + submodule: false, + submodule_link: null, + blob: { + id: '9e10516ca50788acf18c518a231914a21e5f16f7', + path: 'CHANGELOG', + name: 'CHANGELOG', + mode: '100644', + readable_text: false, + icon: 'file-text-o', + }, + blob_path: 'CHANGELOG', + blob_name: 'CHANGELOG', + blob_icon: '<i aria-hidden="true" data-hidden="true" class="fa fa-file-text-o fa-fw"></i>', + file_hash: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a', + file_path: 'CHANGELOG', + new_file: false, + deleted_file: false, + renamed_file: false, + old_path: 'CHANGELOG', + new_path: 'CHANGELOG', + mode_changed: false, + a_mode: '100644', + b_mode: '100644', + text: true, + viewer: { + name: 'text', + error: null, + collapsed: false, + }, + added_lines: 0, + removed_lines: 0, + diff_refs: { + base_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a', + start_sha: 'd9eaefe5a676b820c57ff18cf5b68316025f7962', + head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13', + }, + content_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13', + stored_externally: null, + external_storage: null, + old_path_html: 'CHANGELOG', + new_path_html: 'CHANGELOG', + edit_path: '/gitlab-org/gitlab-test/edit/spooky-stuff/CHANGELOG', + view_path: '/gitlab-org/gitlab-test/blob/spooky-stuff/CHANGELOG', + replaced_view_path: null, + collapsed: false, + renderIt: false, + too_large: false, + context_lines_path: + '/gitlab-org/gitlab-test/blob/c48ee0d1bf3b30453f5b32250ce03134beaa6d13/CHANGELOG/diff', + highlighted_diff_lines: [ + { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1', + type: 'new', + old_line: null, + new_line: 1, + discussions: [], + text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + rich_text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + meta_data: null, + }, + { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2', + type: 'new', + old_line: null, + new_line: 2, + discussions: [], + text: '+<span id="LC2" class="line" lang="plaintext"></span>\n', + rich_text: '+<span id="LC2" class="line" lang="plaintext"></span>\n', + meta_data: null, + }, + { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', + type: null, + old_line: 1, + new_line: 3, + discussions: [], + text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + rich_text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + meta_data: null, + }, + { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', + type: null, + old_line: 2, + new_line: 4, + discussions: [], + text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', + rich_text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', + meta_data: null, + }, + { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', + type: null, + old_line: 3, + new_line: 5, + discussions: [], + text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + rich_text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + meta_data: null, + }, + { + line_code: null, + type: 'match', + old_line: null, + new_line: null, + discussions: [], + text: '', + rich_text: '', + meta_data: { + old_pos: 3, + new_pos: 5, + }, + }, + ], + parallel_diff_lines: [ + { + left: { + type: 'empty-cell', + }, + right: { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1', + type: 'new', + old_line: null, + new_line: 1, + discussions: [], + text: '+<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + rich_text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n', + meta_data: null, + }, + }, + { + left: { + type: 'empty-cell', + }, + right: { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2', + type: 'new', + old_line: null, + new_line: 2, + discussions: [], + text: '+<span id="LC2" class="line" lang="plaintext"></span>\n', + rich_text: '<span id="LC2" class="line" lang="plaintext"></span>\n', + meta_data: null, + }, + }, + { + left: { + line_Code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', + type: null, + old_line: 1, + new_line: 3, + discussions: [], + text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + meta_data: null, + }, + right: { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3', + type: null, + old_line: 1, + new_line: 3, + discussions: [], + text: ' <span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n', + meta_data: null, + }, + }, + { + left: { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', + type: null, + old_line: 2, + new_line: 4, + discussions: [], + text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', + rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n', + meta_data: null, + }, + right: { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4', + type: null, + old_line: 2, + new_line: 4, + discussions: [], + text: ' <span id="LC4" class="line" lang="plaintext"></span>\n', + rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n', + meta_data: null, + }, + }, + { + left: { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', + type: null, + old_line: 3, + new_line: 5, + discussions: [], + text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + meta_data: null, + }, + right: { + line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5', + type: null, + old_line: 3, + new_line: 5, + discussions: [], + text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n', + meta_data: null, + }, + }, + { + left: { + line_code: null, + type: 'match', + old_line: null, + new_line: null, + discussions: [], + text: '', + rich_text: '', + meta_data: { + old_pos: 3, + new_pos: 5, + }, + }, + right: { + line_code: null, + type: 'match', + old_line: null, + new_line: null, + discussions: [], + text: '', + rich_text: '', + meta_data: { + old_pos: 3, + new_pos: 5, + }, + }, + }, + ], + discussions: [], + renderingLines: false, +}; diff --git a/spec/lib/gitlab/ci/ansi2json_spec.rb b/spec/lib/gitlab/ci/ansi2json_spec.rb index 3c6bc46436b..3cd448d1aae 100644 --- a/spec/lib/gitlab/ci/ansi2json_spec.rb +++ b/spec/lib/gitlab/ci/ansi2json_spec.rb @@ -12,11 +12,26 @@ describe Gitlab::Ci::Ansi2json do ]) end - it 'adds new line in a separate element' do - expect(convert_json("Hello\nworld")).to eq([ - { offset: 0, content: [{ text: 'Hello' }] }, - { offset: 6, content: [{ text: 'world' }] } - ]) + context 'new lines' do + it 'adds new line when encountering \n' do + expect(convert_json("Hello\nworld")).to eq([ + { offset: 0, content: [{ text: 'Hello' }] }, + { offset: 6, content: [{ text: 'world' }] } + ]) + end + + it 'adds new line when encountering \r\n' do + expect(convert_json("Hello\r\nworld")).to eq([ + { offset: 0, content: [{ text: 'Hello' }] }, + { offset: 7, content: [{ text: 'world' }] } + ]) + end + + it 'replace the current line when encountering \r' do + expect(convert_json("Hello\rworld")).to eq([ + { offset: 0, content: [{ text: 'world' }] } + ]) + end end it 'recognizes color changing ANSI sequences' do @@ -113,10 +128,6 @@ describe Gitlab::Ci::Ansi2json do content: [], section_duration: '01:03', section: 'prepare-script' - }, - { - offset: 63, - content: [] } ]) end @@ -134,10 +145,6 @@ describe Gitlab::Ci::Ansi2json do content: [], section: 'prepare-script', section_duration: '01:03' - }, - { - offset: 56, - content: [] } ]) end @@ -157,7 +164,7 @@ describe Gitlab::Ci::Ansi2json do section_duration: '01:03' }, { - offset: 49, + offset: 91, content: [{ text: 'world' }] } ]) @@ -198,7 +205,7 @@ describe Gitlab::Ci::Ansi2json do expect(convert_json("#{section_start}hello")).to eq([ { offset: 0, - content: [{ text: "#{section_start.gsub("\033[0K", '')}hello" }] + content: [{ text: 'hello' }] } ]) end @@ -211,7 +218,7 @@ describe Gitlab::Ci::Ansi2json do expect(convert_json("#{section_start}hello")).to eq([ { offset: 0, - content: [{ text: "#{section_start.gsub("\033[0K", '').gsub('<', '<')}hello" }] + content: [{ text: 'hello' }] } ]) end @@ -231,10 +238,6 @@ describe Gitlab::Ci::Ansi2json do content: [], section: 'prepare-script', section_duration: '01:03' - }, - { - offset: 95, - content: [] } ]) end @@ -274,7 +277,7 @@ describe Gitlab::Ci::Ansi2json do section_duration: '00:02' }, { - offset: 106, + offset: 155, content: [{ text: 'baz' }], section: 'prepare-script' }, @@ -285,7 +288,7 @@ describe Gitlab::Ci::Ansi2json do section_duration: '01:03' }, { - offset: 158, + offset: 200, content: [{ text: 'world' }] } ]) @@ -318,14 +321,10 @@ describe Gitlab::Ci::Ansi2json do section_duration: '00:02' }, { - offset: 115, + offset: 164, content: [], section: 'prepare-script', section_duration: '01:03' - }, - { - offset: 164, - content: [] } ]) end @@ -380,7 +379,7 @@ describe Gitlab::Ci::Ansi2json do ] end - it 'returns the full line' do + it 'returns the line since last partially processed line' do expect(pass2.lines).to eq(lines) expect(pass2.append).to be_truthy end @@ -399,7 +398,7 @@ describe Gitlab::Ci::Ansi2json do ] end - it 'returns the full line' do + it 'returns the line since last partially processed line' do expect(pass2.lines).to eq(lines) expect(pass2.append).to be_falsey end @@ -416,7 +415,7 @@ describe Gitlab::Ci::Ansi2json do ] end - it 'returns the full line' do + it 'returns a blank line and the next line' do expect(pass2.lines).to eq(lines) expect(pass2.append).to be_falsey end @@ -502,10 +501,6 @@ describe Gitlab::Ci::Ansi2json do content: [], section: 'prepare-script', section_duration: '01:03' - }, - { - offset: 77, - content: [] } ] end diff --git a/spec/lib/gitlab/ci/config/entry/commands_spec.rb b/spec/lib/gitlab/ci/config/entry/commands_spec.rb index 269a3406913..8e7f9ab9706 100644 --- a/spec/lib/gitlab/ci/config/entry/commands_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/commands_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' describe Gitlab::Ci::Config::Entry::Commands do let(:entry) { described_class.new(config) } - context 'when entry config value is an array' do + context 'when entry config value is an array of strings' do let(:config) { %w(ls pwd) } describe '#value' do @@ -37,13 +37,74 @@ describe Gitlab::Ci::Config::Entry::Commands do end end - context 'when entry value is not valid' do + context 'when entry config value is array of arrays of strings' do + let(:config) { [['ls'], ['pwd', 'echo 1']] } + + describe '#value' do + it 'returns array of strings' do + expect(entry.value).to eq ['ls', 'pwd', 'echo 1'] + end + end + + describe '#errors' do + it 'does not append errors' do + expect(entry.errors).to be_empty + end + end + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when entry config value is array of strings and arrays of strings' do + let(:config) { ['ls', ['pwd', 'echo 1']] } + + describe '#value' do + it 'returns array of strings' do + expect(entry.value).to eq ['ls', 'pwd', 'echo 1'] + end + end + + describe '#errors' do + it 'does not append errors' do + expect(entry.errors).to be_empty + end + end + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when entry value is integer' do let(:config) { 1 } describe '#errors' do it 'saves errors' do expect(entry.errors) - .to include 'commands config should be an array of strings or a string' + .to include 'commands config should be a string or an array containing strings and arrays of strings' + end + end + end + + context 'when entry value is multi-level nested array' do + let(:config) { [['ls', ['echo 1']], 'pwd'] } + + describe '#errors' do + it 'saves errors' do + expect(entry.errors) + .to include 'commands config should be a string or an array containing strings and arrays of strings' + end + end + + describe '#valid?' do + it 'is not valid' do + expect(entry).not_to be_valid end end end diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb index 8243fcfd162..3877eec8887 100644 --- a/spec/lib/gitlab/ci/config/entry/root_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb @@ -298,7 +298,7 @@ describe Gitlab::Ci::Config::Entry::Root do describe '#errors' do it 'reports errors from child nodes' do expect(root.errors) - .to include 'before_script config should be an array of strings' + .to include 'before_script config should be an array containing strings and arrays of strings' end end end diff --git a/spec/lib/gitlab/ci/config/entry/script_spec.rb b/spec/lib/gitlab/ci/config/entry/script_spec.rb index d523243d3b6..57dc20ea628 100644 --- a/spec/lib/gitlab/ci/config/entry/script_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/script_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::Ci::Config::Entry::Script do let(:entry) { described_class.new(config) } describe 'validations' do - context 'when entry config value is correct' do + context 'when entry config value is array of strings' do let(:config) { %w(ls pwd) } describe '#value' do @@ -28,13 +28,74 @@ describe Gitlab::Ci::Config::Entry::Script do end end - context 'when entry value is not correct' do + context 'when entry config value is array of arrays of strings' do + let(:config) { [['ls'], ['pwd', 'echo 1']] } + + describe '#value' do + it 'returns array of strings' do + expect(entry.value).to eq ['ls', 'pwd', 'echo 1'] + end + end + + describe '#errors' do + it 'does not append errors' do + expect(entry.errors).to be_empty + end + end + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when entry config value is array containing strings and arrays of strings' do + let(:config) { ['ls', ['pwd', 'echo 1']] } + + describe '#value' do + it 'returns array of strings' do + expect(entry.value).to eq ['ls', 'pwd', 'echo 1'] + end + end + + describe '#errors' do + it 'does not append errors' do + expect(entry.errors).to be_empty + end + end + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when entry value is string' do let(:config) { 'ls' } describe '#errors' do it 'saves errors' do expect(entry.errors) - .to include 'script config should be an array of strings' + .to include 'script config should be an array containing strings and arrays of strings' + end + end + + describe '#valid?' do + it 'is not valid' do + expect(entry).not_to be_valid + end + end + end + + context 'when entry value is multi-level nested array' do + let(:config) { [['ls', ['echo 1']], 'pwd'] } + + describe '#errors' do + it 'saves errors' do + expect(entry.errors) + .to include 'script config should be an array containing strings and arrays of strings' end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb index 79acd3e4f54..e23aa09d881 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb @@ -94,7 +94,7 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Config do it 'appends configuration validation errors to pipeline errors' do expect(pipeline.errors.to_a) - .to include "jobs:rspec:before_script config should be an array of strings" + .to include "jobs:rspec:before_script config should be an array containing strings and arrays of strings" end it 'breaks the chain' do diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 375075ce8f3..c7ea6ed9ddb 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -330,7 +330,7 @@ module Gitlab } end - it "return commands with scripts concencaced" do + it "return commands with scripts concatenated" do expect(subject[:options][:before_script]).to eq(["global script"]) end end @@ -343,7 +343,7 @@ module Gitlab } end - it "return commands with scripts concencaced" do + it "return commands with scripts concatenated" do expect(subject[:options][:before_script]).to eq(["global script"]) end end @@ -356,21 +356,48 @@ module Gitlab } end - it "return commands with scripts concencaced" do + it "return commands with scripts concatenated" do expect(subject[:options][:before_script]).to eq(["local script"]) end end + + context 'when script is array of arrays of strings' do + let(:config) do + { + before_script: [["global script", "echo 1"], ["ls"], "pwd"], + test: { script: ["script"] } + } + end + + it "return commands with scripts concatenated" do + expect(subject[:options][:before_script]).to eq(["global script", "echo 1", "ls", "pwd"]) + end + end end describe "script" do - let(:config) do - { - test: { script: ["script"] } - } + context 'when script is array of strings' do + let(:config) do + { + test: { script: ["script"] } + } + end + + it "return commands with scripts concatenated" do + expect(subject[:options][:script]).to eq(["script"]) + end end - it "return commands with scripts concencaced" do - expect(subject[:options][:script]).to eq(["script"]) + context 'when script is array of arrays of strings' do + let(:config) do + { + test: { script: [["script"], ["echo 1"], "ls"] } + } + end + + it "return commands with scripts concatenated" do + expect(subject[:options][:script]).to eq(["script", "echo 1", "ls"]) + end end end @@ -413,6 +440,19 @@ module Gitlab expect(subject[:options][:after_script]).to eq(["local after_script"]) end end + + context 'when script is array of arrays of strings' do + let(:config) do + { + after_script: [["global script", "echo 1"], ["ls"], "pwd"], + test: { script: ["script"] } + } + end + + it "return after_script in options" do + expect(subject[:options][:after_script]).to eq(["global script", "echo 1", "ls", "pwd"]) + end + end end end @@ -1536,28 +1576,42 @@ module Gitlab config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } }) expect do Gitlab::Ci::YamlProcessor.new(config) - end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "before_script config should be an array of strings") + end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "before_script config should be an array containing strings and arrays of strings") end it "returns errors if job before_script parameter is not an array of strings" do config = YAML.dump({ rspec: { script: "test", before_script: [10, "test"] } }) expect do Gitlab::Ci::YamlProcessor.new(config) - end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array of strings") + end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array containing strings and arrays of strings") + end + + it "returns errors if job before_script parameter is multi-level nested array of strings" do + config = YAML.dump({ rspec: { script: "test", before_script: [["ls", ["pwd"]], "test"] } }) + expect do + Gitlab::Ci::YamlProcessor.new(config) + end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array containing strings and arrays of strings") end it "returns errors if after_script parameter is invalid" do config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } }) expect do Gitlab::Ci::YamlProcessor.new(config) - end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "after_script config should be an array of strings") + end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "after_script config should be an array containing strings and arrays of strings") end it "returns errors if job after_script parameter is not an array of strings" do config = YAML.dump({ rspec: { script: "test", after_script: [10, "test"] } }) expect do Gitlab::Ci::YamlProcessor.new(config) - end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array of strings") + end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array containing strings and arrays of strings") + end + + it "returns errors if job after_script parameter is multi-level nested array of strings" do + config = YAML.dump({ rspec: { script: "test", after_script: [["ls", ["pwd"]], "test"] } }) + expect do + Gitlab::Ci::YamlProcessor.new(config) + end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array containing strings and arrays of strings") end it "returns errors if image parameter is invalid" do diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb index 0f7f57095df..473ad639ead 100644 --- a/spec/lib/google_api/cloud_platform/client_spec.rb +++ b/spec/lib/google_api/cloud_platform/client_spec.rb @@ -104,7 +104,8 @@ describe GoogleApi::CloudPlatform::Client do enabled: legacy_abac }, ip_allocation_policy: { - use_ip_aliases: true + use_ip_aliases: true, + cluster_ipv4_cidr_block: '/16' }, addons_config: addons_config } |