Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-17 15:10:50 +00:00
parent 735165a16c
commit 31d92b51ea
11 changed files with 132 additions and 12 deletions

View File

@ -35,6 +35,12 @@ module Resolvers
private
def preloads
{
last_edited_by: :last_edited_by
}
end
# Allows to apply lookahead for fields
# selected from WidgetInterface
override :node_selection

View File

@ -13,8 +13,18 @@ module Types
implements Types::WorkItems::WidgetInterface
field :description, GraphQL::Types::String,
null: true,
description: 'Description of the work item.'
null: true,
description: 'Description of the work item.'
field :edited, GraphQL::Types::Boolean,
null: false,
description: 'Whether the description has been edited since the work item was created.',
method: :edited?
field :last_edited_at, Types::TimeType,
null: true,
description: 'Timestamp of when the work item\'s description was last edited.'
field :last_edited_by, Types::UserType,
null: true,
description: 'User that made the last edit to the work item\'s description.'
markdown_field :description_html, null: true do |resolved_object|
resolved_object.work_item

View File

@ -3,7 +3,13 @@
module WorkItems
module Widgets
class Description < Base
delegate :description, to: :work_item
delegate :description, :edited?, :last_edited_at, to: :work_item
def last_edited_by
return unless work_item.edited?
work_item.last_edited_by
end
end
end
end

View File

@ -19367,6 +19367,9 @@ Represents a description widget.
| ---- | ---- | ----------- |
| <a id="workitemwidgetdescriptiondescription"></a>`description` | [`String`](#string) | Description of the work item. |
| <a id="workitemwidgetdescriptiondescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
| <a id="workitemwidgetdescriptionedited"></a>`edited` | [`Boolean!`](#boolean) | Whether the description has been edited since the work item was created. |
| <a id="workitemwidgetdescriptionlasteditedat"></a>`lastEditedAt` | [`Time`](#time) | Timestamp of when the work item's description was last edited. |
| <a id="workitemwidgetdescriptionlasteditedby"></a>`lastEditedBy` | [`UserCore`](#usercore) | User that made the last edit to the work item's description. |
| <a id="workitemwidgetdescriptiontype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
### `WorkItemWidgetHierarchy`

View File

@ -18,7 +18,7 @@ For Free, Premium, and Ultimate plan customers, jobs on these instances consume
| | Small | Medium | Large |
|-------------------|---------------------------|---------------------------|--------------------------|
| Specs | 1 vCPU, 3.75GB RAM | 2 vCPUs, 8GB RAM | 4 vCPUs, 16GB RAM |
| GitLab CI/CD tags | `saas-linux-medium-amd64` | `saas-linux-medium-amd64` | `saas-linux-large-amd64` |
| GitLab CI/CD tags | `saas-linux-small-amd64` | `saas-linux-medium-amd64` | `saas-linux-large-amd64` |
| Subscription | Free, Premium, Ultimate | Free, Premium, Ultimate | Premium, Ultimate |
The `small` machine type is the default. Your job runs on this machine type if you don't specify

View File

@ -23,5 +23,9 @@ FactoryBot.define do
issue_type { :incident }
association :work_item_type, :default, :incident
end
trait :last_edited_by_user do
association :last_edited_by, factory: :user
end
end
end

View File

@ -28,8 +28,6 @@ RSpec.describe GitlabSchema.types['WorkItem'] do
closed_at
]
fields.each do |field_name|
expect(described_class).to have_graphql_fields(*fields)
end
expect(described_class).to have_graphql_fields(*fields)
end
end

View File

@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Types::WorkItems::Widgets::DescriptionType do
it 'exposes the expected fields' do
expected_fields = %i[description description_html type]
expected_fields = %i[description description_html edited last_edited_at last_edited_by type]
expect(described_class).to have_graphql_fields(*expected_fields)
end

View File

@ -3,7 +3,10 @@
require 'spec_helper'
RSpec.describe WorkItems::Widgets::Description do
let_it_be(:work_item) { create(:work_item, description: '# Title') }
let_it_be(:user) { create(:user) }
let_it_be(:work_item, refind: true) do
create(:work_item, description: 'Title', last_edited_at: 10.days.ago, last_edited_by: user)
end
describe '.type' do
subject { described_class.type }
@ -22,4 +25,42 @@ RSpec.describe WorkItems::Widgets::Description do
it { is_expected.to eq(work_item.description) }
end
describe '#edited?' do
subject { described_class.new(work_item).edited? }
it { is_expected.to be_truthy }
end
describe '#last_edited_at' do
subject { described_class.new(work_item).last_edited_at }
it { is_expected.to eq(work_item.last_edited_at) }
end
describe '#last_edited_by' do
subject { described_class.new(work_item).last_edited_by }
context 'when the work item is edited' do
context 'when last edited user still exists in the DB' do
it { is_expected.to eq(user) }
end
context 'when last edited user no longer exists' do
before do
work_item.update!(last_edited_by: nil)
end
it { is_expected.to eq(User.ghost) }
end
end
context 'when the work item is not edited yet' do
before do
work_item.update!(last_edited_at: nil)
end
it { is_expected.to be_nil }
end
end
end

View File

@ -10,7 +10,10 @@ RSpec.describe 'getting an work item list for a project' do
let_it_be(:current_user) { create(:user) }
let_it_be(:item1) { create(:work_item, project: project, discussion_locked: true, title: 'item1') }
let_it_be(:item2) { create(:work_item, project: project, title: 'item2') }
let_it_be(:item2) do
create(:work_item, project: project, title: 'item2', last_edited_by: current_user, last_edited_at: 1.day.ago)
end
let_it_be(:confidential_item) { create(:work_item, confidential: true, project: project, title: 'item3') }
let_it_be(:other_item) { create(:work_item) }
@ -75,6 +78,40 @@ RSpec.describe 'getting an work item list for a project' do
end
end
context 'when fetching description edit information' do
let(:fields) do
<<~GRAPHQL
nodes {
widgets {
type
... on WorkItemWidgetDescription {
edited
lastEditedAt
lastEditedBy {
webPath
username
}
}
}
}
GRAPHQL
end
it 'avoids N+1 queries' do
post_graphql(query, current_user: current_user) # warm-up
control = ActiveRecord::QueryRecorder.new do
post_graphql(query, current_user: current_user)
end
expect_graphql_errors_to_be_empty
create_list(:work_item, 3, :last_edited_by_user, last_edited_at: 1.week.ago, project: project)
expect_graphql_errors_to_be_empty
expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
end
end
context 'when filtering by search' do
it_behaves_like 'query with a search term' do
let(:issuable_data) { items_data }

View File

@ -14,7 +14,10 @@ RSpec.describe 'Query.work_item(id)' do
project: project,
description: '- List item',
start_date: Date.today,
due_date: 1.week.from_now
due_date: 1.week.from_now,
created_at: 1.week.ago,
last_edited_at: 1.day.ago,
last_edited_by: guest
)
end
@ -67,6 +70,12 @@ RSpec.describe 'Query.work_item(id)' do
... on WorkItemWidgetDescription {
description
descriptionHtml
edited
lastEditedBy {
webPath
username
}
lastEditedAt
}
}
GRAPHQL
@ -79,7 +88,13 @@ RSpec.describe 'Query.work_item(id)' do
hash_including(
'type' => 'DESCRIPTION',
'description' => work_item.description,
'descriptionHtml' => ::MarkupHelper.markdown_field(work_item, :description, {})
'descriptionHtml' => ::MarkupHelper.markdown_field(work_item, :description, {}),
'edited' => true,
'lastEditedAt' => work_item.last_edited_at.iso8601,
'lastEditedBy' => {
'webPath' => "/#{guest.full_path}",
'username' => guest.username
}
)
)
)