Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-23 21:13:22 +00:00
parent 3acaaf7231
commit 0978fc4c40
63 changed files with 468 additions and 320 deletions

View File

@ -3,7 +3,7 @@ import { EditorContent as TiptapEditorContent } from '@tiptap/vue-2';
import { __ } from '~/locale';
import { VARIANT_DANGER } from '~/flash';
import { createContentEditor } from '../services/create_content_editor';
import { ALERT_EVENT } from '../constants';
import { ALERT_EVENT, TIPTAP_AUTOFOCUS_OPTIONS } from '../constants';
import ContentEditorAlert from './content_editor_alert.vue';
import ContentEditorProvider from './content_editor_provider.vue';
import EditorStateObserver from './editor_state_observer.vue';
@ -51,6 +51,12 @@ export default {
required: false,
default: '',
},
autofocus: {
type: [String, Boolean],
required: false,
default: false,
validator: (autofocus) => TIPTAP_AUTOFOCUS_OPTIONS.includes(autofocus),
},
},
data() {
return {
@ -67,7 +73,7 @@ export default {
},
},
created() {
const { renderMarkdown, uploadsPath, extensions, serializerConfig } = this;
const { renderMarkdown, uploadsPath, extensions, serializerConfig, autofocus } = this;
// This is a non-reactive attribute intentionally since this is a complex object.
this.contentEditor = createContentEditor({
@ -75,6 +81,9 @@ export default {
uploadsPath,
extensions,
serializerConfig,
tiptapOptions: {
autofocus,
},
});
},
mounted() {

View File

@ -66,3 +66,5 @@ export const SAFE_VIDEO_EXT = ['mp4', 'm4v', 'mov', 'webm', 'ogv'];
export const SAFE_AUDIO_EXT = ['mp3', 'oga', 'ogg', 'spx', 'wav'];
export const DIAGRAM_LANGUAGES = ['plantuml', 'mermaid'];
export const TIPTAP_AUTOFOCUS_OPTIONS = [true, false, 'start', 'end', 'all'];

View File

@ -299,7 +299,7 @@ export default {
:uploads-path="pageInfo.uploadsPath"
:enable-content-editor="isMarkdownFormat"
:enable-preview="isMarkdownFormat"
:autofocus="pageInfo.persisted"
:init-on-autofocus="pageInfo.persisted"
:form-field-placeholder="$options.i18n.content.placeholder"
:form-field-aria-label="$options.i18n.content.label"
form-field-id="wiki_content"

View File

@ -31,7 +31,8 @@ export default {
},
uploadsPath: {
type: String,
required: true,
required: false,
default: () => window.uploads_path,
},
enableContentEditor: {
type: Boolean,
@ -56,11 +57,6 @@ export default {
required: false,
default: true,
},
autofocus: {
type: Boolean,
required: false,
default: false,
},
formFieldPlaceholder: {
type: String,
required: false,
@ -71,17 +67,30 @@ export default {
required: false,
default: '',
},
initOnAutofocus: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
editingMode: EDITING_MODE_MARKDOWN_FIELD,
switchEditingControlEnabled: true,
autofocus: this.initOnAutofocus,
};
},
computed: {
isContentEditorActive() {
return this.enableContentEditor && this.editingMode === EDITING_MODE_CONTENT_EDITOR;
},
contentEditorAutofocus() {
// Match textarea focus behavior
return this.autofocus ? 'end' : false;
},
},
mounted() {
this.autofocusTextarea(this.editingMode);
},
methods: {
updateMarkdownFromContentEditor({ markdown }) {
@ -99,9 +108,25 @@ export default {
renderMarkdown(markdown) {
return axios.post(this.renderMarkdownPath, { text: markdown }).then(({ data }) => data.body);
},
onEditingModeChange(editingMode) {
this.notifyEditingModeChange(editingMode);
this.enableAutofocus(editingMode);
},
onEditingModeRestored(editingMode) {
this.notifyEditingModeChange(editingMode);
},
notifyEditingModeChange(editingMode) {
this.$emit(editingMode);
},
enableAutofocus(editingMode) {
this.autofocus = true;
this.autofocusTextarea(editingMode);
},
autofocusTextarea(editingMode) {
if (this.autofocus && editingMode === EDITING_MODE_MARKDOWN_FIELD) {
this.$refs.textarea.focus();
}
},
},
switchEditingControlOptions: [
{ text: __('Source'), value: EDITING_MODE_MARKDOWN_FIELD },
@ -119,13 +144,13 @@ export default {
class="gl-display-flex"
:options="$options.switchEditingControlOptions"
:disabled="!enableContentEditor || !switchEditingControlEnabled"
@change="notifyEditingModeChange"
@change="onEditingModeChange"
/>
</div>
<local-storage-sync
v-model="editingMode"
storage-key="gl-wiki-content-editor-enabled"
@input="notifyEditingModeChange"
@input="onEditingModeRestored"
/>
<markdown-field
v-if="!isContentEditorActive"
@ -148,7 +173,6 @@ export default {
dir="auto"
data-supports-quick-actions="false"
data-qa-selector="markdown_editor_form_field"
:autofocus="autofocus"
:aria-label="formFieldAriaLabel"
:placeholder="formFieldPlaceholder"
@input="updateMarkdownFromMarkdownField"
@ -161,6 +185,7 @@ export default {
:render-markdown="renderMarkdown"
:uploads-path="uploadsPath"
:markdown="value"
:autofocus="contentEditorAutofocus"
@change="updateMarkdownFromContentEditor"
@loading="disableSwitchEditingControl"
@loadingSuccess="enableSwitchEditingControl"

View File

@ -856,7 +856,6 @@ module Ci
variables.append(key: 'CI_COMMIT_REF_NAME', value: source_ref)
variables.append(key: 'CI_COMMIT_REF_SLUG', value: source_ref_slug)
variables.append(key: 'CI_COMMIT_BRANCH', value: ref) if branch?
variables.append(key: 'CI_COMMIT_TAG', value: ref) if tag?
variables.append(key: 'CI_COMMIT_MESSAGE', value: git_commit_message.to_s)
variables.append(key: 'CI_COMMIT_TITLE', value: git_commit_full_title.to_s)
variables.append(key: 'CI_COMMIT_DESCRIPTION', value: git_commit_description.to_s)
@ -869,7 +868,8 @@ module Ci
variables.append(key: 'CI_BUILD_BEFORE_SHA', value: before_sha)
variables.append(key: 'CI_BUILD_REF_NAME', value: source_ref)
variables.append(key: 'CI_BUILD_REF_SLUG', value: source_ref_slug)
variables.append(key: 'CI_BUILD_TAG', value: ref) if tag?
variables.concat(predefined_commit_tag_variables)
end
end
end
@ -894,6 +894,20 @@ module Ci
end
end
def predefined_commit_tag_variables
strong_memoize(:predefined_commit_ref_variables) do
Gitlab::Ci::Variables::Collection.new.tap do |variables|
next variables unless tag?
variables.append(key: 'CI_COMMIT_TAG', value: ref)
variables.append(key: 'CI_COMMIT_TAG_MESSAGE', value: project.repository.find_tag(ref).message)
# legacy variable
variables.append(key: 'CI_BUILD_TAG', value: ref)
end
end
end
def queued_duration
return unless started_at

View File

@ -77,7 +77,7 @@
= _("The maximum file size in megabytes for individual job artifacts.")
= link_to sprite_icon('question-o'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'maximum-artifacts-size'), target: '_blank', rel: 'noopener noreferrer'
= f.submit _('Save changes'), class: "btn gl-button btn-confirm"
= f.submit _('Save changes'), pajamas_button: true
%hr

View File

@ -1,12 +1,13 @@
- return unless custom_attributes.present?
.card
.card-header
= render Pajamas::CardComponent.new(body_options: { class: 'gl-py-0' }) do |c|
- c.header do
= link_to(_('Custom Attributes'), help_page_path('api/custom_attributes.md'))
%ul.content-list
- custom_attributes.each do |custom_attribute|
%li
%span.light
= custom_attribute.key
%strong
= custom_attribute.value
- c.body do
%ul.content-list
- custom_attributes.each do |custom_attribute|
%li
%span.light
= custom_attribute.key
%strong
= custom_attribute.value

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
class FinalizeTaskSystemNoteRenaming < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
MIGRATION = 'RenameTaskSystemNoteToChecklistItem'
def up
ensure_batched_background_migration_is_finished(
job_class_name: MIGRATION,
table_name: :system_note_metadata,
column_name: :id,
job_arguments: []
)
end
def down
# noop
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class RemoveTaskSystemNoteRenameTempIndex < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
INDEX_NAME = 'tmp_index_system_note_metadata_on_id_where_task'
def up
remove_concurrent_index_by_name :system_note_metadata, INDEX_NAME
end
def down
add_concurrent_index :system_note_metadata, [:id, :action], where: "action = 'task'", name: INDEX_NAME
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class RemoveTraceColumnFromCiBuilds < Gitlab::Database::Migration[2.0]
enable_lock_retries!
def change
remove_column :ci_builds, :trace, :text
end
end

View File

@ -0,0 +1 @@
e683bd10619f9ceee2a5d330ca4d6b9d396ad8934095b707a0eec5d49cdaf2be

View File

@ -0,0 +1 @@
6a4677165bca249c369214aee9fae331fde4dc716544bac93c06f0ee33222455

View File

@ -0,0 +1 @@
6ce159118651ec93989e8f111528ad2134e46f359c483b60239290d677f9f4f4

View File

@ -12601,7 +12601,6 @@ CREATE TABLE ci_build_trace_metadata (
CREATE TABLE ci_builds (
status character varying,
finished_at timestamp without time zone,
trace text,
created_at timestamp without time zone,
updated_at timestamp without time zone,
started_at timestamp without time zone,
@ -30910,8 +30909,6 @@ CREATE INDEX tmp_index_project_statistics_cont_registry_size ON project_statisti
CREATE INDEX tmp_index_system_note_metadata_on_attention_request_actions ON system_note_metadata USING btree (id) WHERE ((action)::text = ANY ((ARRAY['attention_requested'::character varying, 'attention_request_removed'::character varying])::text[]));
CREATE INDEX tmp_index_system_note_metadata_on_id_where_task ON system_note_metadata USING btree (id, action) WHERE ((action)::text = 'task'::text);
CREATE INDEX tmp_index_vulnerability_occurrences_on_id_and_scanner_id ON vulnerability_occurrences USING btree (id, scanner_id) WHERE (report_type = ANY (ARRAY[7, 99]));
CREATE UNIQUE INDEX uniq_pkgs_deb_grp_architectures_on_distribution_id_and_name ON packages_debian_group_architectures USING btree (distribution_id, name);

View File

@ -27,8 +27,9 @@ Features behind flags can be gradually rolled out, typically:
1. The feature flag is removed.
These features can be enabled and disabled to allow or prevent users from using
them. It can be done by GitLab administrators with access to GitLab Rails
console.
them. It can be done by GitLab administrators with access to the
[Rails console](#how-to-enable-and-disable-features-behind-flags) or the
[Feature flags API](../api/features.md).
When you disable a feature flag, the feature is hidden from users and all of the functionality is turned off.
For example, data is not recorded and services do not run.

View File

@ -22,7 +22,8 @@ a database schema.
Adding a `:migration` tag to a test signature enables some custom RSpec
`before` and `after` hooks in our
[`spec/support/migration.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/f81fa6ab1dd788b70ef44b85aaba1f31ffafae7d/spec/support/migration.rb)
to run.
to run. If performing a migration against a database schema other than
`:gitlab_main` (for example `:gitlab_ci`), then you must specify it as well: `migration: :gitlab_ci`. See [spec/migrations/change_public_projects_cost_factor_spec.rb](https://gitlab.com/gitlab-org/gitlab/blob/master/spec/migrations/change_public_projects_cost_factor_spec.rb#L6-6) for an example.
A `before` hook reverts all migrations to the point that a migration
under test is not yet migrated.

View File

@ -19,14 +19,14 @@ Group push rules allow group maintainers to set
In GitLab 15.4 and later, to configure push rules for a group:
1. On the left sidebar, select **Push rules**.
1. On the left sidebar, select **Settings > Repository**.
1. Expand the **Pre-defined push rules** section.
1. Select the settings you want.
1. Select **Save Push Rules**.
In GitLab 15.3 and earlier, to configure push rules for a group:
1. On the left sidebar, select **Settings > Repository** page.
1. Expand the **Pre-defined push rules** section.
1. On the left sidebar, select **Push rules**.
1. Select the settings you want.
1. Select **Save Push Rules**.

View File

@ -27,7 +27,7 @@ module Gitlab
end
def id_for_already_imported_cache(note)
note.id
note[:id]
end
end
end

View File

@ -27,7 +27,7 @@ module Gitlab
end
def id_for_already_imported_cache(event)
event.id
event[:id]
end
end
end

View File

@ -33,7 +33,7 @@ module Gitlab
end
def id_for_already_imported_cache(issue)
issue.number
issue[:number]
end
def collection_options

View File

@ -22,7 +22,7 @@ module Gitlab
end
def already_imported?(label)
existing_labels.include?(label.name)
existing_labels.include?(label[:name])
end
def build_labels_cache
@ -33,8 +33,8 @@ module Gitlab
time = Time.zone.now
{
title: label.name,
color: '#' + label.color,
title: label[:name],
color: '#' + label[:color],
project_id: project.id,
type: 'ProjectLabel',
created_at: time,

View File

@ -22,7 +22,7 @@ module Gitlab
end
def already_imported?(milestone)
existing_milestones.include?(milestone.number)
existing_milestones.include?(milestone[:number])
end
def build_milestones_cache
@ -31,19 +31,19 @@ module Gitlab
def build(milestone)
{
iid: milestone.number,
title: milestone.title,
description: milestone.description,
iid: milestone[:number],
title: milestone[:title],
description: milestone[:description],
project_id: project.id,
state: state_for(milestone),
due_date: milestone.due_on&.to_date,
created_at: milestone.created_at,
updated_at: milestone.updated_at
due_date: milestone[:due_on]&.to_date,
created_at: milestone[:created_at],
updated_at: milestone[:updated_at]
}
end
def state_for(milestone)
milestone.state == 'open' ? :active : :closed
milestone[:state] == 'open' ? :active : :closed
end
def each_milestone

View File

@ -27,7 +27,7 @@ module Gitlab
end
def id_for_already_imported_cache(note)
note.id
note[:id]
end
end
end

View File

@ -19,7 +19,7 @@ module Gitlab
end
def id_for_already_imported_cache(pr)
pr.number
pr[:number]
end
def object_type
@ -55,11 +55,11 @@ module Gitlab
def update_repository?(pr)
last_update = project.last_repository_updated_at || project.created_at
return false if pr.updated_at < last_update
return false if pr[:updated_at] < last_update
# PRs may be updated without there actually being new commits, thus we
# check to make sure we only re-fetch if truly necessary.
!(commit_exists?(pr.head.sha) && commit_exists?(pr.base.sha))
!(commit_exists?(pr.dig(:head, :sha)) && commit_exists?(pr.dig(:base, :sha)))
end
def commit_exists?(sha)

View File

@ -34,7 +34,7 @@ module Gitlab
end
def id_for_already_imported_cache(review)
review.id
review[:id]
end
# The worker can be interrupted, by rate limit for instance,
@ -52,7 +52,7 @@ module Gitlab
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
review.merge_request_id = merge_request.id
review[:merge_request_id] = merge_request.id
yield(review)
mark_as_imported(review)

View File

@ -21,21 +21,21 @@ module Gitlab
end
def already_imported?(release)
existing_tags.include?(release.tag_name) || release.tag_name.nil?
existing_tags.include?(release[:tag_name]) || release[:tag_name].nil?
end
def build(release)
existing_tags.add(release.tag_name)
existing_tags.add(release[:tag_name])
{
name: release.name,
tag: release.tag_name,
name: release[:name],
tag: release[:tag_name],
author_id: fetch_author_id(release),
description: description_for(release),
created_at: release.created_at,
updated_at: release.created_at,
created_at: release[:created_at],
updated_at: release[:created_at],
# Draft releases will have a null published_at
released_at: release.published_at || Time.current,
released_at: release[:published_at] || Time.current,
project_id: project.id
}
end
@ -45,7 +45,7 @@ module Gitlab
end
def description_for(release)
release.body.presence || "Release for tag #{release.tag_name}"
release[:body].presence || "Release for tag #{release[:tag_name]}"
end
def object_type

View File

@ -28,7 +28,7 @@ module Gitlab
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
pull_request = parent_record.is_a? MergeRequest
associated.issue = { 'number' => parent_record.iid, 'pull_request' => pull_request }
associated[:issue] = { 'number' => parent_record.iid, 'pull_request' => pull_request }
yield(associated)
mark_as_imported(associated)
@ -78,7 +78,7 @@ module Gitlab
end
def id_for_already_imported_cache(event)
event.id
event[:id]
end
def collection_options
@ -87,9 +87,9 @@ module Gitlab
# Cross-referenced events on Github doesn't have id.
def compose_associated_id!(issuable, event)
return if event.event != 'cross-referenced'
return if event[:event] != 'cross-referenced'
event.id = "cross-reference##{issuable.iid}-in-#{event.source.issue.id}"
event[:id] = "cross-reference##{issuable.iid}-in-#{event.dig(:source, :issue, :id)}"
end
end
end

View File

@ -21,31 +21,31 @@ module Gitlab
#
# note - An instance of `Sawyer::Resource` containing the note details.
def self.from_api_response(note, additional_data = {})
matches = note.html_url.match(NOTEABLE_ID_REGEX)
matches = note[:html_url].match(NOTEABLE_ID_REGEX)
unless matches
raise(
ArgumentError,
"The note URL #{note.html_url.inspect} is not supported"
"The note URL #{note[:html_url].inspect} is not supported"
)
end
user = Representation::User.from_api_response(note.user) if note.user
user = Representation::User.from_api_response(note[:user]) if note[:user]
hash = {
noteable_id: matches[:iid].to_i,
file_path: note.path,
commit_id: note.commit_id,
original_commit_id: note.original_commit_id,
diff_hunk: note.diff_hunk,
file_path: note[:path],
commit_id: note[:commit_id],
original_commit_id: note[:original_commit_id],
diff_hunk: note[:diff_hunk],
author: user,
note: note.body,
created_at: note.created_at,
updated_at: note.updated_at,
note_id: note.id,
end_line: note.line,
start_line: note.start_line,
side: note.side,
in_reply_to_id: note.in_reply_to_id
note: note[:body],
created_at: note[:created_at],
updated_at: note[:updated_at],
note_id: note[:id],
end_line: note[:line],
start_line: note[:start_line],
side: note[:side],
in_reply_to_id: note[:in_reply_to_id]
}
new(hash)

View File

@ -19,24 +19,24 @@ module Gitlab
# details.
def self.from_api_response(issue, additional_data = {})
user =
if issue.user
Representation::User.from_api_response(issue.user)
if issue[:user]
Representation::User.from_api_response(issue[:user])
end
hash = {
iid: issue.number,
title: issue.title,
description: issue.body,
milestone_number: issue.milestone&.number,
state: issue.state == 'open' ? :opened : :closed,
assignees: issue.assignees.map do |u|
iid: issue[:number],
title: issue[:title],
description: issue[:body],
milestone_number: issue.dig(:milestone, :number),
state: issue[:state] == 'open' ? :opened : :closed,
assignees: issue[:assignees].map do |u|
Representation::User.from_api_response(u)
end,
label_names: issue.labels.map(&:name),
label_names: issue[:labels].map { _1[:name] },
author: user,
created_at: issue.created_at,
updated_at: issue.updated_at,
pull_request: issue.pull_request ? true : false,
created_at: issue[:created_at],
updated_at: issue[:updated_at],
pull_request: issue[:pull_request] ? true : false,
work_item_type_id: additional_data[:work_item_type_id]
}

View File

@ -37,20 +37,20 @@ module Gitlab
# event - An instance of `Sawyer::Resource` containing the event details.
def from_api_response(event, additional_data = {})
new(
id: event.id,
actor: user_representation(event.actor),
event: event.event,
commit_id: event.commit_id,
label_title: event.label && event.label[:name],
old_title: event.rename && event.rename[:from],
new_title: event.rename && event.rename[:to],
milestone_title: event.milestone && event.milestone[:title],
issue: event.issue&.to_h&.symbolize_keys,
source: event.source,
assignee: user_representation(event.assignee),
requested_reviewer: user_representation(event.requested_reviewer),
review_requester: user_representation(event.review_requester),
created_at: event.created_at
id: event[:id],
actor: user_representation(event[:actor]),
event: event[:event],
commit_id: event[:commit_id],
label_title: event.dig(:label, :name),
old_title: event.dig(:rename, :from),
new_title: event.dig(:rename, :to),
milestone_title: event.dig(:milestone, :title),
issue: event[:issue]&.symbolize_keys,
source: event[:source],
assignee: user_representation(event[:assignee]),
requested_reviewer: user_representation(event[:requested_reviewer]),
review_requester: user_representation(event[:review_requester]),
created_at: event[:created_at]
)
end

View File

@ -18,12 +18,12 @@ module Gitlab
#
# note - An instance of `Sawyer::Resource` containing the note details.
def self.from_api_response(note, additional_data = {})
matches = note.html_url.match(NOTEABLE_TYPE_REGEX)
matches = note[:html_url].match(NOTEABLE_TYPE_REGEX)
if !matches || !matches[:type]
raise(
ArgumentError,
"The note URL #{note.html_url.inspect} is not supported"
"The note URL #{note[:html_url].inspect} is not supported"
)
end
@ -34,15 +34,15 @@ module Gitlab
'Issue'
end
user = Representation::User.from_api_response(note.user) if note.user
user = Representation::User.from_api_response(note[:user]) if note[:user]
hash = {
noteable_type: noteable_type,
noteable_id: matches[:iid].to_i,
author: user,
note: note.body,
created_at: note.created_at,
updated_at: note.updated_at,
note_id: note.id
note: note[:body],
created_at: note[:created_at],
updated_at: note[:updated_at],
note_id: note[:id]
}
new(hash)

View File

@ -19,28 +19,28 @@ module Gitlab
#
# issue - An instance of `Sawyer::Resource` containing the PR details.
def self.from_api_response(pr, additional_data = {})
assignee = Representation::User.from_api_response(pr.assignee) if pr.assignee
user = Representation::User.from_api_response(pr.user) if pr.user
merged_by = Representation::User.from_api_response(pr.merged_by) if pr.merged_by
assignee = Representation::User.from_api_response(pr[:assignee]) if pr[:assignee]
user = Representation::User.from_api_response(pr[:user]) if pr[:user]
merged_by = Representation::User.from_api_response(pr[:merged_by]) if pr[:merged_by]
hash = {
iid: pr.number,
title: pr.title,
description: pr.body,
source_branch: pr.head.ref,
target_branch: pr.base.ref,
source_branch_sha: pr.head.sha,
target_branch_sha: pr.base.sha,
source_repository_id: pr.head&.repo&.id,
target_repository_id: pr.base&.repo&.id,
source_repository_owner: pr.head&.user&.login,
state: pr.state == 'open' ? :opened : :closed,
milestone_number: pr.milestone&.number,
iid: pr[:number],
title: pr[:title],
description: pr[:body],
source_branch: pr.dig(:head, :ref),
target_branch: pr.dig(:base, :ref),
source_branch_sha: pr.dig(:head, :sha),
target_branch_sha: pr.dig(:base, :sha),
source_repository_id: pr.dig(:head, :repo, :id),
target_repository_id: pr.dig(:base, :repo, :id),
source_repository_owner: pr.dig(:head, :user, :login),
state: pr[:state] == 'open' ? :opened : :closed,
milestone_number: pr.dig(:milestone, :number),
author: user,
assignee: assignee,
created_at: pr.created_at,
updated_at: pr.updated_at,
merged_at: pr.merged_at,
created_at: pr[:created_at],
updated_at: pr[:updated_at],
merged_at: pr[:merged_at],
merged_by: merged_by
}

View File

@ -11,16 +11,19 @@ module Gitlab
expose_attribute :author, :note, :review_type, :submitted_at, :merge_request_id, :review_id
# Builds a PullRequestReview from a GitHub API response.
#
# review - An instance of `Sawyer::Resource` containing the note details.
def self.from_api_response(review, additional_data = {})
user = Representation::User.from_api_response(review.user) if review.user
user = Representation::User.from_api_response(review[:user]) if review[:user]
new(
merge_request_id: review.merge_request_id,
merge_request_id: review[:merge_request_id],
author: user,
note: review.body,
review_type: review.state,
submitted_at: review.submitted_at,
review_id: review.id
note: review[:body],
review_type: review[:state],
submitted_at: review[:submitted_at],
review_id: review[:id]
)
end

View File

@ -16,8 +16,8 @@ module Gitlab
# user - An instance of `Sawyer::Resource` containing the user details.
def self.from_api_response(user, additional_data = {})
new(
id: user.id,
login: user.login
id: user[:id],
login: user[:login]
)
end

View File

@ -32,7 +32,7 @@ module Gitlab
end
def id_for_already_imported_cache(associated)
associated.id
associated[:id]
end
def parent_collection

View File

@ -39,18 +39,19 @@ module Gitlab
#
# If the object has no author ID we'll use the ID of the GitLab ghost
# user.
# object - An instance of `Sawyer::Resource` or a `Github::Representer`
def author_id_for(object, author_key: :author)
user_info = case author_key
when :actor
object&.actor
object[:actor]
when :assignee
object&.assignee
object[:assignee]
when :requested_reviewer
object&.requested_reviewer
object[:requested_reviewer]
when :review_requester
object&.review_requester
object[:review_requester]
else
object&.author
object ? object[:author] : nil
end
id = user_info ? user_id_for(user_info) : GithubImport.ghost_user_id
@ -64,14 +65,14 @@ module Gitlab
# Returns the GitLab user ID of an issuable's assignee.
def assignee_id_for(issuable)
user_id_for(issuable.assignee) if issuable.assignee
user_id_for(issuable[:assignee]) if issuable[:assignee]
end
# Returns the GitLab user ID for a GitHub user.
#
# user - An instance of `Gitlab::GithubImport::Representation::User`.
# user - An instance of `Gitlab::GithubImport::Representation::User` or `Sawyer::Resource`.
def user_id_for(user)
find(user.id, user.login) if user.present?
find(user[:id], user[:login]) if user.present?
end
# Returns the GitLab ID for the given GitHub ID or username.
@ -114,7 +115,7 @@ module Gitlab
unless email
user = client.user(username)
email = Gitlab::Cache::Import::Caching.write(cache_key, user.email, timeout: timeout(user.email)) if user
email = Gitlab::Cache::Import::Caching.write(cache_key, user[:email], timeout: timeout(user[:email])) if user
end
email

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
# This is based on https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/bin/slack
#
# Sends Slack notification MSG to CI_SLACK_WEBHOOK_URL (which needs to be set).

View File

@ -26,12 +26,13 @@ describe('ContentEditor', () => {
const findEditorStateObserver = () => wrapper.findComponent(EditorStateObserver);
const findLoadingIndicator = () => wrapper.findComponent(LoadingIndicator);
const findContentEditorAlert = () => wrapper.findComponent(ContentEditorAlert);
const createWrapper = ({ markdown } = {}) => {
const createWrapper = ({ markdown, autofocus } = {}) => {
wrapper = shallowMountExtended(ContentEditor, {
propsData: {
renderMarkdown,
uploadsPath,
markdown,
autofocus,
},
stubs: {
EditorStateObserver,
@ -70,14 +71,22 @@ describe('ContentEditor', () => {
expect(editorContent.classes()).toContain('md');
});
it('renders ContentEditorProvider component', async () => {
await createWrapper();
it('allows setting the tiptap editor to autofocus', async () => {
createWrapper({ autofocus: 'start' });
await nextTick();
expect(findEditorContent().props().editor.options.autofocus).toBe('start');
});
it('renders ContentEditorProvider component', () => {
createWrapper();
expect(wrapper.findComponent(ContentEditorProvider).exists()).toBe(true);
});
it('renders top toolbar component', async () => {
await createWrapper();
it('renders top toolbar component', () => {
createWrapper();
expect(wrapper.findComponent(TopToolbar).exists()).toBe(true);
});

View File

@ -123,7 +123,7 @@ describe('WikiForm', () => {
renderMarkdownPath: pageInfoPersisted.markdownPreviewPath,
markdownDocsPath: pageInfoPersisted.markdownHelpPath,
uploadsPath: pageInfoPersisted.uploadsPath,
autofocus: pageInfoPersisted.persisted,
initOnAutofocus: pageInfoPersisted.persisted,
formFieldId: 'wiki_content',
formFieldName: 'wiki[content]',
}),

View File

@ -1,12 +1,15 @@
import { GlSegmentedControl } from '@gitlab/ui';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { EDITING_MODE_MARKDOWN_FIELD, EDITING_MODE_CONTENT_EDITOR } from '~/vue_shared/constants';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import ContentEditor from '~/content_editor/components/content_editor.vue';
import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import { stubComponent } from 'helpers/stub_component';
jest.mock('~/emoji');
@ -15,7 +18,6 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
const value = 'test markdown';
const renderMarkdownPath = '/api/markdown';
const markdownDocsPath = '/help/markdown';
const uploadsPath = '/uploads';
const enableAutocomplete = true;
const enablePreview = false;
const formFieldId = 'markdown_field';
@ -24,13 +26,13 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
const formFieldAriaLabel = 'Edit your content';
let mock;
const buildWrapper = (propsData = {}) => {
const buildWrapper = ({ propsData = {}, attachTo } = {}) => {
wrapper = mountExtended(MarkdownEditor, {
attachTo,
propsData: {
value,
renderMarkdownPath,
markdownDocsPath,
uploadsPath,
enableAutocomplete,
enablePreview,
formFieldId,
@ -39,6 +41,9 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
formFieldAriaLabel,
...propsData,
},
stubs: {
BubbleMenu: stubComponent(BubbleMenu),
},
});
};
const findSegmentedControl = () => wrapper.findComponent(GlSegmentedControl);
@ -48,6 +53,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
const findContentEditor = () => wrapper.findComponent(ContentEditor);
beforeEach(() => {
window.uploads_path = 'uploads';
mock = new MockAdapter(axios);
});
@ -66,7 +72,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
enableAutocomplete,
textareaValue: value,
markdownDocsPath,
uploadsPath,
uploadsPath: window.uploads_path,
enablePreview,
}),
);
@ -129,18 +135,32 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(wrapper.emitted('input')).toEqual([[newValue]]);
});
describe('when initOnAutofocus is true', () => {
beforeEach(async () => {
buildWrapper({ attachTo: document.body, propsData: { initOnAutofocus: true } });
await nextTick();
});
it('sets the markdown field as the active element in the document', () => {
expect(document.activeElement).toBe(findTextarea().element);
});
});
describe(`when segmented control triggers input event with ${EDITING_MODE_CONTENT_EDITOR} value`, () => {
beforeEach(() => {
buildWrapper();
findSegmentedControl().vm.$emit('input', EDITING_MODE_CONTENT_EDITOR);
findSegmentedControl().vm.$emit('change', EDITING_MODE_CONTENT_EDITOR);
});
it('displays the content editor', () => {
expect(findContentEditor().props()).toEqual(
expect.objectContaining({
renderMarkdown: expect.any(Function),
uploadsPath,
uploadsPath: window.uploads_path,
markdown: value,
autofocus: 'end',
}),
);
});
@ -173,6 +193,17 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
findSegmentedControl().vm.$emit('input', EDITING_MODE_CONTENT_EDITOR);
});
describe('when initOnAutofocus is true', () => {
beforeEach(() => {
buildWrapper({ propsData: { initOnAutofocus: true } });
findLocalStorageSync().vm.$emit('input', EDITING_MODE_CONTENT_EDITOR);
});
it('sets the content editor autofocus property to end', () => {
expect(findContentEditor().props().autofocus).toBe('end');
});
});
it('emits input event when content editor emits change event', async () => {
const newValue = 'new value';
@ -197,6 +228,19 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
it('updates localStorage value', () => {
expect(findLocalStorageSync().props().value).toBe(EDITING_MODE_MARKDOWN_FIELD);
});
it('sets the textarea as the activeElement in the document', async () => {
// The component should be rebuilt to attach it to the document body
buildWrapper({ attachTo: document.body });
await findSegmentedControl().vm.$emit('input', EDITING_MODE_CONTENT_EDITOR);
expect(findContentEditor().exists()).toBe(true);
await findSegmentedControl().vm.$emit('input', EDITING_MODE_MARKDOWN_FIELD);
await findSegmentedControl().vm.$emit('change', EDITING_MODE_MARKDOWN_FIELD);
expect(document.activeElement).toBe(findTextarea().element);
});
});
describe('when content editor emits loading event', () => {

View File

@ -68,8 +68,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
context 'when refs policy is specified' do
let(:tag_name) { project.repository.tags.first.name }
let(:pipeline) do
build(:ci_pipeline, project: project, ref: 'feature', tag: true)
build(:ci_pipeline, project: project, ref: tag_name, tag: true)
end
let(:config) do

View File

@ -7,14 +7,13 @@ RSpec.describe Gitlab::GithubImport::Importer::DiffNotesImporter do
let(:client) { double(:client) }
let(:github_comment) do
double(
:response,
{
html_url: 'https://github.com/foo/bar/pull/42',
path: 'README.md',
commit_id: '123abc',
original_commit_id: 'original123abc',
diff_hunk: "@@ -1 +1 @@\n-Hello\n+Hello world",
user: double(:user, id: 4, login: 'alice'),
user: { id: 4, login: 'alice' },
created_at: Time.zone.now,
updated_at: Time.zone.now,
line: 23,
@ -29,7 +28,7 @@ RSpec.describe Gitlab::GithubImport::Importer::DiffNotesImporter do
sug1
```
BODY
)
}
end
describe '#parallel?' do

View File

@ -9,20 +9,19 @@ RSpec.describe Gitlab::GithubImport::Importer::IssuesImporter do
let(:updated_at) { Time.new(2017, 1, 1, 12, 15) }
let(:github_issue) do
double(
:response,
{
number: 42,
title: 'My Issue',
body: 'This is my issue',
milestone: double(:milestone, number: 4),
milestone: { number: 4 },
state: 'open',
assignees: [double(:user, id: 4, login: 'alice')],
labels: [double(:label, name: 'bug')],
user: double(:user, id: 4, login: 'alice'),
assignees: [{ id: 4, login: 'alice' }],
labels: [{ name: 'bug' }],
user: { id: 4, login: 'alice' },
created_at: created_at,
updated_at: updated_at,
pull_request: false
)
}
end
describe '#parallel?' do

View File

@ -28,7 +28,7 @@ RSpec.describe Gitlab::GithubImport::Importer::LabelsImporter, :clean_gitlab_red
describe '#build_labels' do
it 'returns an Array containnig label rows' do
label = double(:label, name: 'bug', color: 'ffffff')
label = { name: 'bug', color: 'ffffff' }
expect(importer).to receive(:each_label).and_return([label])
@ -41,7 +41,7 @@ RSpec.describe Gitlab::GithubImport::Importer::LabelsImporter, :clean_gitlab_red
it 'does not create labels that already exist' do
create(:label, project: project, title: 'bug')
label = double(:label, name: 'bug', color: 'ffffff')
label = { name: 'bug', color: 'ffffff' }
expect(importer).to receive(:each_label).and_return([label])
expect(importer.build_labels).to be_empty
@ -60,7 +60,7 @@ RSpec.describe Gitlab::GithubImport::Importer::LabelsImporter, :clean_gitlab_red
describe '#build' do
let(:label_hash) do
importer.build(double(:label, name: 'bug', color: 'ffffff'))
importer.build({ name: 'bug', color: 'ffffff' })
end
it 'returns the attributes of the label as a Hash' do

View File

@ -11,8 +11,7 @@ RSpec.describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab
let(:updated_at) { Time.new(2017, 1, 1, 12, 15) }
let(:milestone) do
double(
:milestone,
{
number: 1,
title: '1.0',
description: 'The first release',
@ -20,12 +19,11 @@ RSpec.describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab
due_on: due_on,
created_at: created_at,
updated_at: updated_at
)
}
end
let(:milestone2) do
double(
:milestone,
{
number: 1,
title: '1.0',
description: 'The first release',
@ -33,7 +31,7 @@ RSpec.describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab
due_on: nil,
created_at: created_at,
updated_at: updated_at
)
}
end
describe '#execute' do

View File

@ -7,15 +7,14 @@ RSpec.describe Gitlab::GithubImport::Importer::NotesImporter do
let(:client) { double(:client) }
let(:github_comment) do
double(
:response,
{
html_url: 'https://github.com/foo/bar/issues/42',
user: double(:user, id: 4, login: 'alice'),
user: { id: 4, login: 'alice' },
body: 'Hello world',
created_at: Time.zone.now,
updated_at: Time.zone.now,
id: 1
)
}
end
describe '#parallel?' do

View File

@ -7,15 +7,16 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestMergedByImporter, :cle
let(:project) { merge_request.project }
let(:merged_at) { Time.new(2017, 1, 1, 12, 00).utc }
let(:client_double) { double(user: double(id: 999, login: 'merger', email: 'merger@email.com')) }
let(:merger_user) { double(id: 999, login: 'merger') }
let(:client_double) { double(user: { id: 999, login: 'merger', email: 'merger@email.com' } ) }
let(:merger_user) { { id: 999, login: 'merger' } }
let(:pull_request) do
instance_double(
Gitlab::GithubImport::Representation::PullRequest,
iid: merge_request.iid,
merged_at: merged_at,
merged_by: merger_user
Gitlab::GithubImport::Representation::PullRequest.from_api_response(
{
number: merge_request.iid,
merged_at: merged_at,
merged_by: merger_user
}
)
end

View File

@ -8,7 +8,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
let_it_be(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:client_double) { double(user: double(id: 999, login: 'author', email: 'author@email.com')) }
let(:client_double) { double(user: { id: 999, login: 'author', email: 'author@email.com' }) }
let(:submitted_at) { Time.new(2017, 1, 1, 12, 00).utc }
subject { described_class.new(review, project, client_double) }

View File

@ -8,33 +8,30 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter do
let(:client) { double(:client) }
let(:pull_request) do
double(
:response,
{
number: 42,
title: 'My Pull Request',
body: 'This is my pull request',
state: 'closed',
head: double(
:head,
head: {
sha: '123abc',
ref: 'my-feature',
repo: double(:repo, id: 400),
user: double(:user, id: 4, login: 'alice')
),
base: double(
:base,
repo: { id: 400 },
user: { id: 4, login: 'alice' }
},
base: {
sha: '456def',
ref: 'master',
repo: double(:repo, id: 200)
),
milestone: double(:milestone, number: 4),
user: double(:user, id: 4, login: 'alice'),
assignee: double(:user, id: 4, login: 'alice'),
merged_by: double(:user, id: 4, login: 'alice'),
repo: { id: 200 }
},
milestone: { number: 4 },
user: { id: 4, login: 'alice' },
assignee: { id: 4, login: 'alice' },
merged_by: { id: 4, login: 'alice' },
created_at: 1.second.ago,
updated_at: 1.second.ago,
merged_at: 1.second.ago
)
}
end
describe '#parallel?' do
@ -184,12 +181,11 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter do
context 'when the pull request was updated after the last update' do
let(:pr) do
double(
:pr,
{
updated_at: Time.zone.now,
head: double(:head, sha: '123'),
base: double(:base, sha: '456')
)
head: { sha: '123' },
base: { sha: '456' }
}
end
before do
@ -201,7 +197,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter do
it 'returns true when the head SHA is not present' do
expect(importer)
.to receive(:commit_exists?)
.with(pr.head.sha)
.with('123')
.and_return(false)
expect(importer.update_repository?(pr)).to eq(true)
@ -210,12 +206,12 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter do
it 'returns true when the base SHA is not present' do
expect(importer)
.to receive(:commit_exists?)
.with(pr.head.sha)
.with('123')
.and_return(true)
expect(importer)
.to receive(:commit_exists?)
.with(pr.base.sha)
.with('456')
.and_return(false)
expect(importer.update_repository?(pr)).to eq(true)
@ -224,12 +220,12 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter do
it 'returns false if both the head and base SHAs are present' do
expect(importer)
.to receive(:commit_exists?)
.with(pr.head.sha)
.with('123')
.and_return(true)
expect(importer)
.to receive(:commit_exists?)
.with(pr.base.sha)
.with('456')
.and_return(true)
expect(importer.update_repository?(pr)).to eq(false)
@ -238,7 +234,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsImporter do
context 'when the pull request was updated before the last update' do
it 'returns false' do
pr = double(:pr, updated_at: 1.year.ago)
pr = { updated_at: 1.year.ago }
allow(project)
.to receive(:last_repository_updated_at)

View File

@ -23,7 +23,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsReviewsImporter do
end
describe '#id_for_already_imported_cache' do
it { expect(subject.id_for_already_imported_cache(double(id: 1))).to eq(1) }
it { expect(subject.id_for_already_imported_cache({ id: 1 })).to eq(1) }
end
describe '#each_object_to_import', :clean_gitlab_redis_cache do
@ -36,15 +36,11 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsReviewsImporter do
)
end
let(:review) { double(id: 1) }
let(:review) { { id: 1 } }
it 'fetches the pull requests reviews data' do
page = double(objects: [review], number: 1)
expect(review)
.to receive(:merge_request_id=)
.with(merge_request.id)
expect(client)
.to receive(:each_page)
.exactly(:once) # ensure to be cached on the second call
@ -55,6 +51,8 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestsReviewsImporter do
.to yield_with_args(review)
subject.each_object_to_import {}
expect(review[:merge_request_id]).to eq(merge_request.id)
end
it 'skips cached pages' do

View File

@ -10,22 +10,21 @@ RSpec.describe Gitlab::GithubImport::Importer::ReleasesImporter do
let(:created_at) { Time.new(2017, 1, 1, 12, 00) }
let(:released_at) { Time.new(2017, 1, 1, 12, 00) }
let(:author) do
double(
{
login: 'User A',
id: 1
)
}
end
let(:github_release) do
double(
:github_release,
{
tag_name: '1.0',
name: github_release_name,
body: 'This is my release',
created_at: created_at,
published_at: released_at,
author: author
)
}
end
def stub_email_for_github_username(user_name = 'User A', user_email = 'user@example.com')
@ -56,7 +55,7 @@ RSpec.describe Gitlab::GithubImport::Importer::ReleasesImporter do
end
it 'imports draft releases' do
release_double = double(
release_double = {
name: 'Test',
body: 'This is description',
tag_name: '1.0',
@ -65,7 +64,7 @@ RSpec.describe Gitlab::GithubImport::Importer::ReleasesImporter do
updated_at: created_at,
published_at: nil,
author: author
)
}
expect(importer).to receive(:each_release).and_return([release_double])
@ -101,7 +100,7 @@ RSpec.describe Gitlab::GithubImport::Importer::ReleasesImporter do
end
it 'uses a default release description if none is provided' do
expect(github_release).to receive(:body).and_return('')
github_release[:body] = nil
expect(importer).to receive(:each_release).and_return([github_release])
release = importer.build_releases.first
@ -110,10 +109,10 @@ RSpec.describe Gitlab::GithubImport::Importer::ReleasesImporter do
end
it 'does not create releases that have a NULL tag' do
null_tag_release = double(
null_tag_release = {
name: 'NULL Test',
tag_name: nil
)
}
expect(importer).to receive(:each_release).and_return([null_tag_release])
expect(importer.build_releases).to be_empty
@ -179,13 +178,13 @@ RSpec.describe Gitlab::GithubImport::Importer::ReleasesImporter do
end
it 'returns ghost user when author is empty in Github release' do
allow(github_release).to receive(:author).and_return(nil)
github_release[:author] = nil
expect(release_hash[:author_id]).to eq(Gitlab::GithubImport.ghost_user_id)
end
context 'when Github author is not found in Gitlab' do
let(:author) { double(login: 'octocat', id: 1 ) }
let(:author) { { login: 'octocat', id: 1 } }
before do
# Stub user email which does not match a Gitlab user.
@ -222,11 +221,11 @@ RSpec.describe Gitlab::GithubImport::Importer::ReleasesImporter do
describe '#description_for' do
it 'returns the description when present' do
expect(importer.description_for(github_release)).to eq(github_release.body)
expect(importer.description_for(github_release)).to eq(github_release[:body])
end
it 'returns a generated description when one is not present' do
allow(github_release).to receive(:body).and_return('')
github_release[:body] = nil
expect(importer.description_for(github_release)).to eq('Release for tag 1.0')
end

View File

@ -14,7 +14,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointDiffNotesImporter d
it { expect(subject.importer_class).to eq(Gitlab::GithubImport::Importer::DiffNoteImporter) }
it { expect(subject.collection_method).to eq(:pull_request_comments) }
it { expect(subject.object_type).to eq(:diff_note) }
it { expect(subject.id_for_already_imported_cache(double(id: 1))).to eq(1) }
it { expect(subject.id_for_already_imported_cache({ id: 1 })).to eq(1) }
describe '#each_object_to_import', :clean_gitlab_redis_cache do
let(:merge_request) do
@ -26,7 +26,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointDiffNotesImporter d
)
end
let(:note) { double(id: 1) }
let(:note) { { id: 1 } }
let(:page) { double(objects: [note], number: 1) }
it 'fetches data' do

View File

@ -40,7 +40,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
end
describe '#id_for_already_imported_cache' do
let(:event) { instance_double('Event', id: 1) }
let(:event) { { id: 1 } }
it { expect(subject.id_for_already_imported_cache(event)).to eq(1) }
end
@ -116,8 +116,8 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
counter = 0
subject.each_object_to_import do |object|
expect(object).to eq issue_event
expect(issue_event.issue['number']).to eq issuable.iid
expect(issue_event.issue['pull_request']).to eq false
expect(issue_event[:issue]['number']).to eq issuable.iid
expect(issue_event[:issue]['pull_request']).to eq false
counter += 1
end
expect(counter).to eq 1
@ -131,8 +131,8 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueEventsImporter
counter = 0
subject.each_object_to_import do |object|
expect(object).to eq issue_event
expect(issue_event.issue['number']).to eq issuable.iid
expect(issue_event.issue['pull_request']).to eq true
expect(issue_event[:issue]['number']).to eq issuable.iid
expect(issue_event[:issue]['pull_request']).to eq true
counter += 1
end
expect(counter).to eq 1

View File

@ -14,7 +14,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueNotesImporter
it { expect(subject.importer_class).to eq(Gitlab::GithubImport::Importer::NoteImporter) }
it { expect(subject.collection_method).to eq(:issue_comments) }
it { expect(subject.object_type).to eq(:note) }
it { expect(subject.id_for_already_imported_cache(double(id: 1))).to eq(1) }
it { expect(subject.id_for_already_imported_cache({ id: 1 })).to eq(1) }
describe '#each_object_to_import', :clean_gitlab_redis_cache do
let(:issue) do
@ -25,7 +25,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueNotesImporter
)
end
let(:note) { double(id: 1) }
let(:note) { { id: 1 } }
let(:page) { double(objects: [note], number: 1) }
it 'fetches data' do

View File

@ -14,7 +14,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointMergeRequestNotesIm
it { expect(subject.importer_class).to eq(Gitlab::GithubImport::Importer::NoteImporter) }
it { expect(subject.collection_method).to eq(:issue_comments) }
it { expect(subject.object_type).to eq(:note) }
it { expect(subject.id_for_already_imported_cache(double(id: 1))).to eq(1) }
it { expect(subject.id_for_already_imported_cache({ id: 1 })).to eq(1) }
describe '#each_object_to_import', :clean_gitlab_redis_cache do
let(:merge_request) do
@ -26,7 +26,7 @@ RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointMergeRequestNotesIm
)
end
let(:note) { double(id: 1) }
let(:note) { { id: 1 } }
let(:page) { double(objects: [note], number: 1) }
it 'fetches data' do

View File

@ -28,7 +28,7 @@ RSpec.describe Gitlab::GithubImport::Representation::DiffNote, :clean_gitlab_red
let(:start_line) { nil }
let(:end_line) { 23 }
let(:note_body) { 'Hello world' }
let(:user_data) { { 'id' => 4, 'login' => 'alice' } }
let(:user_data) { { id: 4, login: 'alice' } }
let(:side) { 'RIGHT' }
let(:created_at) { Time.new(2017, 1, 1, 12, 00) }
let(:updated_at) { Time.new(2017, 1, 1, 12, 15) }
@ -275,15 +275,14 @@ RSpec.describe Gitlab::GithubImport::Representation::DiffNote, :clean_gitlab_red
describe '.from_api_response' do
it_behaves_like 'a DiffNote representation' do
let(:response) do
double(
:response,
{
id: note_id,
html_url: 'https://github.com/foo/bar/pull/42',
path: 'README.md',
commit_id: '123abc',
original_commit_id: 'original123abc',
side: side,
user: user_data && double(:user, user_data),
user: user_data,
diff_hunk: hunk,
body: note_body,
created_at: created_at,
@ -291,7 +290,7 @@ RSpec.describe Gitlab::GithubImport::Representation::DiffNote, :clean_gitlab_red
line: end_line,
start_line: start_line,
in_reply_to_id: in_reply_to_id
)
}
end
subject(:note) { described_class.from_api_response(response) }

View File

@ -74,20 +74,19 @@ RSpec.describe Gitlab::GithubImport::Representation::Issue do
describe '.from_api_response' do
let(:response) do
double(
:response,
{
number: 42,
title: 'My Issue',
body: 'This is my issue',
milestone: double(:milestone, number: 4),
milestone: { number: 4 },
state: 'open',
assignees: [double(:user, id: 4, login: 'alice')],
labels: [double(:label, name: 'bug')],
user: double(:user, id: 4, login: 'alice'),
assignees: [{ id: 4, login: 'alice' }],
labels: [{ name: 'bug' }],
user: { id: 4, login: 'alice' },
created_at: created_at,
updated_at: updated_at,
pull_request: false
)
}
end
let(:additional_data) { { work_item_type_id: work_item_type_id } }
@ -97,9 +96,7 @@ RSpec.describe Gitlab::GithubImport::Representation::Issue do
end
it 'does not set the user if the response did not include a user' do
allow(response)
.to receive(:user)
.and_return(nil)
response[:user] = nil
issue = described_class.from_api_response(response, additional_data)

View File

@ -48,15 +48,14 @@ RSpec.describe Gitlab::GithubImport::Representation::Note do
describe '.from_api_response' do
let(:response) do
double(
:response,
{
html_url: 'https://github.com/foo/bar/issues/42',
user: double(:user, id: 4, login: 'alice'),
user: { id: 4, login: 'alice' },
body: 'Hello world',
created_at: created_at,
updated_at: updated_at,
id: 1
)
}
end
it_behaves_like 'a Note' do
@ -64,9 +63,7 @@ RSpec.describe Gitlab::GithubImport::Representation::Note do
end
it 'does not set the user if the response did not include a user' do
allow(response)
.to receive(:user)
.and_return(nil)
response[:user] = nil
note = described_class.from_api_response(response)

View File

@ -21,15 +21,14 @@ RSpec.describe Gitlab::GithubImport::Representation::PullRequestReview do
describe '.from_api_response' do
let(:response) do
double(
:response,
{
id: 999,
merge_request_id: 42,
body: 'note',
state: 'APPROVED',
user: double(:user, id: 4, login: 'alice'),
user: { id: 4, login: 'alice' },
submitted_at: submitted_at
)
}
end
it_behaves_like 'a PullRequest review' do
@ -37,9 +36,7 @@ RSpec.describe Gitlab::GithubImport::Representation::PullRequestReview do
end
it 'does not set the user if the response did not include a user' do
allow(response)
.to receive(:user)
.and_return(nil)
response[:user] = nil
review = described_class.from_api_response(response)

View File

@ -93,33 +93,30 @@ RSpec.describe Gitlab::GithubImport::Representation::PullRequest do
describe '.from_api_response' do
let(:response) do
double(
:response,
{
number: 42,
title: 'My Pull Request',
body: 'This is my pull request',
state: 'closed',
head: double(
:head,
head: {
sha: '123abc',
ref: 'my-feature',
repo: double(:repo, id: 400),
user: double(:user, id: 4, login: 'alice')
),
base: double(
:base,
repo: { id: 400 },
user: { id: 4, login: 'alice' }
},
base: {
sha: '456def',
ref: 'master',
repo: double(:repo, id: 200)
),
milestone: double(:milestone, number: 4),
user: double(:user, id: 4, login: 'alice'),
assignee: double(:user, id: 4, login: 'alice'),
merged_by: double(:user, id: 4, login: 'alice'),
repo: { id: 200 }
},
milestone: { number: 4 },
user: { id: 4, login: 'alice' },
assignee: { id: 4, login: 'alice' },
merged_by: { id: 4, login: 'alice' },
created_at: created_at,
updated_at: updated_at,
merged_at: merged_at
)
}
end
it_behaves_like 'a PullRequest' do
@ -127,9 +124,7 @@ RSpec.describe Gitlab::GithubImport::Representation::PullRequest do
end
it 'does not set the user if the response did not include a user' do
allow(response)
.to receive(:user)
.and_return(nil)
response[:user] = nil
pr = described_class.from_api_response(response)

View File

@ -21,7 +21,7 @@ RSpec.describe Gitlab::GithubImport::Representation::User do
describe '.from_api_response' do
it_behaves_like 'a User' do
let(:response) { double(:response, id: 42, login: 'alice') }
let(:response) { { id: 42, login: 'alice' } }
let(:user) { described_class.from_api_response(response) }
end
end

View File

@ -17,8 +17,8 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
describe '#author_id_for' do
context 'with default author_key' do
it 'returns the user ID for the author of an object' do
user = double(:user, id: 4, login: 'kittens')
note = double(:note, author: user)
user = { id: 4, login: 'kittens' }
note = { author: user }
expect(finder).to receive(:user_id_for).with(user).and_return(42)
@ -26,8 +26,8 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
end
it 'returns the ID of the project creator if no user ID could be found' do
user = double(:user, id: 4, login: 'kittens')
note = double(:note, author: user)
user = { id: 4, login: 'kittens' }
note = { author: user }
expect(finder).to receive(:user_id_for).with(user).and_return(nil)
@ -35,7 +35,7 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
end
it 'returns the ID of the ghost user when the object has no user' do
note = double(:note, author: nil)
note = { author: nil }
expect(finder.author_id_for(note)).to eq([User.ghost.id, true])
end
@ -46,7 +46,7 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
end
context 'with a non-default author_key' do
let(:user) { double(:user, id: 4, login: 'kittens') }
let(:user) { { id: 4, login: 'kittens' } }
shared_examples 'user ID finder' do |author_key|
it 'returns the user ID for an object' do
@ -57,25 +57,25 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
end
context 'when the author_key parameter is :actor' do
let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', actor: user) }
let(:issue_event) { { actor: user } }
it_behaves_like 'user ID finder', :actor
end
context 'when the author_key parameter is :assignee' do
let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', assignee: user) }
let(:issue_event) { { assignee: user } }
it_behaves_like 'user ID finder', :assignee
end
context 'when the author_key parameter is :requested_reviewer' do
let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', requested_reviewer: user) }
let(:issue_event) { { requested_reviewer: user } }
it_behaves_like 'user ID finder', :requested_reviewer
end
context 'when the author_key parameter is :review_requester' do
let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', review_requester: user) }
let(:issue_event) { { review_requester: user } }
it_behaves_like 'user ID finder', :review_requester
end
@ -84,15 +84,15 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
describe '#assignee_id_for' do
it 'returns the user ID for the assignee of an issuable' do
user = double(:user, id: 4, login: 'kittens')
issue = double(:issue, assignee: user)
user = { id: 4, login: 'kittens' }
issue = { assignee: user }
expect(finder).to receive(:user_id_for).with(user).and_return(42)
expect(finder.assignee_id_for(issue)).to eq(42)
end
it 'returns nil if the issuable does not have an assignee' do
issue = double(:issue, assignee: nil)
issue = { assignee: nil }
expect(finder).not_to receive(:user_id_for)
expect(finder.assignee_id_for(issue)).to be_nil
@ -101,9 +101,9 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
describe '#user_id_for' do
it 'returns the user ID for the given user' do
user = double(:user, id: 4, login: 'kittens')
user = { id: 4, login: 'kittens' }
expect(finder).to receive(:find).with(user.id, user.login).and_return(42)
expect(finder).to receive(:find).with(user[:id], user[:login]).and_return(42)
expect(finder.user_id_for(user)).to eq(42)
end
@ -221,7 +221,7 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
end
context 'when an Email address is not cached' do
let(:user) { double(:user, email: email) }
let(:user) { { email: email } }
it 'retrieves the Email address from the GitHub API' do
expect(client).to receive(:user).with('kittens').and_return(user)
@ -251,7 +251,7 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
end
it 'shortens the timeout for Email address in cache when an Email address is private/nil from GitHub' do
user = double(:user, email: nil)
user = { email: nil }
expect(client).to receive(:user).with('kittens').and_return(user)
expect(Gitlab::Cache::Import::Caching)

View File

@ -3069,8 +3069,24 @@ RSpec.describe Ci::Build do
end
context 'when build is for tag' do
let(:tag_name) { project.repository.tags.first.name }
let(:tag_message) { project.repository.tags.first.message }
let!(:pipeline) do
create(:ci_pipeline, project: project,
sha: project.commit.id,
ref: tag_name,
status: 'success')
end
let!(:build) { create(:ci_build, pipeline: pipeline, ref: tag_name) }
let(:tag_variable) do
{ key: 'CI_COMMIT_TAG', value: 'master', public: true, masked: false }
{ key: 'CI_COMMIT_TAG', value: tag_name, public: true, masked: false }
end
let(:tag_message_variable) do
{ key: 'CI_COMMIT_TAG_MESSAGE', value: tag_message, public: true, masked: false }
end
before do
@ -3081,7 +3097,7 @@ RSpec.describe Ci::Build do
it do
build.reload
expect(subject).to include(tag_variable)
expect(subject).to include(tag_variable, tag_message_variable)
end
end