Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2763994b8f
commit
74b99c4264
|
@ -217,52 +217,50 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="diff-grid-row diff-grid-row-full diff-tr line_holder match expansion">
|
||||
<div :class="{ parallel: !inline }" class="diff-grid-left diff-grid-2-col left-side">
|
||||
<div
|
||||
class="diff-td diff-line-num gl-text-center! gl-p-0! gl-w-full! gl-display-flex gl-flex-direction-column"
|
||||
<div>
|
||||
<div
|
||||
class="diff-td diff-line-num gl-text-center! gl-p-0! gl-w-full! gl-display-flex gl-flex-direction-column"
|
||||
>
|
||||
<button
|
||||
v-if="showExpandDown"
|
||||
v-gl-tooltip.left
|
||||
:title="s__('Diffs|Next 20 lines')"
|
||||
:disabled="loading.down"
|
||||
type="button"
|
||||
class="js-unfold-down gl-rounded-0 gl-border-0 diff-line-expand-button"
|
||||
@click="handleExpandLines($options.EXPAND_DOWN)"
|
||||
>
|
||||
<button
|
||||
v-if="showExpandDown"
|
||||
v-gl-tooltip.left
|
||||
:title="s__('Diffs|Next 20 lines')"
|
||||
:disabled="loading.down"
|
||||
type="button"
|
||||
class="js-unfold-down gl-rounded-0 gl-border-0 diff-line-expand-button"
|
||||
@click="handleExpandLines($options.EXPAND_DOWN)"
|
||||
>
|
||||
<gl-loading-icon v-if="loading.down" size="sm" color="dark" inline />
|
||||
<gl-icon v-else name="expand-down" />
|
||||
</button>
|
||||
<button
|
||||
v-if="lineCountBetween !== -1 && lineCountBetween < 20"
|
||||
v-gl-tooltip.left
|
||||
:title="s__('Diffs|Expand all lines')"
|
||||
:disabled="loading.all"
|
||||
type="button"
|
||||
class="js-unfold-all gl-rounded-0 gl-border-0 diff-line-expand-button"
|
||||
@click="handleExpandLines()"
|
||||
>
|
||||
<gl-loading-icon v-if="loading.all" size="sm" color="dark" inline />
|
||||
<gl-icon v-else name="expand" />
|
||||
</button>
|
||||
<button
|
||||
v-if="showExpandUp"
|
||||
v-gl-tooltip.left
|
||||
:title="s__('Diffs|Previous 20 lines')"
|
||||
:disabled="loading.up"
|
||||
type="button"
|
||||
class="js-unfold gl-rounded-0 gl-border-0 diff-line-expand-button"
|
||||
@click="handleExpandLines($options.EXPAND_UP)"
|
||||
>
|
||||
<gl-loading-icon v-if="loading.up" size="sm" color="dark" inline />
|
||||
<gl-icon v-else name="expand-up" />
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-safe-html="line.rich_text"
|
||||
class="gl-display-flex! gl-flex-direction-column gl-justify-content-center diff-td line_content left-side gl-white-space-normal!"
|
||||
></div>
|
||||
<gl-loading-icon v-if="loading.down" size="sm" color="dark" inline />
|
||||
<gl-icon v-else name="expand-down" />
|
||||
</button>
|
||||
<button
|
||||
v-if="lineCountBetween !== -1 && lineCountBetween < 20"
|
||||
v-gl-tooltip.left
|
||||
:title="s__('Diffs|Expand all lines')"
|
||||
:disabled="loading.all"
|
||||
type="button"
|
||||
class="js-unfold-all gl-rounded-0 gl-border-0 diff-line-expand-button"
|
||||
@click="handleExpandLines()"
|
||||
>
|
||||
<gl-loading-icon v-if="loading.all" size="sm" color="dark" inline />
|
||||
<gl-icon v-else name="expand" />
|
||||
</button>
|
||||
<button
|
||||
v-if="showExpandUp"
|
||||
v-gl-tooltip.left
|
||||
:title="s__('Diffs|Previous 20 lines')"
|
||||
:disabled="loading.up"
|
||||
type="button"
|
||||
class="js-unfold gl-rounded-0 gl-border-0 diff-line-expand-button"
|
||||
@click="handleExpandLines($options.EXPAND_UP)"
|
||||
>
|
||||
<gl-loading-icon v-if="loading.up" size="sm" color="dark" inline />
|
||||
<gl-icon v-else name="expand-up" />
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-safe-html="line.rich_text"
|
||||
class="gl-display-flex! gl-flex-direction-column gl-justify-content-center diff-td line_content left-side gl-white-space-normal!"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -197,17 +197,33 @@ export default {
|
|||
@mousedown="handleParallelLineMouseDown"
|
||||
>
|
||||
<template v-for="(line, index) in diffLines">
|
||||
<template v-if="line.isMatchLineLeft || line.isMatchLineRight">
|
||||
<div
|
||||
v-if="line.isMatchLineLeft || line.isMatchLineRight"
|
||||
:key="`expand-${index}`"
|
||||
class="diff-grid-row diff-tr line_holder match expansion"
|
||||
>
|
||||
<diff-expansion-cell
|
||||
:key="`expand-${index}`"
|
||||
:file="diffFile"
|
||||
:line="line.left"
|
||||
:is-top="index === 0"
|
||||
:is-bottom="index + 1 === diffLinesLength"
|
||||
:inline="inline"
|
||||
:line-count-between="getCountBetweenIndex(index)"
|
||||
:class="{ parallel: !inline }"
|
||||
class="diff-grid-left diff-grid-2-col left-side"
|
||||
/>
|
||||
</template>
|
||||
<diff-expansion-cell
|
||||
v-if="!inline"
|
||||
:file="diffFile"
|
||||
:line="line.left"
|
||||
:is-top="index === 0"
|
||||
:is-bottom="index + 1 === diffLinesLength"
|
||||
:inline="inline"
|
||||
:line-count-between="getCountBetweenIndex(index)"
|
||||
:class="{ parallel: !inline }"
|
||||
class="diff-grid-right diff-grid-2-col right-side"
|
||||
/>
|
||||
</div>
|
||||
<diff-row
|
||||
v-if="!line.isMatchLineLeft && !line.isMatchLineRight"
|
||||
:key="line.line_code"
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import ResourceLinksBlock from 'ee_component/linked_resources/components/resource_links_block.vue';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
export default function initLinkedResources() {
|
||||
const linkedResourcesRootElement = document.querySelector('.js-linked-resources-root');
|
||||
|
||||
if (linkedResourcesRootElement) {
|
||||
const { issuableId, canAddResourceLinks, helpPath } = linkedResourcesRootElement.dataset;
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: createDefaultClient(),
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new Vue({
|
||||
el: linkedResourcesRootElement,
|
||||
name: 'LinkedResourcesRoot',
|
||||
apolloProvider,
|
||||
components: {
|
||||
resourceLinksBlock: ResourceLinksBlock,
|
||||
},
|
||||
|
|
|
@ -206,7 +206,6 @@ export default {
|
|||
|
||||
<gl-button
|
||||
v-if="isCollapsible"
|
||||
class="js-collapse-btn"
|
||||
data-testid="report-section-expand-button"
|
||||
data-qa-selector="expand_report_button"
|
||||
@click="toggleCollapsed"
|
||||
|
|
|
@ -189,15 +189,10 @@ export default {
|
|||
axios
|
||||
.get(`${this.blobInfo.webPath}?format=json&viewer=${type}`)
|
||||
.then(async ({ data: { html, binary } }) => {
|
||||
this.isRenderingLegacyTextViewer = true;
|
||||
|
||||
if (type === SIMPLE_BLOB_VIEWER) {
|
||||
this.isRenderingLegacyTextViewer = true;
|
||||
|
||||
this.legacySimpleViewer = html;
|
||||
|
||||
window.requestIdleCallback(() => {
|
||||
this.isRenderingLegacyTextViewer = false;
|
||||
new LineHighlighter(); // eslint-disable-line no-new
|
||||
});
|
||||
} else {
|
||||
this.legacyRichViewer = html;
|
||||
}
|
||||
|
@ -205,6 +200,14 @@ export default {
|
|||
this.isBinary = binary;
|
||||
this.isLoadingLegacyViewer = false;
|
||||
|
||||
window.requestIdleCallback(() => {
|
||||
this.isRenderingLegacyTextViewer = false;
|
||||
|
||||
if (type === SIMPLE_BLOB_VIEWER) {
|
||||
new LineHighlighter(); // eslint-disable-line no-new
|
||||
}
|
||||
});
|
||||
|
||||
await this.$nextTick();
|
||||
handleLocationHash(); // Ensures that we scroll to the hash when async content is loaded
|
||||
})
|
||||
|
|
|
@ -575,3 +575,11 @@ span.idiff {
|
|||
@include gl-text-center;
|
||||
}
|
||||
}
|
||||
|
||||
// *:nth-of-type(1n+5) - makes sure we do not render elements 5+ right away when
|
||||
// viewing a file. Even though the HTML is injected in the DOM, as long as we do
|
||||
// not render those elements, the browser doesn't need to spend resources
|
||||
// calculating and repainting what's hidden.
|
||||
.file-holder [data-loading] .file-content *:nth-of-type(1n+5) {
|
||||
@include gl-display-none;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ module Participable
|
|||
when User
|
||||
participants << source
|
||||
when Participable
|
||||
next if skippable_system_notes?(source, participants)
|
||||
next unless !verify_access || source_visible_to_user?(source, current_user)
|
||||
|
||||
source.class.participant_attrs.each do |attr|
|
||||
|
@ -133,6 +134,13 @@ module Participable
|
|||
participants.merge(extractor.users)
|
||||
end
|
||||
|
||||
def skippable_system_notes?(source, participants)
|
||||
source.is_a?(Note) &&
|
||||
source.system? &&
|
||||
source.author.in?(participants) &&
|
||||
!source.note.match?(User.reference_pattern)
|
||||
end
|
||||
|
||||
def use_internal_notes_extractor_for?(source)
|
||||
source.is_a?(Note) && source.confidential?
|
||||
end
|
||||
|
|
|
@ -74,13 +74,11 @@ module Ci
|
|||
end
|
||||
|
||||
def runner_version_with_updated_status(runner_version)
|
||||
version = runner_version['version']
|
||||
suggestion = upgrade_check.check_runner_upgrade_status(version)
|
||||
new_status = suggestion.each_key.first
|
||||
_, new_status = upgrade_check.check_runner_upgrade_suggestion(runner_version.version)
|
||||
|
||||
if new_status != :error && new_status != runner_version['status'].to_sym
|
||||
if new_status != :error && new_status != runner_version.status.to_sym
|
||||
{
|
||||
version: version,
|
||||
version: runner_version.version,
|
||||
status: Ci::RunnerVersion.statuses[new_status]
|
||||
}
|
||||
end
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338165
|
|||
milestone: '14.5'
|
||||
type: development
|
||||
group: group::pipeline insights
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347144
|
|||
milestone: '14.10'
|
||||
type: development
|
||||
group: group::pipeline execution
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/343465
|
|||
milestone: '14.5'
|
||||
type: development
|
||||
group: group::pipeline insights
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -268,7 +268,6 @@ gitlab_rails['ldap_servers'] = {
|
|||
'port' => 636,
|
||||
...
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -444,15 +443,15 @@ If initially your LDAP configuration looked like:
|
|||
|
||||
1. In `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['ldap_servers'] = {
|
||||
'main' => {
|
||||
# snip...
|
||||
'bind_dn' => 'admin',
|
||||
'password' => '123'
|
||||
}
|
||||
}
|
||||
```
|
||||
```ruby
|
||||
gitlab_rails['ldap_servers'] = {
|
||||
'main' => {
|
||||
# snip...
|
||||
'bind_dn' => 'admin',
|
||||
'password' => '123'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Edit the encrypted secret:
|
||||
|
||||
|
|
|
@ -20399,8 +20399,6 @@ Vulnerability sort values.
|
|||
| <a id="vulnerabilitysortreport_type_desc"></a>`report_type_desc` | Report Type in descending order. |
|
||||
| <a id="vulnerabilitysortseverity_asc"></a>`severity_asc` | Severity in ascending order. |
|
||||
| <a id="vulnerabilitysortseverity_desc"></a>`severity_desc` | Severity in descending order. |
|
||||
| <a id="vulnerabilitysortstate_asc"></a>`state_asc` | State in ascending order. |
|
||||
| <a id="vulnerabilitysortstate_desc"></a>`state_desc` | State in descending order. |
|
||||
|
||||
### `VulnerabilityState`
|
||||
|
||||
|
|
|
@ -5,44 +5,12 @@ module Gitlab
|
|||
class RunnerUpgradeCheck
|
||||
include Singleton
|
||||
|
||||
def check_runner_upgrade_status(runner_version)
|
||||
runner_version = ::Gitlab::VersionInfo.parse(runner_version, parse_suffix: true)
|
||||
|
||||
return { invalid_version: runner_version } unless runner_version.valid?
|
||||
return { error: runner_version } unless runner_releases_store.releases
|
||||
|
||||
# Recommend update if outside of backport window
|
||||
recommended_version = recommendation_if_outside_backport_window(runner_version)
|
||||
return { recommended: recommended_version } if recommended_version
|
||||
|
||||
# Recommend patch update if there's a newer release in a same minor branch as runner
|
||||
recommended_version = recommended_runner_release_update(runner_version)
|
||||
return { recommended: recommended_version } if recommended_version
|
||||
|
||||
# Consider update if there's a newer release within the currently deployed GitLab version
|
||||
available_version = available_runner_release(runner_version)
|
||||
return { available: available_version } if available_version
|
||||
|
||||
{ not_available: runner_version }
|
||||
def check_runner_upgrade_suggestion(runner_version)
|
||||
check_runner_upgrade_suggestions(runner_version).first
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def recommended_runner_release_update(runner_version)
|
||||
recommended_release = runner_releases_store.releases_by_minor[runner_version.without_patch]
|
||||
return recommended_release if recommended_release && recommended_release > runner_version
|
||||
|
||||
# Consider the edge case of pre-release runner versions that get registered, but are never published.
|
||||
# In this case, suggest the latest compatible runner version
|
||||
latest_release = runner_releases_store.releases_by_minor.values.select { |v| v < gitlab_version }.max
|
||||
latest_release if latest_release && latest_release > runner_version
|
||||
end
|
||||
|
||||
def available_runner_release(runner_version)
|
||||
available_release = runner_releases_store.releases_by_minor[gitlab_version.without_patch]
|
||||
available_release if available_release && available_release > runner_version
|
||||
end
|
||||
|
||||
def gitlab_version
|
||||
@gitlab_version ||= ::Gitlab::VersionInfo.parse(::Gitlab::VERSION, parse_suffix: true)
|
||||
end
|
||||
|
@ -51,9 +19,55 @@ module Gitlab
|
|||
RunnerReleases.instance
|
||||
end
|
||||
|
||||
def recommendation_if_outside_backport_window(runner_version)
|
||||
return if runner_releases_store.releases.empty?
|
||||
return if runner_version >= runner_releases_store.releases.last # return early if runner version is too new
|
||||
def add_suggestion(suggestions, runner_version, version, status)
|
||||
return false unless version && version > runner_version
|
||||
|
||||
suggestions[version] = status
|
||||
true
|
||||
end
|
||||
|
||||
def check_runner_upgrade_suggestions(runner_version)
|
||||
runner_version = ::Gitlab::VersionInfo.parse(runner_version, parse_suffix: true)
|
||||
|
||||
return { runner_version => :invalid_version } unless runner_version.valid?
|
||||
return { runner_version => :error } unless runner_releases_store.releases
|
||||
|
||||
suggestions = {}
|
||||
|
||||
# Recommend update if outside of backport window
|
||||
unless add_recommendation_if_outside_backport_window(runner_version, suggestions)
|
||||
# Recommend patch update if there's a newer release in a same minor branch as runner
|
||||
add_recommended_runner_release_update(runner_version, suggestions)
|
||||
end
|
||||
|
||||
# Consider update if there's a newer release within the currently deployed GitLab version
|
||||
add_available_runner_release(runner_version, suggestions)
|
||||
|
||||
suggestions[runner_version] = :not_available if suggestions.empty?
|
||||
|
||||
suggestions
|
||||
end
|
||||
|
||||
def add_recommended_runner_release_update(runner_version, suggestions)
|
||||
recommended_release = runner_releases_store.releases_by_minor[runner_version.without_patch]
|
||||
return true if add_suggestion(suggestions, runner_version, recommended_release, :recommended)
|
||||
|
||||
# Consider the edge case of pre-release runner versions that get registered, but are never published.
|
||||
# In this case, suggest the latest compatible runner version
|
||||
latest_release = runner_releases_store.releases_by_minor.values.select { |v| v < gitlab_version }.max
|
||||
add_suggestion(suggestions, runner_version, latest_release, :recommended)
|
||||
end
|
||||
|
||||
def add_available_runner_release(runner_version, suggestions)
|
||||
available_version = runner_releases_store.releases_by_minor[gitlab_version.without_patch]
|
||||
unless suggestions.include?(available_version)
|
||||
add_suggestion(suggestions, runner_version, available_version, :available)
|
||||
end
|
||||
end
|
||||
|
||||
def add_recommendation_if_outside_backport_window(runner_version, suggestions)
|
||||
return false if runner_releases_store.releases.empty?
|
||||
return false if runner_version >= runner_releases_store.releases.last # return early if runner version is too new
|
||||
|
||||
minor_releases_with_index = runner_releases_store.releases_by_minor.keys.each_with_index.to_h
|
||||
runner_minor_version_index = minor_releases_with_index[runner_version.without_patch]
|
||||
|
@ -62,14 +76,15 @@ module Gitlab
|
|||
outside_window = minor_releases_with_index.count - runner_minor_version_index > 3
|
||||
|
||||
if outside_window
|
||||
recommended_release = runner_releases_store.releases_by_minor[gitlab_version.without_patch]
|
||||
|
||||
recommended_release if recommended_release && recommended_release > runner_version
|
||||
recommended_version = runner_releases_store.releases_by_minor[gitlab_version.without_patch]
|
||||
return add_suggestion(suggestions, runner_version, recommended_version, :recommended)
|
||||
end
|
||||
else
|
||||
# If unknown runner version, then recommend the latest version for the GitLab instance
|
||||
recommended_runner_release_update(gitlab_version)
|
||||
return add_recommended_runner_release_update(gitlab_version, suggestions)
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23477,6 +23477,9 @@ msgstr ""
|
|||
msgid "LinkedResources|Cancel"
|
||||
msgstr ""
|
||||
|
||||
msgid "LinkedResources|Fetching linked resources"
|
||||
msgstr ""
|
||||
|
||||
msgid "LinkedResources|Link"
|
||||
msgstr ""
|
||||
|
||||
|
@ -23486,6 +23489,12 @@ msgstr ""
|
|||
msgid "LinkedResources|Read more about linked resources"
|
||||
msgstr ""
|
||||
|
||||
msgid "LinkedResources|Remove"
|
||||
msgstr ""
|
||||
|
||||
msgid "LinkedResources|Something went wrong while fetching linked resources for the incident."
|
||||
msgstr ""
|
||||
|
||||
msgid "LinkedResources|Text (Optional)"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
/**
|
||||
* Deprecated. Please do not use.
|
||||
* Please see https://gitlab.com/groups/gitlab-org/-/epics/2445
|
||||
|
@ -29,33 +27,6 @@ export const mountComponentWithStore = (Component, { el, props, store }) =>
|
|||
propsData: props || {},
|
||||
}).$mount(el);
|
||||
|
||||
/**
|
||||
* Deprecated. Please do not use.
|
||||
* Please see https://gitlab.com/groups/gitlab-org/-/epics/2445
|
||||
*/
|
||||
export const mountComponentWithSlots = (Component, { props, slots }) => {
|
||||
const component = new Component({
|
||||
propsData: props || {},
|
||||
});
|
||||
|
||||
component.$slots = slots;
|
||||
|
||||
return component.$mount();
|
||||
};
|
||||
|
||||
/**
|
||||
* Mount a component with the given render method.
|
||||
*
|
||||
* -----------------------------
|
||||
* Deprecated. Please do not use.
|
||||
* Please see https://gitlab.com/groups/gitlab-org/-/epics/2445
|
||||
* -----------------------------
|
||||
*
|
||||
* This helps with inserting slots that need to be compiled.
|
||||
*/
|
||||
export const mountComponentWithRender = (render, el = null) =>
|
||||
mountComponent(Vue.extend({ render }), {}, el);
|
||||
|
||||
/**
|
||||
* Deprecated. Please do not use.
|
||||
* Please see https://gitlab.com/groups/gitlab-org/-/epics/2445
|
||||
|
|
|
@ -28,8 +28,8 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
|
||||
before do
|
||||
allow(Gitlab::Ci::RunnerUpgradeCheck.instance)
|
||||
.to receive(:check_runner_upgrade_status)
|
||||
.and_return({ not_available: nil })
|
||||
.to receive(:check_runner_upgrade_suggestion)
|
||||
.and_return([nil, :not_available])
|
||||
end
|
||||
|
||||
describe do
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import mountComponent, { mountComponentWithSlots } from 'helpers/vue_mount_component_helper';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import HelpPopover from '~/vue_shared/components/help_popover.vue';
|
||||
import reportSection from '~/reports/components/report_section.vue';
|
||||
import ReportItem from '~/reports/components/report_item.vue';
|
||||
import ReportSection from '~/reports/components/report_section.vue';
|
||||
|
||||
describe('Report section', () => {
|
||||
let vm;
|
||||
describe('ReportSection component', () => {
|
||||
let wrapper;
|
||||
const ReportSection = Vue.extend(reportSection);
|
||||
const findCollapseButton = () => wrapper.findByTestId('report-section-expand-button');
|
||||
|
||||
const findButton = () => wrapper.findComponent(GlButton);
|
||||
const findPopover = () => wrapper.findComponent(HelpPopover);
|
||||
const findReportSection = () => wrapper.find('.js-report-section-container');
|
||||
|
||||
const resolvedIssues = [
|
||||
{
|
||||
|
@ -33,34 +32,24 @@ describe('Report section', () => {
|
|||
alwaysOpen: false,
|
||||
};
|
||||
|
||||
const createComponent = (props) => {
|
||||
wrapper = extendedWrapper(
|
||||
mount(reportSection, {
|
||||
propsData: {
|
||||
...defaultProps,
|
||||
...props,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return wrapper;
|
||||
const createComponent = ({ props = {}, data = {}, slots = {} } = {}) => {
|
||||
wrapper = mountExtended(ReportSection, {
|
||||
propsData: {
|
||||
...defaultProps,
|
||||
...props,
|
||||
},
|
||||
data() {
|
||||
return data;
|
||||
},
|
||||
slots,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
if (vm) {
|
||||
vm.$destroy();
|
||||
vm = null;
|
||||
}
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
}
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('computed', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(ReportSection, defaultProps);
|
||||
});
|
||||
|
||||
describe('isCollapsible', () => {
|
||||
const testMatrix = [
|
||||
{ hasIssues: false, alwaysOpen: false, isCollapsible: false },
|
||||
|
@ -73,12 +62,10 @@ describe('Report section', () => {
|
|||
const issues = hasIssues ? 'has issues' : 'has no issues';
|
||||
const open = alwaysOpen ? 'is always open' : 'is not always open';
|
||||
|
||||
it(`is ${isCollapsible}, if the report ${issues} and ${open}`, async () => {
|
||||
vm.hasIssues = hasIssues;
|
||||
vm.alwaysOpen = alwaysOpen;
|
||||
it(`is ${isCollapsible}, if the report ${issues} and ${open}`, () => {
|
||||
createComponent({ props: { hasIssues, alwaysOpen } });
|
||||
|
||||
await nextTick();
|
||||
expect(vm.isCollapsible).toBe(isCollapsible);
|
||||
expect(wrapper.vm.isCollapsible).toBe(isCollapsible);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -95,12 +82,10 @@ describe('Report section', () => {
|
|||
const issues = isCollapsed ? 'is collapsed' : 'is not collapsed';
|
||||
const open = alwaysOpen ? 'is always open' : 'is not always open';
|
||||
|
||||
it(`is ${isExpanded}, if the report ${issues} and ${open}`, async () => {
|
||||
vm.isCollapsed = isCollapsed;
|
||||
vm.alwaysOpen = alwaysOpen;
|
||||
it(`is ${isExpanded}, if the report ${issues} and ${open}`, () => {
|
||||
createComponent({ props: { alwaysOpen }, data: { isCollapsed } });
|
||||
|
||||
await nextTick();
|
||||
expect(vm.isExpanded).toBe(isExpanded);
|
||||
expect(wrapper.vm.isExpanded).toBe(isExpanded);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -108,110 +93,105 @@ describe('Report section', () => {
|
|||
|
||||
describe('when it is loading', () => {
|
||||
it('should render loading indicator', () => {
|
||||
vm = mountComponent(ReportSection, {
|
||||
component: '',
|
||||
status: 'LOADING',
|
||||
loadingText: 'Loading Code Quality report',
|
||||
errorText: 'foo',
|
||||
successText: 'Code quality improved on 1 point and degraded on 1 point',
|
||||
hasIssues: false,
|
||||
createComponent({
|
||||
props: {
|
||||
component: '',
|
||||
status: 'LOADING',
|
||||
loadingText: 'Loading Code Quality report',
|
||||
errorText: 'foo',
|
||||
successText: 'Code quality improved on 1 point and degraded on 1 point',
|
||||
hasIssues: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(vm.$el.textContent.trim()).toEqual('Loading Code Quality report');
|
||||
expect(wrapper.text()).toBe('Loading Code Quality report');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with success status', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(ReportSection, {
|
||||
...defaultProps,
|
||||
hasIssues: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should render provided data', () => {
|
||||
expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
|
||||
createComponent({ props: { hasIssues: true } });
|
||||
|
||||
expect(wrapper.find('.js-code-text').text()).toBe(
|
||||
'Code quality improved on 1 point and degraded on 1 point',
|
||||
);
|
||||
|
||||
expect(vm.$el.querySelectorAll('.report-block-container li').length).toEqual(
|
||||
resolvedIssues.length,
|
||||
);
|
||||
expect(wrapper.findAllComponents(ReportItem)).toHaveLength(resolvedIssues.length);
|
||||
});
|
||||
|
||||
describe('toggleCollapsed', () => {
|
||||
const hiddenCss = { display: 'none' };
|
||||
|
||||
it('toggles issues', async () => {
|
||||
vm.$el.querySelector('button').click();
|
||||
createComponent({ props: { hasIssues: true } });
|
||||
|
||||
await nextTick();
|
||||
expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss);
|
||||
expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Collapse');
|
||||
await findButton().trigger('click');
|
||||
|
||||
vm.$el.querySelector('button').click();
|
||||
expect(findReportSection().isVisible()).toBe(true);
|
||||
expect(findButton().text()).toBe('Collapse');
|
||||
|
||||
await nextTick();
|
||||
expect(vm.$el.querySelector('.js-report-section-container')).toHaveCss(hiddenCss);
|
||||
expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Expand');
|
||||
await findButton().trigger('click');
|
||||
|
||||
expect(findReportSection().isVisible()).toBe(false);
|
||||
expect(findButton().text()).toBe('Expand');
|
||||
});
|
||||
|
||||
it('is always expanded, if always-open is set to true', async () => {
|
||||
vm.alwaysOpen = true;
|
||||
await nextTick();
|
||||
expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss);
|
||||
expect(vm.$el.querySelector('button')).toBeNull();
|
||||
it('is always expanded, if always-open is set to true', () => {
|
||||
createComponent({ props: { hasIssues: true, alwaysOpen: true } });
|
||||
|
||||
expect(findReportSection().isVisible()).toBe(true);
|
||||
expect(findButton().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('snowplow events', () => {
|
||||
it('does emit an event on issue toggle if the shouldEmitToggleEvent prop does exist', async () => {
|
||||
createComponent({ hasIssues: true, shouldEmitToggleEvent: true });
|
||||
it('does emit an event on issue toggle if the shouldEmitToggleEvent prop does exist', () => {
|
||||
createComponent({ props: { hasIssues: true, shouldEmitToggleEvent: true } });
|
||||
|
||||
expect(wrapper.emitted().toggleEvent).toBeUndefined();
|
||||
expect(wrapper.emitted('toggleEvent')).toBeUndefined();
|
||||
|
||||
findCollapseButton().trigger('click');
|
||||
await nextTick();
|
||||
expect(wrapper.emitted().toggleEvent).toHaveLength(1);
|
||||
findButton().trigger('click');
|
||||
|
||||
expect(wrapper.emitted('toggleEvent')).toEqual([[]]);
|
||||
});
|
||||
|
||||
it('does not emit an event on issue toggle if the shouldEmitToggleEvent prop does not exist', async () => {
|
||||
createComponent({ hasIssues: true });
|
||||
it('does not emit an event on issue toggle if the shouldEmitToggleEvent prop does not exist', () => {
|
||||
createComponent({ props: { hasIssues: true } });
|
||||
|
||||
expect(wrapper.emitted().toggleEvent).toBeUndefined();
|
||||
expect(wrapper.emitted('toggleEvent')).toBeUndefined();
|
||||
|
||||
findCollapseButton().trigger('click');
|
||||
await nextTick();
|
||||
expect(wrapper.emitted().toggleEvent).toBeUndefined();
|
||||
findButton().trigger('click');
|
||||
|
||||
expect(wrapper.emitted('toggleEvent')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not emit an event if always-open is set to true', async () => {
|
||||
createComponent({ alwaysOpen: true, hasIssues: true, shouldEmitToggleEvent: true });
|
||||
it('does not emit an event if always-open is set to true', () => {
|
||||
createComponent({
|
||||
props: { alwaysOpen: true, hasIssues: true, shouldEmitToggleEvent: true },
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.emitted().toggleEvent).toBeUndefined();
|
||||
expect(wrapper.emitted('toggleEvent')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with failed request', () => {
|
||||
it('should render error indicator', () => {
|
||||
vm = mountComponent(ReportSection, {
|
||||
component: '',
|
||||
status: 'ERROR',
|
||||
loadingText: 'Loading Code Quality report',
|
||||
errorText: 'Failed to load Code Quality report',
|
||||
successText: 'Code quality improved on 1 point and degraded on 1 point',
|
||||
hasIssues: false,
|
||||
createComponent({
|
||||
props: {
|
||||
component: '',
|
||||
status: 'ERROR',
|
||||
loadingText: 'Loading Code Quality report',
|
||||
errorText: 'Failed to load Code Quality report',
|
||||
successText: 'Code quality improved on 1 point and degraded on 1 point',
|
||||
hasIssues: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(vm.$el.textContent.trim()).toEqual('Failed to load Code Quality report');
|
||||
expect(wrapper.text()).toBe('Failed to load Code Quality report');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with action buttons passed to the slot', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponentWithSlots(ReportSection, {
|
||||
createComponent({
|
||||
props: {
|
||||
status: 'SUCCESS',
|
||||
successText: 'success',
|
||||
|
@ -224,17 +204,17 @@ describe('Report section', () => {
|
|||
});
|
||||
|
||||
it('should render the passed button', () => {
|
||||
expect(vm.$el.textContent.trim()).toContain('Action!');
|
||||
expect(wrapper.text()).toContain('Action!');
|
||||
});
|
||||
|
||||
it('should still render the expand/collapse button', () => {
|
||||
expect(vm.$el.querySelector('.js-collapse-btn').textContent.trim()).toEqual('Expand');
|
||||
expect(findButton().text()).toBe('Expand');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Success and Error slots', () => {
|
||||
const createComponentWithSlots = (status) => {
|
||||
vm = mountComponentWithSlots(ReportSection, {
|
||||
createComponent({
|
||||
props: {
|
||||
status,
|
||||
hasIssues: true,
|
||||
|
@ -250,25 +230,25 @@ describe('Report section', () => {
|
|||
it('only renders success slot when status is "SUCCESS"', () => {
|
||||
createComponentWithSlots('SUCCESS');
|
||||
|
||||
expect(vm.$el.textContent.trim()).toContain('This is a success');
|
||||
expect(vm.$el.textContent.trim()).not.toContain('This is an error');
|
||||
expect(vm.$el.textContent.trim()).not.toContain('This is loading');
|
||||
expect(wrapper.text()).toContain('This is a success');
|
||||
expect(wrapper.text()).not.toContain('This is an error');
|
||||
expect(wrapper.text()).not.toContain('This is loading');
|
||||
});
|
||||
|
||||
it('only renders error slot when status is "ERROR"', () => {
|
||||
createComponentWithSlots('ERROR');
|
||||
|
||||
expect(vm.$el.textContent.trim()).toContain('This is an error');
|
||||
expect(vm.$el.textContent.trim()).not.toContain('This is a success');
|
||||
expect(vm.$el.textContent.trim()).not.toContain('This is loading');
|
||||
expect(wrapper.text()).toContain('This is an error');
|
||||
expect(wrapper.text()).not.toContain('This is a success');
|
||||
expect(wrapper.text()).not.toContain('This is loading');
|
||||
});
|
||||
|
||||
it('only renders loading slot when status is "LOADING"', () => {
|
||||
createComponentWithSlots('LOADING');
|
||||
|
||||
expect(vm.$el.textContent.trim()).toContain('This is loading');
|
||||
expect(vm.$el.textContent.trim()).not.toContain('This is an error');
|
||||
expect(vm.$el.textContent.trim()).not.toContain('This is a success');
|
||||
expect(wrapper.text()).toContain('This is loading');
|
||||
expect(wrapper.text()).not.toContain('This is an error');
|
||||
expect(wrapper.text()).not.toContain('This is a success');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -280,9 +260,7 @@ describe('Report section', () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
popoverOptions: options,
|
||||
});
|
||||
createComponent({ props: { popoverOptions: options } });
|
||||
});
|
||||
|
||||
it('popover is shown with options', () => {
|
||||
|
@ -292,7 +270,7 @@ describe('Report section', () => {
|
|||
|
||||
describe('when popover options are not defined', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ popoverOptions: {} });
|
||||
createComponent({ props: { popoverOptions: {} } });
|
||||
});
|
||||
|
||||
it('popover is not shown', () => {
|
||||
|
|
|
@ -229,6 +229,12 @@ describe('Blob content viewer component', () => {
|
|||
expect(LineHighlighter).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not load the LineHighlighter for RichViewers', async () => {
|
||||
mockAxios.onGet(legacyViewerUrl).replyOnce(httpStatusCodes.OK, 'test');
|
||||
await createComponent({ blob: { ...richViewerMock, fileType, highlightJs } });
|
||||
expect(LineHighlighter).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('scrolls to the hash', async () => {
|
||||
mockAxios.onGet(legacyViewerUrl).replyOnce(httpStatusCodes.OK, 'test');
|
||||
await createComponent({ blob: { ...simpleViewerMock, fileType, highlightJs } });
|
||||
|
|
|
@ -1,80 +1,71 @@
|
|||
import Vue from 'vue';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
|
||||
|
||||
import { mountComponentWithSlots } from 'helpers/vue_mount_component_helper';
|
||||
import dropdownButtonComponent from '~/vue_shared/components/dropdown/dropdown_button.vue';
|
||||
describe('DropdownButton component', () => {
|
||||
let wrapper;
|
||||
|
||||
const defaultLabel = 'Select';
|
||||
const customLabel = 'Select project';
|
||||
const defaultLabel = 'Select';
|
||||
const customLabel = 'Select project';
|
||||
|
||||
const createComponent = (props, slots = {}) => {
|
||||
const Component = Vue.extend(dropdownButtonComponent);
|
||||
|
||||
return mountComponentWithSlots(Component, { props, slots });
|
||||
};
|
||||
|
||||
describe('DropdownButtonComponent', () => {
|
||||
let vm;
|
||||
|
||||
beforeEach(() => {
|
||||
vm = createComponent();
|
||||
});
|
||||
const createComponent = (props, slots = {}) => {
|
||||
wrapper = mount(DropdownButton, { propsData: props, slots });
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('computed', () => {
|
||||
describe('dropdownToggleText', () => {
|
||||
it('returns default toggle text', () => {
|
||||
expect(vm.toggleText).toBe(defaultLabel);
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.vm.toggleText).toBe(defaultLabel);
|
||||
});
|
||||
|
||||
it('returns custom toggle text when provided via props', () => {
|
||||
const vmEmptyLabels = createComponent({ toggleText: customLabel });
|
||||
createComponent({ toggleText: customLabel });
|
||||
|
||||
expect(vmEmptyLabels.toggleText).toBe(customLabel);
|
||||
vmEmptyLabels.$destroy();
|
||||
expect(wrapper.vm.toggleText).toBe(customLabel);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('template', () => {
|
||||
it('renders component container element of type `button`', () => {
|
||||
expect(vm.$el.nodeName).toBe('BUTTON');
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.element.nodeName).toBe('BUTTON');
|
||||
});
|
||||
|
||||
it('renders component container element with required data attributes', () => {
|
||||
expect(vm.$el.dataset.abilityName).toBe(vm.abilityName);
|
||||
expect(vm.$el.dataset.fieldName).toBe(vm.fieldName);
|
||||
expect(vm.$el.dataset.issueUpdate).toBe(vm.updatePath);
|
||||
expect(vm.$el.dataset.labels).toBe(vm.labelsPath);
|
||||
expect(vm.$el.dataset.namespacePath).toBe(vm.namespace);
|
||||
expect(vm.$el.dataset.showAny).not.toBeDefined();
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.element.dataset.abilityName).toBe(wrapper.vm.abilityName);
|
||||
expect(wrapper.element.dataset.fieldName).toBe(wrapper.vm.fieldName);
|
||||
expect(wrapper.element.dataset.issueUpdate).toBe(wrapper.vm.updatePath);
|
||||
expect(wrapper.element.dataset.labels).toBe(wrapper.vm.labelsPath);
|
||||
expect(wrapper.element.dataset.namespacePath).toBe(wrapper.vm.namespace);
|
||||
expect(wrapper.element.dataset.showAny).toBeUndefined();
|
||||
});
|
||||
|
||||
it('renders dropdown toggle text element', () => {
|
||||
const dropdownToggleTextEl = vm.$el.querySelector('.dropdown-toggle-text');
|
||||
createComponent();
|
||||
|
||||
expect(dropdownToggleTextEl).not.toBeNull();
|
||||
expect(dropdownToggleTextEl.innerText.trim()).toBe(defaultLabel);
|
||||
expect(wrapper.find('.dropdown-toggle-text').text()).toBe(defaultLabel);
|
||||
});
|
||||
|
||||
it('renders dropdown button icon', () => {
|
||||
const dropdownIconEl = vm.$el.querySelector('[data-testid="chevron-down-icon"]');
|
||||
createComponent();
|
||||
|
||||
expect(dropdownIconEl).not.toBeNull();
|
||||
expect(wrapper.find('[data-testid="chevron-down-icon"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders slot, if default slot exists', () => {
|
||||
vm = createComponent(
|
||||
{},
|
||||
{
|
||||
default: ['Lorem Ipsum Dolar'],
|
||||
},
|
||||
);
|
||||
createComponent({}, { default: ['Lorem Ipsum Dolar'] });
|
||||
|
||||
expect(vm.$el.querySelector('.dropdown-toggle-text')).toBeNull();
|
||||
expect(vm.$el).toHaveText('Lorem Ipsum Dolar');
|
||||
expect(wrapper.find('.dropdown-toggle-text').exists()).toBe(false);
|
||||
expect(wrapper.text()).toBe('Lorem Ipsum Dolar');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,8 +5,8 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
describe '#check_runner_upgrade_status' do
|
||||
subject(:result) { described_class.instance.check_runner_upgrade_status(runner_version) }
|
||||
describe '#check_runner_upgrade_suggestion' do
|
||||
subject(:result) { described_class.instance.check_runner_upgrade_suggestion(runner_version) }
|
||||
|
||||
let(:gitlab_version) { '14.1.1' }
|
||||
let(:parsed_runner_version) { ::Gitlab::VersionInfo.parse(runner_version, parse_suffix: true) }
|
||||
|
@ -26,7 +26,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
end
|
||||
|
||||
it 'returns :error' do
|
||||
is_expected.to eq({ error: parsed_runner_version })
|
||||
is_expected.to eq([parsed_runner_version, :error])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -53,7 +53,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
let(:runner_version) { 'v14.0.1' }
|
||||
|
||||
it 'returns :not_available' do
|
||||
is_expected.to eq({ not_available: parsed_runner_version })
|
||||
is_expected.to eq([parsed_runner_version, :not_available])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -68,7 +68,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
let(:runner_version) { nil }
|
||||
|
||||
it 'returns :invalid_version' do
|
||||
is_expected.to match({ invalid_version: anything })
|
||||
is_expected.to match([anything, :invalid_version])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -76,7 +76,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
let(:runner_version) { 'junk' }
|
||||
|
||||
it 'returns :invalid_version' do
|
||||
is_expected.to match({ invalid_version: anything })
|
||||
is_expected.to match([anything, :invalid_version])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -87,7 +87,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
let(:runner_version) { 'v14.2.0' }
|
||||
|
||||
it 'returns :not_available' do
|
||||
is_expected.to eq({ not_available: parsed_runner_version })
|
||||
is_expected.to eq([parsed_runner_version, :not_available])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -96,7 +96,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
let(:gitlab_version) { '14.0.1' }
|
||||
|
||||
context 'with valid params' do
|
||||
where(:runner_version, :expected_result, :expected_suggested_version) do
|
||||
where(:runner_version, :expected_status, :expected_suggested_version) do
|
||||
'v15.0.0' | :not_available | '15.0.0' # not available since the GitLab instance is still on 14.x, a major version might be incompatible, and a patch upgrade is not available
|
||||
'v14.1.0-rc3' | :recommended | '14.1.1' # recommended since even though the GitLab instance is still on 14.0.x, there is a patch release (14.1.1) available which might contain security fixes
|
||||
'v14.1.0~beta.1574.gf6ea9389' | :recommended | '14.1.1' # suffixes are correctly handled
|
||||
|
@ -116,7 +116,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
end
|
||||
|
||||
with_them do
|
||||
it { is_expected.to eq({ expected_result => Gitlab::VersionInfo.parse(expected_suggested_version) }) }
|
||||
it { is_expected.to eq([Gitlab::VersionInfo.parse(expected_suggested_version), expected_status]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -125,7 +125,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
let(:gitlab_version) { '13.9.0' }
|
||||
|
||||
context 'with valid params' do
|
||||
where(:runner_version, :expected_result, :expected_suggested_version) do
|
||||
where(:runner_version, :expected_status, :expected_suggested_version) do
|
||||
'v14.0.0' | :recommended | '14.0.2' # recommended upgrade since 14.0.2 is available, even though the GitLab instance is still on 13.x and a major version might be incompatible
|
||||
'v13.10.1' | :not_available | '13.10.1' # not available since 13.10.1 is already ahead of GitLab instance version and is the latest patch update for 13.10.x
|
||||
'v13.10.0' | :recommended | '13.10.1' # recommended upgrade since 13.10.1 is available
|
||||
|
@ -136,7 +136,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
end
|
||||
|
||||
with_them do
|
||||
it { is_expected.to eq({ expected_result => Gitlab::VersionInfo.parse(expected_suggested_version) }) }
|
||||
it { is_expected.to eq([Gitlab::VersionInfo.parse(expected_suggested_version), expected_status]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -152,7 +152,7 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
|
|||
let(:runner_version) { '14.11.0~beta.29.gd0c550e3' }
|
||||
|
||||
it 'recommends 15.1.0 since 14.11 is an unknown release and 15.1.0 is available' do
|
||||
is_expected.to eq({ recommended: Gitlab::VersionInfo.new(15, 1, 0) })
|
||||
is_expected.to eq([Gitlab::VersionInfo.new(15, 1, 0), :recommended])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -124,6 +124,7 @@ RSpec.describe Participable do
|
|||
end
|
||||
|
||||
let(:readable) { true }
|
||||
let(:project) { build(:project, :public) }
|
||||
|
||||
it 'returns the list of participants' do
|
||||
model.participant(:foo)
|
||||
|
@ -132,7 +133,6 @@ RSpec.describe Participable do
|
|||
user1 = build(:user)
|
||||
user2 = build(:user)
|
||||
user3 = build(:user)
|
||||
project = build(:project, :public)
|
||||
instance = model.new
|
||||
|
||||
allow(instance).to receive_message_chain(:model_name, :element) { 'class' }
|
||||
|
@ -155,7 +155,6 @@ RSpec.describe Participable do
|
|||
instance = model.new
|
||||
user1 = build(:user)
|
||||
user2 = build(:user)
|
||||
project = build(:project, :public)
|
||||
|
||||
allow(instance).to receive_message_chain(:model_name, :element) { 'class' }
|
||||
allow(instance).to receive(:bar).and_return(user2)
|
||||
|
@ -164,6 +163,29 @@ RSpec.describe Participable do
|
|||
expect(instance.visible_participants(user1)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple system notes from the same author and mentioned_users' do
|
||||
let!(:user1) { create(:user) }
|
||||
let!(:user2) { create(:user) }
|
||||
|
||||
it 'skips expensive checks if the author is aleady in participants list' do
|
||||
model.participant(:notes)
|
||||
|
||||
instance = model.new
|
||||
note1 = create(:system_note, author: user1)
|
||||
note2 = create(:system_note, author: user1) # only skip system notes with no mentioned users
|
||||
note3 = create(:system_note, author: user1, note: "assigned to #{user2.to_reference}")
|
||||
note4 = create(:note, author: user2)
|
||||
|
||||
allow(instance).to receive(:project).and_return(project)
|
||||
allow(instance).to receive_message_chain(:model_name, :element) { 'class' }
|
||||
allow(instance).to receive(:notes).and_return([note1, note2, note3, note4])
|
||||
|
||||
allow(Ability).to receive(:allowed?).with(anything, :read_project, anything).and_return(true)
|
||||
allow(Ability).to receive(:allowed?).with(anything, :read_note, anything).exactly(3).times.and_return(true)
|
||||
expect(instance.visible_participants(user1)).to match_array [user1, user2]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#participant?' do
|
||||
|
|
|
@ -37,7 +37,7 @@ RSpec.describe 'Query.runners' do
|
|||
end
|
||||
|
||||
before do
|
||||
allow(Gitlab::Ci::RunnerUpgradeCheck.instance).to receive(:check_runner_upgrade_status)
|
||||
allow(Gitlab::Ci::RunnerUpgradeCheck.instance).to receive(:check_runner_upgrade_suggestion)
|
||||
|
||||
post_graphql(query, current_user: current_user)
|
||||
end
|
||||
|
|
|
@ -15,8 +15,8 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
|
|||
stub_const('Ci::Runners::ReconcileExistingRunnerVersionsService::VERSION_BATCH_SIZE', 1)
|
||||
|
||||
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
|
||||
.to receive(:check_runner_upgrade_status)
|
||||
.and_return({ recommended: ::Gitlab::VersionInfo.new(14, 0, 2) })
|
||||
.to receive(:check_runner_upgrade_suggestion)
|
||||
.and_return([::Gitlab::VersionInfo.new(14, 0, 2), :recommended])
|
||||
end
|
||||
|
||||
context 'with runner with new version' do
|
||||
|
@ -26,9 +26,9 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
|
|||
|
||||
before do
|
||||
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
|
||||
.to receive(:check_runner_upgrade_status)
|
||||
.to receive(:check_runner_upgrade_suggestion)
|
||||
.with('14.0.2')
|
||||
.and_return({ not_available: ::Gitlab::VersionInfo.new(14, 0, 2) })
|
||||
.and_return([::Gitlab::VersionInfo.new(14, 0, 2), :not_available])
|
||||
.once
|
||||
end
|
||||
|
||||
|
@ -59,8 +59,8 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
|
|||
|
||||
before do
|
||||
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
|
||||
.to receive(:check_runner_upgrade_status)
|
||||
.and_return({ not_available: ::Gitlab::VersionInfo.new(14, 0, 2) })
|
||||
.to receive(:check_runner_upgrade_suggestion)
|
||||
.and_return([::Gitlab::VersionInfo.new(14, 0, 2), :not_available])
|
||||
end
|
||||
|
||||
it 'deletes orphan ci_runner_versions entry', :aggregate_failures do
|
||||
|
@ -81,8 +81,8 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
|
|||
context 'with no runner version changes' do
|
||||
before do
|
||||
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
|
||||
.to receive(:check_runner_upgrade_status)
|
||||
.and_return({ not_available: ::Gitlab::VersionInfo.new(14, 0, 1) })
|
||||
.to receive(:check_runner_upgrade_suggestion)
|
||||
.and_return([::Gitlab::VersionInfo.new(14, 0, 1), :not_available])
|
||||
end
|
||||
|
||||
it 'does not modify ci_runner_versions entries', :aggregate_failures do
|
||||
|
@ -101,8 +101,8 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
|
|||
context 'with failing version check' do
|
||||
before do
|
||||
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
|
||||
.to receive(:check_runner_upgrade_status)
|
||||
.and_return({ error: ::Gitlab::VersionInfo.new(14, 0, 1) })
|
||||
.to receive(:check_runner_upgrade_suggestion)
|
||||
.and_return([::Gitlab::VersionInfo.new(14, 0, 1), :error])
|
||||
end
|
||||
|
||||
it 'makes no changes to ci_runner_versions', :aggregate_failures do
|
||||
|
|
Loading…
Reference in New Issue