Commit cb3e6b9c authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent dee93158
...@@ -54,11 +54,12 @@ export default { ...@@ -54,11 +54,12 @@ export default {
showLoadingIcon() { showLoadingIcon() {
return this.isLoadingCollapsedDiff || (!this.file.renderIt && !this.isCollapsed); return this.isLoadingCollapsedDiff || (!this.file.renderIt && !this.isCollapsed);
}, },
hasDiffLines() { hasDiff() {
return ( return (
this.file.highlighted_diff_lines && (this.file.highlighted_diff_lines &&
this.file.parallel_diff_lines && this.file.parallel_diff_lines &&
this.file.parallel_diff_lines.length > 0 this.file.parallel_diff_lines.length > 0) ||
!this.file.blob.readable_text
); );
}, },
isFileTooLarge() { isFileTooLarge() {
...@@ -82,7 +83,7 @@ export default { ...@@ -82,7 +83,7 @@ export default {
}, },
watch: { watch: {
isCollapsed: function fileCollapsedWatch(newVal, oldVal) { isCollapsed: function fileCollapsedWatch(newVal, oldVal) {
if (!newVal && oldVal && !this.hasDiffLines) { if (!newVal && oldVal && !this.hasDiff) {
this.handleLoadCollapsedDiff(); this.handleLoadCollapsedDiff();
} }
...@@ -103,7 +104,7 @@ export default { ...@@ -103,7 +104,7 @@ export default {
'setFileCollapsed', 'setFileCollapsed',
]), ]),
handleToggle() { handleToggle() {
if (!this.hasDiffLines) { if (!this.hasDiff) {
this.handleLoadCollapsedDiff(); this.handleLoadCollapsedDiff();
} else { } else {
this.isCollapsed = !this.isCollapsed; this.isCollapsed = !this.isCollapsed;
......
---
title: 'fixed #27164 Image cannot be collapsed on merge request changes tab'
merge_request: 18917
author: Jannik Lehmann
type: fixed
---
title: Reduce the allocated IP for Cluster and Services
merge_request: 18341
author:
type: changed
---
title: Let ANSI \r code replace the current job log line
merge_request: 18933
author:
type: fixed
---
title: Add support for YAML anchors in CI scripts.
merge_request: 18849
author:
type: changed
...@@ -181,6 +181,25 @@ that the YAML parser knows to interpret the whole thing as a string rather than ...@@ -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: 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` ### `image`
Used to specify [a Docker image](../docker/using_docker_images.md#what-is-an-image) to use for the job. 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: ...@@ -284,6 +303,33 @@ job:
- execute this after my script - 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`
`stages` is used to define stages that can be used by jobs and is defined `stages` is used to define stages that can be used by jobs and is defined
......
...@@ -175,6 +175,9 @@ NOTE: **Note:** ...@@ -175,6 +175,9 @@ NOTE: **Note:**
Starting from [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/issues/55902), all GKE clusters 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. 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 ### Cloud Run on GKE
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16566) in GitLab 12.4. > [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16566) in GitLab 12.4.
......
...@@ -22,11 +22,11 @@ module Gitlab ...@@ -22,11 +22,11 @@ module Gitlab
start_offset = @state.offset 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| stream.each_line do |line|
s = StringScanner.new(line) consume_line(line)
convert_line(s)
end end
# This must be assigned before flushing the current line # This must be assigned before flushing the current line
...@@ -52,26 +52,43 @@ module Gitlab ...@@ -52,26 +52,43 @@ module Gitlab
private private
def convert_line(scanner) def consume_line(line)
until scanner.eos? scanner = StringScanner.new(line)
if scanner.scan(Gitlab::Regex.build_trace_section_regex) consume_token(scanner) until scanner.eos?
handle_section(scanner) end
elsif scanner.scan(/\e([@-_])(.*?)([@-~])/)
handle_sequence(scanner) def consume_token(scanner)
elsif scanner.scan(/\e(([@-_])(.*?)?)?$/) if scan_token(scanner, Gitlab::Regex.build_trace_section_regex, consume: false)
break handle_section(scanner)
elsif scanner.scan(/</) elsif scan_token(scanner, /\e([@-_])(.*?)([@-~])/)
@state.current_line << '&lt;' handle_sequence(scanner)
elsif scanner.scan(/\r?\n/) elsif scan_token(scanner, /\e(([@-_])(.*?)?)?$/)
# we advance the offset of the next current line # stop scanning
# so it does not start from \n scanner.terminate
flush_current_line(advance_offset: scanner.matched_size) elsif scan_token(scanner, /</)
else @state.current_line << '&lt;'
@state.current_line << scanner.scan(/./m) elsif scan_token(scanner, /\r?\n/)
end flush_current_line
elsif scan_token(scanner, /\r/)
@state.offset += scanner.matched_size # 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
end end
...@@ -96,32 +113,50 @@ module Gitlab ...@@ -96,32 +113,50 @@ module Gitlab
section_name = sanitize_section_name(section) section_name = sanitize_section_name(section)
if action == "start" if action == "start"
handle_section_start(section_name, timestamp) handle_section_start(scanner, section_name, timestamp)
elsif action == "end" elsif action == "end"
handle_section_end(section_name, timestamp) handle_section_end(scanner, section_name, timestamp)
else
raise 'unsupported action'
end end
end end
def handle_section_start(section, timestamp) def handle_section_start(scanner, section, timestamp)
flush_current_line unless @state.current_line.empty? # We make a new line for new section
flush_current_line
@state.open_section(section, timestamp) @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 end
def handle_section_end(section, timestamp) def handle_section_end(scanner, section, timestamp)
return unless @state.section_open?(section) 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) @state.close_section(section, timestamp)
# ensure that section end is detached from the last # we need to consume match before handling
# line in the section # 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 flush_current_line
end end
def flush_current_line(advance_offset: 0) def flush_current_line
@lines << @state.current_line.to_h unless @state.current_line.empty?
@lines << @state.current_line.to_h
end
@state.set_current_line!(advance_offset: advance_offset) @state.new_line!
end end
def sanitize_section_name(section) def sanitize_section_name(section)
......
...@@ -47,12 +47,17 @@ module Gitlab ...@@ -47,12 +47,17 @@ module Gitlab
@current_segment.text << data @current_segment.text << data
end end
def clear!
@segments.clear
@current_segment = Segment.new(style: style)
end
def style def style
@current_segment.style @current_segment.style
end end
def empty? def empty?
@segments.empty? && @current_segment.empty? @segments.empty? && @current_segment.empty? && @section_duration.nil?
end end
def update_style(ansi_commands) def update_style(ansi_commands)
......
...@@ -46,9 +46,9 @@ module Gitlab ...@@ -46,9 +46,9 @@ module Gitlab
@open_sections.key?(section) @open_sections.key?(section)
end end
def set_current_line!(style: nil, advance_offset: 0) def new_line!(style: nil)
new_line = Line.new( new_line = Line.new(
offset: @offset + advance_offset, offset: @offset,
style: style || @current_line.style, style: style || @current_line.style,
sections: @open_sections.keys sections: @open_sections.keys
) )
......
...@@ -11,11 +11,11 @@ module Gitlab ...@@ -11,11 +11,11 @@ module Gitlab
include ::Gitlab::Config::Entry::Validatable include ::Gitlab::Config::Entry::Validatable
validations do validations do
validates :config, array_of_strings_or_string: true validates :config, string_or_nested_array_of_strings: true
end end
def value def value
Array(@config) Array(@config).flatten(1)
end end
end end
end end
......
...@@ -11,7 +11,11 @@ module Gitlab ...@@ -11,7 +11,11 @@ module Gitlab
include ::Gitlab::Config::Entry::Validatable include ::Gitlab::Config::Entry::Validatable
validations do validations do
validates :config, array_of_strings: true validates :config, nested_array_of_strings: true
end
def value
config.flatten(1)
end end
end end
end end
......
...@@ -228,6 +228,34 @@ module Gitlab ...@@ -228,6 +228,34 @@ module Gitlab
end end
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 class TypeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value) def validate_each(record, attribute, value)
type = options[:with] type = options[:with]
......
...@@ -12,6 +12,7 @@ module GoogleApi ...@@ -12,6 +12,7 @@ module GoogleApi
SCOPE = 'https://www.googleapis.com/auth/cloud-platform' SCOPE = 'https://www.googleapis.com/auth/cloud-platform'
LEAST_TOKEN_LIFE_TIME = 10.minutes LEAST_TOKEN_LIFE_TIME = 10.minutes
CLUSTER_MASTER_AUTH_USERNAME = 'admin' CLUSTER_MASTER_AUTH_USERNAME = 'admin'
CLUSTER_IPV4_CIDR_BLOCK = '/16'
class << self class << self
def session_key_for_token def session_key_for_token
...@@ -97,7 +98,8 @@ module GoogleApi ...@@ -97,7 +98,8 @@ module GoogleApi
enabled: legacy_abac enabled: legacy_abac
}, },
ip_allocation_policy: { 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| addons_config: enable_addons.each_with_object({}) do |addon, hash|
hash[addon] = { disabled: false } hash[addon] = { disabled: false }
......
...@@ -3,14 +3,15 @@ import DiffFileComponent from '~/diffs/components/diff_file.vue'; ...@@ -3,14 +3,15 @@ import DiffFileComponent from '~/diffs/components/diff_file.vue';
import { diffViewerModes, diffViewerErrors } from '~/ide/constants'; import { diffViewerModes, diffViewerErrors } from '~/ide/constants';
import { createStore } from 'ee_else_ce/mr_notes/stores'; import { createStore } from 'ee_else_ce/mr_notes/stores';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; 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', () => { describe('DiffFile', () => {
let vm; let vm;
beforeEach(() => { beforeEach(() => {
vm = createComponentWithStore(Vue.extend(DiffFileComponent), createStore(), { vm = createComponentWithStore(Vue.extend(DiffFileComponent), createStore(), {
file: JSON.parse(JSON.stringify(diffFileMockData)), file: JSON.parse(JSON.stringify(diffFileMockDataReadable)),
canCurrentUserFork: false, canCurrentUserFork: false,
}).$mount(); }).$mount();
}); });
...@@ -81,6 +82,24 @@ describe('DiffFile', () => { ...@@ -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 => { it('should be collapsed for renamed files', done => {
vm.renderIt = true; vm.renderIt = true;
vm.isCollapsed = false; vm.isCollapsed = false;
...@@ -184,5 +203,31 @@ describe('DiffFile', () => { ...@@ -184,5 +203,31 @@ describe('DiffFile', () => {
.then(done) .then(done)
.catch(done.fail); .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);
});
}); });
}); });
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,
};
...@@ -12,11 +12,26 @@ describe Gitlab::Ci::Ansi2json do ...@@ -12,11 +12,26 @@ describe Gitlab::Ci::Ansi2json do
]) ])
end end
it 'adds new line in a separate element' do context 'new lines' do
expect(convert_json("Hello\nworld")).to eq([ it 'adds new line when encountering \n' do
{ offset: 0, content: [{ text: 'Hello' }] }, expect(convert_json("Hello\nworld")).to eq([
{ offset: 6, content: [{ text: 'world' }] } { 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 end
it 'recognizes color changing ANSI sequences' do it 'recognizes color changing ANSI sequences' do
...@@ -113,10 +128,6 @@ describe Gitlab::Ci::Ansi2json do ...@@ -113,10 +128,6 @@ describe Gitlab::Ci::Ansi2json do
content: [], content: [],
section_duration: '01:03', section_duration: '01:03',
section: 'prepare-script' section: 'prepare-script'
},
{
offset: 63,
content: []
} }
]) ])
end end
...@@ -134,10 +145,6 @@ describe Gitlab::Ci::Ansi2json do ...@@ -134,10 +145,6 @@ describe Gitlab::Ci::Ansi2json do
content: [], content: [],
section: 'prepare-script', section: 'prepare-script',
section_duration: '01:03' section_duration: '01:03'
},
{
offset: 56,
content: []
} }
]) ])
end end
...@@ -157,7 +164,7 @@ describe Gitlab::Ci::Ansi2json do ...@@ -157,7 +164,7 @@ describe Gitlab::Ci::Ansi2json do
section_duration: '01:03' section_duration: '01:03'
}, },
{ {
offset: 49, offset: 91,
content: [{ text: 'world' }] content: [{ text: 'world' }]
} }
]) ])
...@@ -198,7 +205,7 @@ describe Gitlab::Ci::Ansi2json do ...@@ -198,7 +205,7 @@ describe Gitlab::Ci::Ansi2json do
expect(convert_json("#{section_start}hello")).to eq([ expect(convert_json("#{section_start}hello")).to eq([
{ {
offset: 0, offset: 0,
content: [{ text: "#{section_start.gsub("\033[0K", '')}hello" }] content: [{ text: 'hello' }]
} }
]) ])
end end
...@@ -211,7 +218,7 @@ describe Gitlab::Ci::Ansi2json do ...@@ -211,7 +218,7 @@ describe Gitlab::Ci::Ansi2json do
expect(convert_json("#{section_start}hello")).to eq([ expect(convert_json("#{section_start}hello")).to eq([
{ {
offset: 0, offset: 0,
content: [{ text: "#{section_start.gsub("\033[0K", '').gsub('<', '&lt;')}hello" }] content: [{ text: 'hello' }]
} }
]) ])
end end
...@@ -231,10 +238,6 @@ describe Gitlab::Ci::Ansi2json do ...@@ -231,10 +238,6 @@ describe Gitlab::Ci::Ansi2json do
content: [], content: [],
section: 'prepare-script', section: 'prepare-script',
section_duration: '01:03' section_duration: '01:03'
},
{
offset: 95,
content: []
} }
]) ])
end end
...@@ -274,7 +277,7 @@ describe Gitlab::Ci::Ansi2json do ...@@ -274,7 +277,7 @@ describe Gitlab::Ci::Ansi2json do
section_duration: '00:02' section_duration: '00:02'
}, },
{ {
offset: 106, offset: 155,
content: [{ text: 'baz' }], content: [{ text: 'baz' }],
section: 'prepare-script' section: 'prepare-script'
}, },
...@@ -285,7 +288,7 @@ describe Gitlab::Ci::Ansi2json do ...@@ -285,7 +288,7 @@ describe Gitlab::Ci::Ansi2json do
section_duration: '01:03' section_duration: '01:03'
}, },
{ {
offset: 158, offset: 200,
content: [{ text: 'world' }] content: [{ text: 'world' }]
} }
]) ])
...@@ -318,14 +321,10 @@ describe Gitlab::Ci::Ansi2json do ...@@ -318,14 +321,10 @@ describe Gitlab::Ci::Ansi2json do
section_duration: '00:02' section_duration: '00:02'
}, },
{ {
offset: 115, offset: 164,
content: [], content: [],
section: 'prepare-script', section: 'prepare-script',
section_duration: '01:03' section_duration: '01:03'
},
{
offset: 164,
content: []
} }
]) ])
end end
...@@ -380,7 +379,7 @@ describe Gitlab::Ci::Ansi2json do ...@@ -380,7 +379,7 @@ describe Gitlab::Ci::Ansi2json do
] ]
end 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.lines).to eq(lines)
expect(pass2.append).to be_truthy expect(pass2.append).to be_truthy
end end
...@@ -399,7 +398,7 @@ describe Gitlab::Ci::Ansi2json do ...@@ -399,7 +398,7 @@ describe Gitlab::Ci::Ansi2json do
] ]
end 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.lines).to eq(lines)
expect(pass2.append).to be_falsey expect(pass2.append).to be_falsey
end end
...@@ -416,7 +415,7 @@ describe Gitlab::Ci::Ansi2json do ...@@ -416,7 +415,7 @@ describe Gitlab::Ci::Ansi2json do
] ]
end 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.lines).to eq(lines)
expect(pass2.append).to be_falsey expect(pass2.append).to be_falsey
end end
...@@ -502,10 +501,6 @@ describe Gitlab::Ci::Ansi2json do ...@@ -502,10 +501,6 @@ describe Gitlab::Ci::Ansi2json do
content: [], content: [],
section: 'prepare-script', section: 'prepare-script',
section_duration: '01:03' section_duration: '01:03'
},
{
offset: 77,
content: []
} }
] ]
end end
......
...@@ -5,7 +5,7 @@ require 'spec_helper' ...@@ -5,7 +5,7 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Commands do describe Gitlab::Ci::Config::Entry::Commands do
let(:entry) { described_class.new(config) } 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) } let(:config) { %w(ls pwd) }
describe '#value' do describe '#value' do
...@@ -37,13 +37,74 @@ describe Gitlab::Ci::Config::Entry::Commands do ...@@ -37,13 +37,74 @@ describe Gitlab::Ci::Config::Entry::Commands do
end end
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 } let(:config) { 1 }
describe '#errors' do describe '#errors' do
it 'saves errors' do it 'saves errors' do
expect(entry.errors) 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 end
end end
......
...@@ -298,7 +298,7 @@ describe Gitlab::Ci::Config::Entry::Root do ...@@ -298,7 +298,7 @@ describe Gitlab::Ci::Config::Entry::Root do
describe '#errors' do describe '#errors' do
it 'reports errors from child nodes' do it 'reports errors from child nodes' do
expect(root.errors) 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 end
end end
......
...@@ -6,7 +6,7 @@ describe Gitlab::Ci::Config::Entry::Script do ...@@ -6,7 +6,7 @@ describe Gitlab::Ci::Config::Entry::Script do
let(:entry) { described_class.new(config) } let(:entry) { described_class.new(config) }
describe 'validations' do 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) } let(:config) { %w(ls pwd) }
describe '#value' do describe '#value' do
...@@ -28,13 +28,74 @@ describe Gitlab::Ci::Config::Entry::Script do ...@@ -28,13 +28,74 @@ describe Gitlab::Ci::Config::Entry::Script do
end end
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' } let(:config) { 'ls' }
describe '#errors' do describe '#errors' do
it 'saves errors' do it 'saves errors' do
expect(entry.errors) 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
end end
......
...@@ -94,7 +94,7 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Config do ...@@ -94,7 +94,7 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Config do
it 'appends configuration validation errors to pipeline errors' do it 'appends configuration validation errors to pipeline errors' do
expect(pipeline.errors.to_a) 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 end
it 'breaks the chain' do it 'breaks the chain' do
......
...@@ -330,7 +330,7 @@ module Gitlab ...@@ -330,7 +330,7 @@ module Gitlab
} }
end end
it "return commands with scripts concencaced" do it "return commands with scripts concatenated" do
expect(subject[:options][:before_script]).to eq(["global script"]) expect(subject[:options][:before_script]).to eq(["global script"])
end end
end end
...@@ -343,7 +343,7 @@ module Gitlab ...@@ -343,7 +343,7 @@ module Gitlab
} }
end end
it "return commands with scripts concencaced" do it "return commands with scripts concatenated" do
expect(subject[:options][:before_script]).to eq(["global script"]) expect(subject[:options][:before_script]).to eq(["global script"])
end end
end end
...@@ -356,21 +356,48 @@ module Gitlab ...@@ -356,21 +356,48 @@ module Gitlab
} }
end end
it "return commands with scripts concencaced" do it "return commands with scripts concatenated" do
expect(subject[:options][:before_script]).to eq(["local script"]) expect(subject[:options][:before_script]).to eq(["local script"])
end end
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 end
describe "script" do describe "script" do
let(:config) do context 'when script is array of strings' do
{ let(:config) do
test: { script: ["script"] } {
} test: { script: ["script"] }
}
end
it "return commands with scripts concatenated" do
expect(subject[:options][:script]).to eq(["script"])
end
end end
it "return commands with scripts concencaced" do context 'when script is array of arrays of strings' do
expect(subject[:options][:script]).to eq(["script"]) 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
end end
...@@ -413,6 +440,19 @@ module Gitlab ...@@ -413,6 +440,19 @@ module Gitlab
expect(subject[:options][:after_script]).to eq(["local after_script"]) expect(subject[:options][:after_script]).to eq(["local after_script"])
end end
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
end end
...@@ -1536,28 +1576,42 @@ module Gitlab ...@@ -1536,28 +1576,42 @@ module Gitlab
config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } }) config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config) 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 end
it "returns errors if job before_script parameter is not an array of strings" do 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"] } }) config = YAML.dump({ rspec: { script: "test", before_script: [10, "test"] } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config) 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 end
it "returns errors if after_script parameter is invalid" do it "returns errors if after_script parameter is invalid" do
config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } }) config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config) 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 end
it "returns errors if job after_script parameter is not an array of strings" do 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"] } }) config = YAML.dump({ rspec: { script: "test", after_script: [10, "test"] } })
expect do expect do
Gitlab::Ci::YamlProcessor.new(config) 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 end
it "returns errors if image parameter is invalid" do it "returns errors if image parameter is invalid" do
......
...@@ -104,7 +104,8 @@ describe GoogleApi::CloudPlatform::Client do ...@@ -104,7 +104,8 @@ describe GoogleApi::CloudPlatform::Client do
enabled: legacy_abac enabled: legacy_abac
}, },
ip_allocation_policy: { ip_allocation_policy: {
use_ip_aliases: true use_ip_aliases: true,
cluster_ipv4_cidr_block: '/16'
}, },
addons_config: addons_config addons_config: addons_config
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment