Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/autosave.js16
-rw-r--r--app/assets/javascripts/clusters/components/crossplane_provider_stack.vue10
-rw-r--r--app/assets/javascripts/issuable_form.js54
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js32
-rw-r--r--app/assets/javascripts/monitoring/components/graph_group.vue3
-rw-r--r--app/assets/javascripts/pages/projects/project.js24
-rw-r--r--app/models/diff_note.rb6
-rw-r--r--app/models/discussion.rb4
-rw-r--r--app/models/note.rb4
-rw-r--r--app/services/issuable/common_system_notes_service.rb26
-rw-r--r--app/services/issuable_base_service.rb14
-rw-r--r--app/services/notes/base_service.rb2
-rw-r--r--app/views/notify/_note_email.html.haml2
-rw-r--r--app/views/notify/_note_email.text.erb2
-rw-r--r--changelogs/unreleased/30016-changing-branch-keep-details.yml5
-rw-r--r--changelogs/unreleased/34734-monitor-dashboard-does-not-expand-sections-that-have-data-on-load.yml5
-rw-r--r--changelogs/unreleased/36450-update-the-saas-trial-copy-to-be-dynamic-depending-on-the-trial-typ.yml5
-rw-r--r--changelogs/unreleased/36455-add-external-link-icon.yml5
-rw-r--r--changelogs/unreleased/3695-view-closed-issues-in-epic.yml5
-rw-r--r--locale/gitlab.pot9
-rwxr-xr-xscripts/review_apps/automated_cleanup.rb14
-rw-r--r--spec/frontend/autosave_spec.js37
-rw-r--r--spec/frontend/clusters/services/crossplane_provider_stack_spec.js9
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js16
-rw-r--r--spec/frontend/notes/components/note_edited_text_spec.js62
-rw-r--r--spec/frontend/registry/components/app_spec.js4
-rw-r--r--spec/frontend/registry/components/collapsible_container_spec.js20
-rw-r--r--spec/frontend/registry/components/project_empty_state_spec.js2
-rw-r--r--spec/frontend/registry/components/table_registry_spec.js5
-rw-r--r--spec/javascripts/line_highlighter_spec.js41
-rw-r--r--spec/javascripts/monitoring/components/graph_group_spec.js30
-rw-r--r--spec/lib/gitlab/git/attributes_at_ref_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/git/attributes_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/git/blame_spec.rb2
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb2
-rw-r--r--spec/lib/gitlab/git/branch_spec.rb6
-rw-r--r--spec/lib/gitlab/git/bundle_file_spec.rb2
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb8
-rw-r--r--spec/lib/gitlab/git/compare_spec.rb2
-rw-r--r--spec/lib/gitlab/git/conflict/file_spec.rb6
-rw-r--r--spec/lib/gitlab/git/conflict/parser_spec.rb4
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb2
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb2
-rw-r--r--spec/lib/gitlab/git/gitmodules_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/git/hook_env_spec.rb2
-rw-r--r--spec/lib/gitlab/git/lfs_changes_spec.rb2
-rw-r--r--spec/lib/gitlab/git/lfs_pointer_file_spec.rb2
-rw-r--r--spec/lib/gitlab/git/pre_receive_error_spec.rb2
-rw-r--r--spec/lib/gitlab/git/push_spec.rb2
-rw-r--r--spec/lib/gitlab/git/raw_diff_change_spec.rb2
-rw-r--r--spec/lib/gitlab/git/remote_mirror_spec.rb2
-rw-r--r--spec/lib/gitlab/git/remote_repository_spec.rb2
-rw-r--r--spec/lib/gitlab/git/repository_cleaner_spec.rb2
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb2
-rw-r--r--spec/lib/gitlab/git/tag_spec.rb2
-rw-r--r--spec/lib/gitlab/git/tree_spec.rb2
-rw-r--r--spec/lib/gitlab/git/user_spec.rb2
-rw-r--r--spec/lib/gitlab/git/util_spec.rb2
-rw-r--r--spec/lib/gitlab/git/wiki_spec.rb2
-rw-r--r--spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb2
-rw-r--r--spec/lib/gitlab/gpg/commit_spec.rb2
-rw-r--r--spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb2
-rw-r--r--spec/mailers/notify_spec.rb24
-rw-r--r--spec/models/note_spec.rb13
64 files changed, 430 insertions, 158 deletions
diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js
index 7652b67ae1e..07d79ea1c70 100644
--- a/app/assets/javascripts/autosave.js
+++ b/app/assets/javascripts/autosave.js
@@ -1,9 +1,9 @@
-/* eslint-disable no-param-reassign, no-void, consistent-return */
+/* eslint-disable no-param-reassign, consistent-return */
import AccessorUtilities from './lib/utils/accessor';
export default class Autosave {
- constructor(field, key) {
+ constructor(field, key, fallbackKey) {
this.field = field;
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
@@ -11,6 +11,7 @@ export default class Autosave {
key = key.join('/');
}
this.key = `autosave/${key}`;
+ this.fallbackKey = fallbackKey;
this.field.data('autosave', this);
this.restore();
this.field.on('input', () => this.save());
@@ -21,9 +22,12 @@ export default class Autosave {
if (!this.field.length) return;
const text = window.localStorage.getItem(this.key);
+ const fallbackText = window.localStorage.getItem(this.fallbackKey);
- if ((text != null ? text.length : void 0) > 0) {
+ if (text) {
this.field.val(text);
+ } else if (fallbackText) {
+ this.field.val(fallbackText);
}
this.field.trigger('input');
@@ -41,7 +45,10 @@ export default class Autosave {
const text = this.field.val();
- if (this.isLocalStorageAvailable && (text != null ? text.length : void 0) > 0) {
+ if (this.isLocalStorageAvailable && text) {
+ if (this.fallbackKey) {
+ window.localStorage.setItem(this.fallbackKey, text);
+ }
return window.localStorage.setItem(this.key, text);
}
@@ -51,6 +58,7 @@ export default class Autosave {
reset() {
if (!this.isLocalStorageAvailable) return;
+ window.localStorage.removeItem(this.fallbackKey);
return window.localStorage.removeItem(this.key);
}
diff --git a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
index 966918ae636..6b99bb09504 100644
--- a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
+++ b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
@@ -1,6 +1,5 @@
<script>
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import Icon from '~/vue_shared/components/icon.vue';
+import { GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui';
import { s__ } from '../../locale';
export default {
@@ -8,7 +7,7 @@ export default {
components: {
GlDropdown,
GlDropdownItem,
- Icon,
+ GlIcon,
},
props: {
stacks: {
@@ -86,8 +85,9 @@ export default {
href="https://crossplane.io/docs/master/stacks-guide.html"
target="_blank"
rel="noopener noreferrer"
- >{{ __('Crossplane') }}</a
- >
+ >{{ __('Crossplane') }}
+ <gl-icon name="external-link" class="vertical-align-middle" />
+ </a>
</p>
</div>
</template>
diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js
index 7576d36f27d..1d0807dc15d 100644
--- a/app/assets/javascripts/issuable_form.js
+++ b/app/assets/javascripts/issuable_form.js
@@ -6,6 +6,36 @@ import UsersSelect from './users_select';
import ZenMode from './zen_mode';
import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
+import { queryToObject, objectToQuery } from './lib/utils/url_utility';
+
+function organizeQuery(obj, isFallbackKey = false) {
+ const sourceBranch = 'merge_request[source_branch]';
+ const targetBranch = 'merge_request[target_branch]';
+
+ if (isFallbackKey) {
+ return {
+ [sourceBranch]: obj[sourceBranch],
+ };
+ }
+
+ return {
+ [sourceBranch]: obj[sourceBranch],
+ [targetBranch]: obj[targetBranch],
+ };
+}
+
+function format(searchTerm, isFallbackKey = false) {
+ const queryObject = queryToObject(searchTerm);
+ const organizeQueryObject = organizeQuery(queryObject, isFallbackKey);
+ const formattedQuery = objectToQuery(organizeQueryObject);
+
+ return formattedQuery;
+}
+
+function getFallbackKey() {
+ const searchTerm = format(document.location.search, true);
+ return ['autosave', document.location.pathname, searchTerm].join('/');
+}
export default class IssuableForm {
constructor(form) {
@@ -57,16 +87,20 @@ export default class IssuableForm {
}
initAutosave() {
- this.autosave = new Autosave(this.titleField, [
- document.location.pathname,
- document.location.search,
- 'title',
- ]);
- return new Autosave(this.descriptionField, [
- document.location.pathname,
- document.location.search,
- 'description',
- ]);
+ const searchTerm = format(document.location.search);
+ const fallbackKey = getFallbackKey();
+
+ this.autosave = new Autosave(
+ this.titleField,
+ [document.location.pathname, searchTerm, 'title'],
+ `${fallbackKey}=title`,
+ );
+
+ return new Autosave(
+ this.descriptionField,
+ [document.location.pathname, searchTerm, 'description'],
+ `${fallbackKey}=description`,
+ );
}
handleSubmit() {
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 4be0d05a9b7..202a44d5694 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -181,4 +181,36 @@ export function getWebSocketUrl(path) {
return `${getWebSocketProtocol()}//${joinPaths(window.location.host, path)}`;
}
+/**
+ * Convert search query into an object
+ *
+ * @param {String} query from "document.location.search"
+ * @returns {Object}
+ *
+ * ex: "?one=1&two=2" into {one: 1, two: 2}
+ */
+export function queryToObject(query) {
+ const removeQuestionMarkFromQuery = String(query).startsWith('?') ? query.slice(1) : query;
+ return removeQuestionMarkFromQuery.split('&').reduce((accumulator, curr) => {
+ const p = curr.split('=');
+ accumulator[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ return accumulator;
+ }, {});
+}
+
+/**
+ * Convert search query object back into a search query
+ *
+ * @param {Object} obj that needs to be converted
+ * @returns {String}
+ *
+ * ex: {one: 1, two: 2} into "one=1&two=2"
+ *
+ */
+export function objectToQuery(obj) {
+ return Object.keys(obj)
+ .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`)
+ .join('&');
+}
+
export { joinPaths };
diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue
index 3cb6ccb64b1..e01324372a7 100644
--- a/app/assets/javascripts/monitoring/components/graph_group.vue
+++ b/app/assets/javascripts/monitoring/components/graph_group.vue
@@ -30,9 +30,6 @@ export default {
return this.collapseGroup && this.showGroup ? 'angle-down' : 'angle-right';
},
},
- created() {
- this.showGroup = this.collapseGroup;
- },
methods: {
collapse() {
this.showGroup = !this.showGroup;
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index 01acfca158f..739ae1cea16 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -1,4 +1,4 @@
-/* eslint-disable func-names, no-var, no-return-assign */
+/* eslint-disable func-names, no-return-assign */
import $ from 'jquery';
import Cookies from 'js-cookie';
@@ -90,19 +90,19 @@ export default class Project {
}
static initRefSwitcher() {
- var refListItem = document.createElement('li');
- var refLink = document.createElement('a');
+ const refListItem = document.createElement('li');
+ const refLink = document.createElement('a');
refLink.href = '#';
return $('.js-project-refs-dropdown').each(function() {
- var $dropdown = $(this);
- var selected = $dropdown.data('selected');
- var fieldName = $dropdown.data('fieldName');
- var shouldVisit = Boolean($dropdown.data('visit'));
- var $form = $dropdown.closest('form');
- var action = $form.attr('action');
- var linkTarget = mergeUrlParams(serializeForm($form[0]), action);
+ const $dropdown = $(this);
+ const selected = $dropdown.data('selected');
+ const fieldName = $dropdown.data('fieldName');
+ const shouldVisit = Boolean($dropdown.data('visit'));
+ const $form = $dropdown.closest('form');
+ const action = $form.attr('action');
+ const linkTarget = mergeUrlParams(serializeForm($form[0]), action);
return $dropdown.glDropdown({
data(term, callback) {
@@ -123,9 +123,9 @@ export default class Project {
inputFieldName: $dropdown.data('inputFieldName'),
fieldName,
renderRow(ref) {
- var li = refListItem.cloneNode(false);
+ const li = refListItem.cloneNode(false);
- var link = refLink.cloneNode(false);
+ const link = refLink.cloneNode(false);
if (ref === selected) {
link.className = 'is-active';
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index 65e87bb08a7..0623ba746c2 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -88,10 +88,6 @@ class DiffNote < Note
line&.suggestible?
end
- def discussion_first_note?
- self == discussion.first_note
- end
-
def banzai_render_context(field)
super.merge(suggestions_filter_enabled: true)
end
@@ -108,7 +104,7 @@ class DiffNote < Note
end
def should_create_diff_file?
- on_text? && note_diff_file.nil? && discussion_first_note?
+ on_text? && note_diff_file.nil? && start_of_discussion?
end
def fetch_diff_file
diff --git a/app/models/discussion.rb b/app/models/discussion.rb
index b8525f7b135..d0a7db39a30 100644
--- a/app/models/discussion.rb
+++ b/app/models/discussion.rb
@@ -139,10 +139,6 @@ class Discussion
false
end
- def new_discussion?
- notes.length == 1
- end
-
def last_note
@last_note ||= notes.last
end
diff --git a/app/models/note.rb b/app/models/note.rb
index ce60413b8a0..1996fd4bff5 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -409,6 +409,10 @@ class Note < ApplicationRecord
full_discussion || to_discussion
end
+ def start_of_discussion?
+ discussion.first_note == self
+ end
+
def part_of_discussion?
!to_discussion.individual_note?
end
diff --git a/app/services/issuable/common_system_notes_service.rb b/app/services/issuable/common_system_notes_service.rb
index a170a4dcae2..846b881e819 100644
--- a/app/services/issuable/common_system_notes_service.rb
+++ b/app/services/issuable/common_system_notes_service.rb
@@ -7,20 +7,24 @@ module Issuable
def execute(issuable, old_labels: [], is_update: true)
@issuable = issuable
- if is_update
- if issuable.previous_changes.include?('title')
- create_title_change_note(issuable.previous_changes['title'].first)
+ # We disable touch so that created system notes do not update
+ # the noteable's updated_at field
+ ActiveRecord::Base.no_touching do
+ if is_update
+ if issuable.previous_changes.include?('title')
+ create_title_change_note(issuable.previous_changes['title'].first)
+ end
+
+ handle_description_change_note
+
+ handle_time_tracking_note if issuable.is_a?(TimeTrackable)
+ create_discussion_lock_note if issuable.previous_changes.include?('discussion_locked')
end
- handle_description_change_note
-
- handle_time_tracking_note if issuable.is_a?(TimeTrackable)
- create_discussion_lock_note if issuable.previous_changes.include?('discussion_locked')
+ create_due_date_note if issuable.previous_changes.include?('due_date')
+ create_milestone_note if issuable.previous_changes.include?('milestone_id')
+ create_labels_note(old_labels) if old_labels && issuable.labels != old_labels
end
-
- create_due_date_note if issuable.previous_changes.include?('due_date')
- create_milestone_note if issuable.previous_changes.include?('milestone_id')
- create_labels_note(old_labels) if old_labels && issuable.labels != old_labels
end
private
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 200eca0e43c..bb65a8f402d 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -164,9 +164,7 @@ class IssuableBaseService < BaseService
before_create(issuable)
if issuable.save
- ActiveRecord::Base.no_touching do
- Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, is_update: false)
- end
+ Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, is_update: false)
after_create(issuable)
execute_hooks(issuable)
@@ -227,10 +225,7 @@ class IssuableBaseService < BaseService
ensure_milestone_available(issuable)
if issuable.with_transaction_returning_status { issuable.save(touch: should_touch) }
- # We do not touch as it will affect a update on updated_at field
- ActiveRecord::Base.no_touching do
- Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: old_associations[:labels])
- end
+ Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: old_associations[:labels])
handle_changes(issuable, old_associations: old_associations)
@@ -264,10 +259,7 @@ class IssuableBaseService < BaseService
before_update(issuable, skip_spam_check: true)
if issuable.with_transaction_returning_status { issuable.save }
- # We do not touch as it will affect a update on updated_at field
- ActiveRecord::Base.no_touching do
- Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: nil)
- end
+ Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: nil)
handle_task_changes(issuable)
invalidate_cache_counts(issuable, users: issuable.assignees.to_a)
diff --git a/app/services/notes/base_service.rb b/app/services/notes/base_service.rb
index b4d04c47cc0..87f7cb0e8ac 100644
--- a/app/services/notes/base_service.rb
+++ b/app/services/notes/base_service.rb
@@ -4,7 +4,7 @@ module Notes
class BaseService < ::BaseService
def clear_noteable_diffs_cache(note)
if note.is_a?(DiffNote) &&
- note.discussion_first_note? &&
+ note.start_of_discussion? &&
note.position.unfolded_diff?(project.repository)
note.noteable.diffs.clear_cache
end
diff --git a/app/views/notify/_note_email.html.haml b/app/views/notify/_note_email.html.haml
index dc5529b489b..c558358725c 100644
--- a/app/views/notify/_note_email.html.haml
+++ b/app/views/notify/_note_email.html.haml
@@ -11,7 +11,7 @@
- if discussion.nil?
commented
- else
- - if discussion.new_discussion?
+ - if note.start_of_discussion?
started a new
- else
commented on a
diff --git a/app/views/notify/_note_email.text.erb b/app/views/notify/_note_email.text.erb
index a25daad8458..8e2f7e6f76e 100644
--- a/app/views/notify/_note_email.text.erb
+++ b/app/views/notify/_note_email.text.erb
@@ -7,7 +7,7 @@
<% if discussion.nil? -%>
<%= 'commented' -%>:
<% else -%>
-<% if discussion.new_discussion? -%>
+<% if note.start_of_discussion? -%>
<%= 'started a new discussion' -%>
<% else -%>
<%= 'commented on a discussion' -%>
diff --git a/changelogs/unreleased/30016-changing-branch-keep-details.yml b/changelogs/unreleased/30016-changing-branch-keep-details.yml
new file mode 100644
index 00000000000..05a280575e5
--- /dev/null
+++ b/changelogs/unreleased/30016-changing-branch-keep-details.yml
@@ -0,0 +1,5 @@
+---
+title: Keep details in MR when changing target branch
+merge_request: 19138
+author:
+type: changed
diff --git a/changelogs/unreleased/34734-monitor-dashboard-does-not-expand-sections-that-have-data-on-load.yml b/changelogs/unreleased/34734-monitor-dashboard-does-not-expand-sections-that-have-data-on-load.yml
new file mode 100644
index 00000000000..c6c5df2e698
--- /dev/null
+++ b/changelogs/unreleased/34734-monitor-dashboard-does-not-expand-sections-that-have-data-on-load.yml
@@ -0,0 +1,5 @@
+---
+title: Fix graph groups in monitor dashboard that are hidden on load
+merge_request: 20312
+author:
+type: fixed
diff --git a/changelogs/unreleased/36450-update-the-saas-trial-copy-to-be-dynamic-depending-on-the-trial-typ.yml b/changelogs/unreleased/36450-update-the-saas-trial-copy-to-be-dynamic-depending-on-the-trial-typ.yml
new file mode 100644
index 00000000000..e2996ed45b0
--- /dev/null
+++ b/changelogs/unreleased/36450-update-the-saas-trial-copy-to-be-dynamic-depending-on-the-trial-typ.yml
@@ -0,0 +1,5 @@
+---
+title: SaaS trial copy shows plan
+merge_request: 20207
+author:
+type: changed
diff --git a/changelogs/unreleased/36455-add-external-link-icon.yml b/changelogs/unreleased/36455-add-external-link-icon.yml
new file mode 100644
index 00000000000..7bbbb772ce9
--- /dev/null
+++ b/changelogs/unreleased/36455-add-external-link-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Add missing external-link icon for Crossplane managed app
+merge_request: 20283
+author:
+type: fixed
diff --git a/changelogs/unreleased/3695-view-closed-issues-in-epic.yml b/changelogs/unreleased/3695-view-closed-issues-in-epic.yml
new file mode 100644
index 00000000000..a7cddcbc6dc
--- /dev/null
+++ b/changelogs/unreleased/3695-view-closed-issues-in-epic.yml
@@ -0,0 +1,5 @@
+---
+title: View closed issues in epic
+merge_request: 19741
+author:
+type: added
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 4f0e112a49d..ce9bc053b98 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2515,10 +2515,10 @@ msgstr ""
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
msgstr ""
-msgid "BillingPlans|Your GitLab.com Gold trial expired on %{expiration_date}. You can restore access to the Gold features at any time by upgrading below."
+msgid "BillingPlans|Your GitLab.com %{plan} trial will <strong>expire after %{expiration_date}</strong>. You can retain access to the %{plan} features by upgrading below."
msgstr ""
-msgid "BillingPlans|Your GitLab.com Gold trial will <strong>expire after %{expiration_date}</strong>. You can retain access to the Gold features by upgrading below."
+msgid "BillingPlans|Your GitLab.com trial expired on %{expiration_date}. You can restore access to the features at any time by upgrading below."
msgstr ""
msgid "BillingPlans|billed annually at %{price_per_year}"
@@ -5770,7 +5770,7 @@ msgstr ""
msgid "DesignManagement|Could not add a new comment. Please try again"
msgstr ""
-msgid "DesignManagement|Could not create new discussion, please try again."
+msgid "DesignManagement|Could not create new discussion. Please try again."
msgstr ""
msgid "DesignManagement|Could not find design, please try again."
@@ -5821,9 +5821,6 @@ msgstr ""
msgid "DesignManagement|We could not delete %{design}. Please try again."
msgstr ""
-msgid "DesignManagement|We could not delete design(s). Please try again."
-msgstr ""
-
msgid "Designs"
msgstr ""
diff --git a/scripts/review_apps/automated_cleanup.rb b/scripts/review_apps/automated_cleanup.rb
index c7ab8829088..01bf149e76e 100755
--- a/scripts/review_apps/automated_cleanup.rb
+++ b/scripts/review_apps/automated_cleanup.rb
@@ -75,9 +75,11 @@ class AutomatedCleanup
deployed_at = Time.parse(last_deploy)
if deployed_at < delete_threshold
- delete_environment(environment, deployment)
- release = Quality::HelmClient::Release.new(environment.slug, 1, deployed_at.to_s, nil, nil, review_apps_namespace)
- releases_to_delete << release
+ environment = delete_environment(environment, deployment)
+ if environment
+ release = Quality::HelmClient::Release.new(environment.slug, 1, deployed_at.to_s, nil, nil, review_apps_namespace)
+ releases_to_delete << release
+ end
elsif deployed_at < stop_threshold
stop_environment(environment, deployment)
else
@@ -116,11 +118,17 @@ class AutomatedCleanup
def delete_environment(environment, deployment)
print_release_state(subject: 'Review app', release_name: environment.slug, release_date: deployment.created_at, action: 'deleting')
gitlab.delete_environment(project_path, environment.id)
+
+ rescue Gitlab::Error::Forbidden
+ puts "Review app '#{environment.slug}' is forbidden: skipping it"
end
def stop_environment(environment, deployment)
print_release_state(subject: 'Review app', release_name: environment.slug, release_date: deployment.created_at, action: 'stopping')
gitlab.stop_environment(project_path, environment.id)
+
+ rescue Gitlab::Error::Forbidden
+ puts "Review app '#{environment.slug}' is forbidden: skipping it"
end
def helm_releases
diff --git a/spec/frontend/autosave_spec.js b/spec/frontend/autosave_spec.js
index 33d402388c9..1d73e452eb4 100644
--- a/spec/frontend/autosave_spec.js
+++ b/spec/frontend/autosave_spec.js
@@ -9,6 +9,7 @@ describe('Autosave', () => {
let autosave;
const field = $('<textarea></textarea>');
const key = 'key';
+ const fallbackKey = 'fallbackKey';
describe('class constructor', () => {
beforeEach(() => {
@@ -22,6 +23,13 @@ describe('Autosave', () => {
expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
expect(autosave.isLocalStorageAvailable).toBe(true);
});
+
+ it('should set .isLocalStorageAvailable if fallbackKey is passed', () => {
+ autosave = new Autosave(field, key, fallbackKey);
+
+ expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
+ expect(autosave.isLocalStorageAvailable).toBe(true);
+ });
});
describe('restore', () => {
@@ -151,4 +159,33 @@ describe('Autosave', () => {
});
});
});
+
+ describe('restore with fallbackKey', () => {
+ beforeEach(() => {
+ autosave = {
+ field,
+ key,
+ fallbackKey,
+ };
+ autosave.isLocalStorageAvailable = true;
+ });
+
+ it('should call .getItem', () => {
+ Autosave.prototype.restore.call(autosave);
+
+ expect(window.localStorage.getItem).toHaveBeenCalledWith(fallbackKey);
+ });
+
+ it('should call .setItem for key and fallbackKey', () => {
+ Autosave.prototype.save.call(autosave);
+
+ expect(window.localStorage.setItem).toHaveBeenCalledTimes(2);
+ });
+
+ it('should call .removeItem for key and fallbackKey', () => {
+ Autosave.prototype.reset.call(autosave);
+
+ expect(window.localStorage.removeItem).toHaveBeenCalledTimes(2);
+ });
+ });
});
diff --git a/spec/frontend/clusters/services/crossplane_provider_stack_spec.js b/spec/frontend/clusters/services/crossplane_provider_stack_spec.js
index 0d234822d7b..d43dc9333b4 100644
--- a/spec/frontend/clusters/services/crossplane_provider_stack_spec.js
+++ b/spec/frontend/clusters/services/crossplane_provider_stack_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDropdownItem, GlIcon } from '@gitlab/ui';
import CrossplaneProviderStack from '~/clusters/components/crossplane_provider_stack.vue';
describe('CrossplaneProviderStack component', () => {
@@ -72,7 +72,12 @@ describe('CrossplaneProviderStack component', () => {
findFirstDropdownElement().vm.$emit('click');
expect(wrapper.emitted().set[0][0].code).toEqual('gcp');
});
- it('it renders the correct dropdown text when no stack is selected', () => {
+
+ it('renders the correct dropdown text when no stack is selected', () => {
expect(wrapper.vm.dropdownText).toBe('Select Stack');
});
+
+ it('renders an external link', () => {
+ expect(wrapper.find(GlIcon).props('name')).toBe('external-link');
+ });
});
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index 6edb2e2dce2..8244acbceea 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -282,4 +282,20 @@ describe('URL utility', () => {
expect(urlUtils.getWebSocketUrl(path)).toEqual('ws://example.com/lorem/ipsum?a=bc');
});
});
+
+ describe('queryToObject', () => {
+ it('converts search query into an object', () => {
+ const searchQuery = '?one=1&two=2';
+
+ expect(urlUtils.queryToObject(searchQuery)).toEqual({ one: '1', two: '2' });
+ });
+ });
+
+ describe('objectToQuery', () => {
+ it('converts search query object back into a search query', () => {
+ const searchQueryObject = { one: '1', two: '2' };
+
+ expect(urlUtils.objectToQuery(searchQueryObject)).toEqual('one=1&two=2');
+ });
+ });
});
diff --git a/spec/frontend/notes/components/note_edited_text_spec.js b/spec/frontend/notes/components/note_edited_text_spec.js
index e4c8d954d50..e8d5a24e86a 100644
--- a/spec/frontend/notes/components/note_edited_text_spec.js
+++ b/spec/frontend/notes/components/note_edited_text_spec.js
@@ -1,47 +1,49 @@
-import Vue from 'vue';
-import noteEditedText from '~/notes/components/note_edited_text.vue';
-
-describe('note_edited_text', () => {
- let vm;
- let props;
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import NoteEditedText from '~/notes/components/note_edited_text.vue';
+
+const localVue = createLocalVue();
+const propsData = {
+ actionText: 'Edited',
+ className: 'foo-bar',
+ editedAt: '2017-08-04T09:52:31.062Z',
+ editedBy: {
+ avatar_url: 'path',
+ id: 1,
+ name: 'Root',
+ path: '/root',
+ state: 'active',
+ username: 'root',
+ },
+};
+
+describe('NoteEditedText', () => {
+ let wrapper;
beforeEach(() => {
- const Component = Vue.extend(noteEditedText);
- props = {
- actionText: 'Edited',
- className: 'foo-bar',
- editedAt: '2017-08-04T09:52:31.062Z',
- editedBy: {
- avatar_url: 'path',
- id: 1,
- name: 'Root',
- path: '/root',
- state: 'active',
- username: 'root',
- },
- };
-
- vm = new Component({
- propsData: props,
- }).$mount();
+ wrapper = shallowMount(NoteEditedText, {
+ localVue,
+ propsData,
+ sync: false,
+ attachToDocument: true,
+ });
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
it('should render block with provided className', () => {
- expect(vm.$el.className).toEqual(props.className);
+ expect(wrapper.classes()).toContain(propsData.className);
});
it('should render provided actionText', () => {
- expect(vm.$el.textContent).toContain(props.actionText);
+ expect(wrapper.text().trim()).toContain(propsData.actionText);
});
it('should render provided user information', () => {
- const authorLink = vm.$el.querySelector('.js-user-link');
+ const authorLink = wrapper.find('.js-user-link');
- expect(authorLink.getAttribute('href')).toEqual(props.editedBy.path);
- expect(authorLink.textContent.trim()).toEqual(props.editedBy.name);
+ expect(authorLink.attributes('href')).toEqual(propsData.editedBy.path);
+ expect(authorLink.text().trim()).toEqual(propsData.editedBy.name);
});
});
diff --git a/spec/frontend/registry/components/app_spec.js b/spec/frontend/registry/components/app_spec.js
index a69c33c246d..2bb21c12fc9 100644
--- a/spec/frontend/registry/components/app_spec.js
+++ b/spec/frontend/registry/components/app_spec.js
@@ -39,6 +39,8 @@ describe('Registry List', () => {
// See https://github.com/vuejs/vue-test-utils/issues/532.
Vue.config.silent = true;
wrapper = mount(registry, {
+ attachToDocument: true,
+ sync: false,
propsData,
computed: {
repos() {
@@ -67,6 +69,8 @@ describe('Registry List', () => {
let localWrapper;
beforeEach(() => {
localWrapper = mount(registry, {
+ attachToDocument: true,
+ sync: false,
propsData,
computed: {
repos() {
diff --git a/spec/frontend/registry/components/collapsible_container_spec.js b/spec/frontend/registry/components/collapsible_container_spec.js
index d035055afd3..3d07ab63776 100644
--- a/spec/frontend/registry/components/collapsible_container_spec.js
+++ b/spec/frontend/registry/components/collapsible_container_spec.js
@@ -22,7 +22,14 @@ describe('collapsible registry container', () => {
const findToggleRepos = (w = wrapper) => w.findAll('.js-toggle-repo');
const findDeleteModal = (w = wrapper) => w.find({ ref: 'deleteModal' });
- const mountWithStore = config => mount(collapsibleComponent, { ...config, store, localVue });
+ const mountWithStore = config =>
+ mount(collapsibleComponent, {
+ ...config,
+ store,
+ localVue,
+ attachToDocument: true,
+ sync: false,
+ });
beforeEach(() => {
createFlash.mockClear();
@@ -63,12 +70,15 @@ describe('collapsible registry container', () => {
it('should be closed by default', () => {
expectIsClosed();
});
- it('should be open when user clicks on closed repo', () => {
+ it('should be open when user clicks on closed repo', done => {
const toggleRepos = findToggleRepos(wrapper);
toggleRepos.at(0).trigger('click');
- const container = findContainerImageTags(wrapper);
- expect(container.exists()).toBe(true);
- expect(wrapper.vm.fetchList).toHaveBeenCalled();
+ Vue.nextTick(() => {
+ const container = findContainerImageTags(wrapper);
+ expect(container.exists()).toBe(true);
+ expect(wrapper.vm.fetchList).toHaveBeenCalled();
+ done();
+ });
});
it('should be closed when the user clicks on an opened repo', done => {
const toggleRepos = findToggleRepos(wrapper);
diff --git a/spec/frontend/registry/components/project_empty_state_spec.js b/spec/frontend/registry/components/project_empty_state_spec.js
index 913524db3aa..dd0fe32b68c 100644
--- a/spec/frontend/registry/components/project_empty_state_spec.js
+++ b/spec/frontend/registry/components/project_empty_state_spec.js
@@ -6,6 +6,8 @@ describe('Registry Project Empty state', () => {
beforeEach(() => {
wrapper = mount(projectEmptyState, {
+ attachToDocument: true,
+ sync: false,
propsData: {
noContainersImage: 'imageUrl',
helpPagePath: 'help',
diff --git a/spec/frontend/registry/components/table_registry_spec.js b/spec/frontend/registry/components/table_registry_spec.js
index b9075f565e9..4566e6ed705 100644
--- a/spec/frontend/registry/components/table_registry_spec.js
+++ b/spec/frontend/registry/components/table_registry_spec.js
@@ -28,7 +28,8 @@ describe('table registry', () => {
const findImageId = (w = wrapper) => w.find({ ref: 'imageId' });
const bulkDeletePath = 'path';
- const mountWithStore = config => mount(tableRegistry, { ...config, store, localVue });
+ const mountWithStore = config =>
+ mount(tableRegistry, { ...config, store, localVue, attachToDocument: true, sync: false });
beforeEach(() => {
// This is needed due to console.error called by vue to emit a warning that stop the tests
@@ -196,7 +197,7 @@ describe('table registry', () => {
expect(wrapper.vm.handleSingleDelete).toHaveBeenCalledWith(repoPropsData.list[0]);
expect(wrapper.vm.handleMultipleDelete).not.toHaveBeenCalled();
});
- it('on ok when multiple items are selected should call muultiDelete', () => {
+ it('on ok when multiple items are selected should call multiDelete', () => {
wrapper.setData({ itemsToBeDeleted: [0, 1, 2] });
wrapper.vm.onDeletionConfirmed();
diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js
index f8f835ffdef..45b10fc3bd8 100644
--- a/spec/javascripts/line_highlighter_spec.js
+++ b/spec/javascripts/line_highlighter_spec.js
@@ -1,12 +1,11 @@
-/* eslint-disable no-var, no-else-return, dot-notation, no-return-assign, no-new, no-underscore-dangle */
+/* eslint-disable no-else-return, dot-notation, no-return-assign, no-new, no-underscore-dangle */
import $ from 'jquery';
import LineHighlighter from '~/line_highlighter';
describe('LineHighlighter', function() {
- var clickLine;
preloadFixtures('static/line_highlighter.html');
- clickLine = function(number, eventData = {}) {
+ const clickLine = function(number, eventData = {}) {
if ($.isEmptyObject(eventData)) {
return $(`#L${number}`).click();
} else {
@@ -39,34 +38,30 @@ describe('LineHighlighter', function() {
});
it('highlights a range of lines given in the URL hash', function() {
- var line;
new LineHighlighter({ hash: '#L5-25' });
expect($(`.${this.css}`).length).toBe(21);
- for (line = 5; line <= 25; line += 1) {
+ for (let line = 5; line <= 25; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css);
}
});
it('scrolls to the first highlighted line on initial load', function() {
- var spy;
- spy = spyOn($, 'scrollTo');
+ const spy = spyOn($, 'scrollTo');
new LineHighlighter({ hash: '#L5-25' });
expect(spy).toHaveBeenCalledWith('#L5', jasmine.anything());
});
it('discards click events', function() {
- var spy;
- spy = spyOnEvent('a[data-line-number]', 'click');
+ const spy = spyOnEvent('a[data-line-number]', 'click');
clickLine(13);
expect(spy).toHaveBeenPrevented();
});
it('handles garbage input from the hash', function() {
- var func;
- func = function() {
+ const func = function() {
return new LineHighlighter({ fileHolderSelector: '#blob-content-holder' });
};
@@ -76,8 +71,7 @@ describe('LineHighlighter', function() {
describe('clickHandler', function() {
it('handles clicking on a child icon element', function() {
- var spy;
- spy = spyOn(this['class'], 'setHash').and.callThrough();
+ const spy = spyOn(this['class'], 'setHash').and.callThrough();
$('#L13 i')
.mousedown()
.click();
@@ -102,8 +96,7 @@ describe('LineHighlighter', function() {
});
it('sets the hash', function() {
- var spy;
- spy = spyOn(this['class'], 'setHash').and.callThrough();
+ const spy = spyOn(this['class'], 'setHash').and.callThrough();
clickLine(13);
expect(spy).toHaveBeenCalledWith(13);
@@ -112,8 +105,7 @@ describe('LineHighlighter', function() {
describe('with shiftKey', function() {
it('sets the hash', function() {
- var spy;
- spy = spyOn(this['class'], 'setHash').and.callThrough();
+ const spy = spyOn(this['class'], 'setHash').and.callThrough();
clickLine(13);
clickLine(20, {
shiftKey: true,
@@ -134,8 +126,7 @@ describe('LineHighlighter', function() {
});
it('sets the hash', function() {
- var spy;
- spy = spyOn(this['class'], 'setHash');
+ const spy = spyOn(this['class'], 'setHash');
clickLine(13, {
shiftKey: true,
});
@@ -146,27 +137,25 @@ describe('LineHighlighter', function() {
describe('with existing single-line highlight', function() {
it('uses existing line as last line when target is lesser', function() {
- var line;
clickLine(20);
clickLine(15, {
shiftKey: true,
});
expect($(`.${this.css}`).length).toBe(6);
- for (line = 15; line <= 20; line += 1) {
+ for (let line = 15; line <= 20; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css);
}
});
it('uses existing line as first line when target is greater', function() {
- var line;
clickLine(5);
clickLine(10, {
shiftKey: true,
});
expect($(`.${this.css}`).length).toBe(6);
- for (line = 5; line <= 10; line += 1) {
+ for (let line = 5; line <= 10; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css);
}
});
@@ -183,25 +172,23 @@ describe('LineHighlighter', function() {
});
it('uses target as first line when it is less than existing first line', function() {
- var line;
clickLine(5, {
shiftKey: true,
});
expect($(`.${this.css}`).length).toBe(6);
- for (line = 5; line <= 10; line += 1) {
+ for (let line = 5; line <= 10; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css);
}
});
it('uses target as last line when it is greater than existing first line', function() {
- var line;
clickLine(15, {
shiftKey: true,
});
expect($(`.${this.css}`).length).toBe(6);
- for (line = 10; line <= 15; line += 1) {
+ for (let line = 10; line <= 15; line += 1) {
expect($(`#LC${line}`)).toHaveClass(this.css);
}
});
diff --git a/spec/javascripts/monitoring/components/graph_group_spec.js b/spec/javascripts/monitoring/components/graph_group_spec.js
index 068c4b5302c..7bcab9116e9 100644
--- a/spec/javascripts/monitoring/components/graph_group_spec.js
+++ b/spec/javascripts/monitoring/components/graph_group_spec.js
@@ -3,6 +3,8 @@ import GraphGroup from '~/monitoring/components/graph_group.vue';
describe('Graph group component', () => {
let graphGroup;
+ const findPrometheusGroup = () => graphGroup.find('.prometheus-graph-group');
+ const findPrometheusPanel = () => graphGroup.find('.prometheus-panel');
afterEach(() => {
graphGroup.destroy();
@@ -40,8 +42,32 @@ describe('Graph group component', () => {
});
});
- it('should not contain a prometheus-graph-group container when showPanels is false', () => {
- expect(graphGroup.vm.$el.querySelector('.prometheus-graph-group')).toBe(null);
+ it('should not contain a prometheus-panel container when showPanels is false', () => {
+ expect(findPrometheusPanel().exists()).toBe(false);
+ });
+ });
+
+ describe('When collapseGroup prop is updated', () => {
+ beforeEach(() => {
+ graphGroup = shallowMount(GraphGroup, {
+ propsData: {
+ name: 'panel',
+ collapseGroup: false,
+ },
+ });
+ });
+
+ it('previously collapsed group should respond to the prop change', done => {
+ expect(findPrometheusGroup().exists()).toBe(false);
+
+ graphGroup.setProps({
+ collapseGroup: true,
+ });
+
+ graphGroup.vm.$nextTick(() => {
+ expect(findPrometheusGroup().exists()).toBe(true);
+ done();
+ });
});
});
});
diff --git a/spec/lib/gitlab/git/attributes_at_ref_parser_spec.rb b/spec/lib/gitlab/git/attributes_at_ref_parser_spec.rb
index 134bd5657e7..6c4f650fa83 100644
--- a/spec/lib/gitlab/git/attributes_at_ref_parser_spec.rb
+++ b/spec/lib/gitlab/git/attributes_at_ref_parser_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::AttributesAtRefParser, :seed_helper do
diff --git a/spec/lib/gitlab/git/attributes_parser_spec.rb b/spec/lib/gitlab/git/attributes_parser_spec.rb
index f431d4e2a53..94b7a086e59 100644
--- a/spec/lib/gitlab/git/attributes_parser_spec.rb
+++ b/spec/lib/gitlab/git/attributes_parser_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::AttributesParser, :seed_helper do
diff --git a/spec/lib/gitlab/git/blame_spec.rb b/spec/lib/gitlab/git/blame_spec.rb
index ac085e2c266..9b2d6fa3bcb 100644
--- a/spec/lib/gitlab/git/blame_spec.rb
+++ b/spec/lib/gitlab/git/blame_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Blame, :seed_helper do
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 7f680071969..15d03a481d5 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Blob, :seed_helper do
diff --git a/spec/lib/gitlab/git/branch_spec.rb b/spec/lib/gitlab/git/branch_spec.rb
index 02ef7b92538..cc26b7e7fcd 100644
--- a/spec/lib/gitlab/git/branch_spec.rb
+++ b/spec/lib/gitlab/git/branch_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Branch, :seed_helper do
@@ -77,7 +79,7 @@ describe Gitlab::Git::Branch, :seed_helper do
tree = parents.first.tree
{
- message: 'commit message',
+ message: +'commit message',
author: committer,
committer: committer,
tree: tree,
@@ -126,7 +128,7 @@ describe Gitlab::Git::Branch, :seed_helper do
it { expect(repository.branches.size).to eq(SeedRepo::Repo::BRANCHES.size) }
def create_commit
- params[:message].delete!("\r")
+ params[:message].delete!(+"\r")
Rugged::Commit.create(rugged, params.merge(committer: committer.merge(time: Time.now)))
end
end
diff --git a/spec/lib/gitlab/git/bundle_file_spec.rb b/spec/lib/gitlab/git/bundle_file_spec.rb
index ff7c981dadd..e88e163a03f 100644
--- a/spec/lib/gitlab/git/bundle_file_spec.rb
+++ b/spec/lib/gitlab/git/bundle_file_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::BundleFile do
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index cdab7127748..6c9467916de 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Commit, :seed_helper do
@@ -64,8 +66,8 @@ describe Gitlab::Git::Commit, :seed_helper do
end
describe "Commit info from gitaly commit" do
- let(:subject) { "My commit".force_encoding('ASCII-8BIT') }
- let(:body) { subject + "My body".force_encoding('ASCII-8BIT') }
+ let(:subject) { (+"My commit").force_encoding('ASCII-8BIT') }
+ let(:body) { subject + (+"My body").force_encoding('ASCII-8BIT') }
let(:body_size) { body.length }
let(:gitaly_commit) { build(:gitaly_commit, subject: subject, body: body, body_size: body_size) }
let(:id) { gitaly_commit.id }
@@ -85,7 +87,7 @@ describe Gitlab::Git::Commit, :seed_helper do
it { expect(commit.parent_ids).to eq(gitaly_commit.parent_ids) }
context 'body_size != body.size' do
- let(:body) { "".force_encoding('ASCII-8BIT') }
+ let(:body) { (+"").force_encoding('ASCII-8BIT') }
context 'zero body_size' do
it { expect(commit.safe_message).to eq(subject) }
diff --git a/spec/lib/gitlab/git/compare_spec.rb b/spec/lib/gitlab/git/compare_spec.rb
index 65dfb93d0db..6136df57acb 100644
--- a/spec/lib/gitlab/git/compare_spec.rb
+++ b/spec/lib/gitlab/git/compare_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Compare, :seed_helper do
diff --git a/spec/lib/gitlab/git/conflict/file_spec.rb b/spec/lib/gitlab/git/conflict/file_spec.rb
index a6cabd4966a..0ee9ff93e87 100644
--- a/spec/lib/gitlab/git/conflict/file_spec.rb
+++ b/spec/lib/gitlab/git/conflict/file_spec.rb
@@ -1,9 +1,11 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::Conflict::File do
let(:conflict) { { theirs: { path: 'foo', mode: 33188 }, ours: { path: 'foo', mode: 33188 } } }
- let(:invalid_content) { described_class.new(nil, nil, conflict, "a\xC4\xFC".force_encoding(Encoding::ASCII_8BIT)) }
- let(:valid_content) { described_class.new(nil, nil, conflict, "Espa\xC3\xB1a".force_encoding(Encoding::ASCII_8BIT)) }
+ let(:invalid_content) { described_class.new(nil, nil, conflict, (+"a\xC4\xFC").force_encoding(Encoding::ASCII_8BIT)) }
+ let(:valid_content) { described_class.new(nil, nil, conflict, (+"Espa\xC3\xB1a").force_encoding(Encoding::ASCII_8BIT)) }
describe '#lines' do
context 'when the content contains non-UTF-8 characters' do
diff --git a/spec/lib/gitlab/git/conflict/parser_spec.rb b/spec/lib/gitlab/git/conflict/parser_spec.rb
index 29a1702a1c6..600c870acd4 100644
--- a/spec/lib/gitlab/git/conflict/parser_spec.rb
+++ b/spec/lib/gitlab/git/conflict/parser_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::Conflict::Parser do
@@ -208,7 +210,7 @@ CONFLICT
# these strings.
context 'when the file contains UTF-8 characters' do
it 'does not raise' do
- expect { parse_text("Espa\xC3\xB1a".force_encoding(Encoding::ASCII_8BIT)) }
+ expect { parse_text((+"Espa\xC3\xB1a").force_encoding(Encoding::ASCII_8BIT)) }
.not_to raise_error
end
end
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index ce45d6e24ba..0d19d35bc52 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::DiffCollection, :seed_helper do
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index 9ab669ad488..456d6af7bd8 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Diff, :seed_helper do
diff --git a/spec/lib/gitlab/git/gitmodules_parser_spec.rb b/spec/lib/gitlab/git/gitmodules_parser_spec.rb
index de81dcd227d..58d1d2c71da 100644
--- a/spec/lib/gitlab/git/gitmodules_parser_spec.rb
+++ b/spec/lib/gitlab/git/gitmodules_parser_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::GitmodulesParser do
diff --git a/spec/lib/gitlab/git/hook_env_spec.rb b/spec/lib/gitlab/git/hook_env_spec.rb
index 5e49ea6da7a..ca6a4ad42a3 100644
--- a/spec/lib/gitlab/git/hook_env_spec.rb
+++ b/spec/lib/gitlab/git/hook_env_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::HookEnv do
diff --git a/spec/lib/gitlab/git/lfs_changes_spec.rb b/spec/lib/gitlab/git/lfs_changes_spec.rb
index d035df7e0c2..a99e8c4f60c 100644
--- a/spec/lib/gitlab/git/lfs_changes_spec.rb
+++ b/spec/lib/gitlab/git/lfs_changes_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::LfsChanges do
diff --git a/spec/lib/gitlab/git/lfs_pointer_file_spec.rb b/spec/lib/gitlab/git/lfs_pointer_file_spec.rb
index d7f76737f3f..8bb26ed4854 100644
--- a/spec/lib/gitlab/git/lfs_pointer_file_spec.rb
+++ b/spec/lib/gitlab/git/lfs_pointer_file_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::LfsPointerFile do
diff --git a/spec/lib/gitlab/git/pre_receive_error_spec.rb b/spec/lib/gitlab/git/pre_receive_error_spec.rb
index cb030e38032..cb539261671 100644
--- a/spec/lib/gitlab/git/pre_receive_error_spec.rb
+++ b/spec/lib/gitlab/git/pre_receive_error_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::PreReceiveError do
diff --git a/spec/lib/gitlab/git/push_spec.rb b/spec/lib/gitlab/git/push_spec.rb
index 566c8209504..32c4c1c82d4 100644
--- a/spec/lib/gitlab/git/push_spec.rb
+++ b/spec/lib/gitlab/git/push_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::Push do
diff --git a/spec/lib/gitlab/git/raw_diff_change_spec.rb b/spec/lib/gitlab/git/raw_diff_change_spec.rb
index a0bb37fd84a..79b2fc21011 100644
--- a/spec/lib/gitlab/git/raw_diff_change_spec.rb
+++ b/spec/lib/gitlab/git/raw_diff_change_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::RawDiffChange do
diff --git a/spec/lib/gitlab/git/remote_mirror_spec.rb b/spec/lib/gitlab/git/remote_mirror_spec.rb
index dc63eef7814..9744562b51b 100644
--- a/spec/lib/gitlab/git/remote_mirror_spec.rb
+++ b/spec/lib/gitlab/git/remote_mirror_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::RemoteMirror do
diff --git a/spec/lib/gitlab/git/remote_repository_spec.rb b/spec/lib/gitlab/git/remote_repository_spec.rb
index e166628d4ca..556cc692231 100644
--- a/spec/lib/gitlab/git/remote_repository_spec.rb
+++ b/spec/lib/gitlab/git/remote_repository_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::RemoteRepository, :seed_helper do
diff --git a/spec/lib/gitlab/git/repository_cleaner_spec.rb b/spec/lib/gitlab/git/repository_cleaner_spec.rb
index 7bba0107e58..b387d1033d3 100644
--- a/spec/lib/gitlab/git/repository_cleaner_spec.rb
+++ b/spec/lib/gitlab/git/repository_cleaner_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::RepositoryCleaner do
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 44c41da7560..20a74af7a45 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Repository, :seed_helper do
diff --git a/spec/lib/gitlab/git/tag_spec.rb b/spec/lib/gitlab/git/tag_spec.rb
index 4c0291f64f0..87db3f588ad 100644
--- a/spec/lib/gitlab/git/tag_spec.rb
+++ b/spec/lib/gitlab/git/tag_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Tag, :seed_helper do
diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb
index 7e169cfe270..98bb4ffd0bd 100644
--- a/spec/lib/gitlab/git/tree_spec.rb
+++ b/spec/lib/gitlab/git/tree_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "spec_helper"
describe Gitlab::Git::Tree, :seed_helper do
diff --git a/spec/lib/gitlab/git/user_spec.rb b/spec/lib/gitlab/git/user_spec.rb
index d9d338206f8..277b1c48355 100644
--- a/spec/lib/gitlab/git/user_spec.rb
+++ b/spec/lib/gitlab/git/user_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::User do
diff --git a/spec/lib/gitlab/git/util_spec.rb b/spec/lib/gitlab/git/util_spec.rb
index 88c871855df..81918f036f9 100644
--- a/spec/lib/gitlab/git/util_spec.rb
+++ b/spec/lib/gitlab/git/util_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::Util do
diff --git a/spec/lib/gitlab/git/wiki_spec.rb b/spec/lib/gitlab/git/wiki_spec.rb
index 1e577392949..8bae2e8125e 100644
--- a/spec/lib/gitlab/git/wiki_spec.rb
+++ b/spec/lib/gitlab/git/wiki_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::Wiki do
diff --git a/spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb b/spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb
index bcf4814edb6..a4489cca443 100644
--- a/spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb
+++ b/spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Git::WrapsGitalyErrors do
diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb
index 8401b683fd5..ea0a6e1b967 100644
--- a/spec/lib/gitlab/gpg/commit_spec.rb
+++ b/spec/lib/gitlab/gpg/commit_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe Gitlab::Gpg::Commit do
diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb
index da307754243..c1516a48b80 100644
--- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb
+++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index df82ac38fc6..ad256c10964 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -990,7 +990,8 @@ describe Notify do
end
context 'when a comment on an existing discussion' do
- let!(:second_note) { create(model, author: note_author, noteable: nil, in_reply_to: note) }
+ let(:first_note) { create_note }
+ let(:note) { create(model, author: note_author, noteable: nil, in_reply_to: first_note) }
it 'contains an introduction' do
is_expected.to have_body_text 'commented on a'
@@ -1000,7 +1001,11 @@ describe Notify do
describe 'on a commit' do
let(:commit) { project.commit }
- let(:note) { create(:discussion_note_on_commit, commit_id: commit.id, project: project, author: note_author) }
+ let(:note) { create_note }
+
+ def create_note
+ create(:discussion_note_on_commit, commit_id: commit.id, project: project, author: note_author)
+ end
before do
allow(note).to receive(:noteable).and_return(commit)
@@ -1027,9 +1032,13 @@ describe Notify do
end
describe 'on a merge request' do
- let(:note) { create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: note_author) }
+ let(:note) { create_note }
let(:note_on_merge_request_path) { project_merge_request_path(project, merge_request, anchor: "note_#{note.id}") }
+ def create_note
+ create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: note_author)
+ end
+
before do
allow(note).to receive(:noteable).and_return(merge_request)
end
@@ -1055,9 +1064,13 @@ describe Notify do
end
describe 'on an issue' do
- let(:note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: note_author) }
+ let(:note) { create_note }
let(:note_on_issue_path) { project_issue_path(project, issue, anchor: "note_#{note.id}") }
+ def create_note
+ create(:discussion_note_on_issue, noteable: issue, project: project, author: note_author)
+ end
+
before do
allow(note).to receive(:noteable).and_return(issue)
end
@@ -1134,7 +1147,8 @@ describe Notify do
end
context 'when a comment on an existing discussion' do
- let!(:second_note) { create(model, author: note_author, noteable: nil, in_reply_to: note) }
+ let(:first_note) { create(model) }
+ let(:note) { create(model, author: note_author, noteable: nil, in_reply_to: first_note) }
it 'contains an introduction' do
is_expected.to have_body_text 'commented on a discussion on'
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 3ab88b52568..b09e699a8a7 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -456,6 +456,19 @@ describe Note do
end
end
+ describe '#start_of_discussion?' do
+ let_it_be(:note) { create(:discussion_note_on_merge_request) }
+ let_it_be(:reply) { create(:discussion_note_on_merge_request, in_reply_to: note) }
+
+ it 'returns true when note is the start of a discussion' do
+ expect(note).to be_start_of_discussion
+ end
+
+ it 'returns false when note is a reply' do
+ expect(reply).not_to be_start_of_discussion
+ end
+ end
+
describe '.find_discussion' do
let!(:note) { create(:discussion_note_on_merge_request) }
let!(:note2) { create(:discussion_note_on_merge_request, in_reply_to: note) }