diff --git a/app/graphql/resolvers/ci/all_jobs_resolver.rb b/app/graphql/resolvers/ci/all_jobs_resolver.rb index 8e9a1deb5419fd2a9f7f994cb0adde7bdfa3579d..54dd435d617d8f82c0f10140103fd95bb387c870 100644 --- a/app/graphql/resolvers/ci/all_jobs_resolver.rb +++ b/app/graphql/resolvers/ci/all_jobs_resolver.rb @@ -39,9 +39,18 @@ def preloads browse_artifacts_path: [{ project: { namespace: [:route] } }], play_path: [{ project: { namespace: [:route] } }], web_path: [{ project: { namespace: [:route] } }], - tags: [:tags] + tags: [:tags], + trace: [{ project: [:namespace] }, :job_artifacts_trace] } end + + def nested_preloads + super.merge({ + trace: { + html_summary: [:trace_chunks] + } + }) + end end end end diff --git a/app/graphql/resolvers/ci/runner_jobs_resolver.rb b/app/graphql/resolvers/ci/runner_jobs_resolver.rb index 39908d8fd11332bb6c07a6585e71a281da3d689a..c0a5057cddd070627fc726eb2000267c6066b647 100644 --- a/app/graphql/resolvers/ci/runner_jobs_resolver.rb +++ b/app/graphql/resolvers/ci/runner_jobs_resolver.rb @@ -44,9 +44,18 @@ def preloads play_path: [{ project: { namespace: [:route] } }], web_path: [{ project: { namespace: [:route] } }], short_sha: [:pipeline], - tags: [:tags] + tags: [:tags], + trace: [{ project: [:namespace] }, :job_artifacts_trace] } end + + def nested_preloads + super.merge({ + trace: { + html_summary: [:trace_chunks] + } + }) + end end end end diff --git a/app/graphql/types/ci/job_trace_type.rb b/app/graphql/types/ci/job_trace_type.rb index a68e26106b8687938ac247b1f1a707a1236e7797..b959d37f3272949ff14d7d61709f4cc01e199513 100644 --- a/app/graphql/types/ci/job_trace_type.rb +++ b/app/graphql/types/ci/job_trace_type.rb @@ -7,11 +7,15 @@ class JobTraceType < BaseObject graphql_name 'CiJobTrace' field :html_summary, GraphQL::Types::String, null: false, - alpha: { milestone: '15.11' }, # As we want the option to change from 10 if needed - description: "HTML summary containing the last 10 lines of the trace." + alpha: { milestone: '15.11' }, + description: 'HTML summary that contains the tail lines of the trace.' do + argument :last_lines, Integer, + required: false, default_value: 10, + description: 'Number of tail lines to return, up to a maximum of 100 lines.' + end - def html_summary - object.html(last_lines: 10).html_safe + def html_summary(last_lines:) + object.html(last_lines: last_lines.clamp(1, 100)).html_safe end end end diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 49bb9fdbefd021e4ddb9ce434271edcc133c0b59..a1fc29747439afe215891912941421fe4b35be4a 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -13866,11 +13866,23 @@ CI/CD variables for a GitLab instance. ### `CiJobTrace` -#### Fields +#### Fields with arguments + +##### `CiJobTrace.htmlSummary` + +HTML summary that contains the tail lines of the trace. + +WARNING: +**Introduced** in 15.11. +This feature is an Experiment. It can be changed or removed at any time. + +Returns [`String!`](#string). + +###### Arguments | Name | Type | Description | | ---- | ---- | ----------- | -| `htmlSummary` **{warning-solid}** | [`String!`](#string) | **Introduced** in 15.11. This feature is an Experiment. It can be changed or removed at any time. HTML summary containing the last 10 lines of the trace. | +| `lastLines` | [`Int`](#int) | Number of tail lines to return, up to a maximum of 100 lines. | ### `CiJobsDurationStatistics` diff --git a/spec/graphql/types/ci/job_trace_type_spec.rb b/spec/graphql/types/ci/job_trace_type_spec.rb index 71803aa9ece3f96ada5ff9cabaec2c834abba641..5f4f3097ace7920377359af59b3da540d04c3110 100644 --- a/spec/graphql/types/ci/job_trace_type_spec.rb +++ b/spec/graphql/types/ci/job_trace_type_spec.rb @@ -13,15 +13,83 @@ expect(described_class).to have_graphql_fields(*expected_fields) end - it 'shows the correct trace contents' do - job.trace.set('BUILD TRACE') + describe 'htmlSummary' do + subject(:resolved_field) { resolve_field(:html_summary, job.trace, args: args) } - expect_next_instance_of(Gitlab::Ci::Trace) do |trace| - expect(trace).to receive(:html).with(last_lines: 10).and_call_original + context 'when trace contains few lines' do + before do + job.trace.set('BUILD TRACE') + end + + context 'when last_lines is set to 10' do + let(:args) { { last_lines: 10 } } + + it 'shows the correct trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10).and_call_original + end + + is_expected.to eq('BUILD TRACE') + end + end end - resolved_field = resolve_field(:html_summary, job.trace) + context 'when trace contains many lines' do + before do + job.trace.set((1..200).map { |i| "Line #{i}" }.join("\n")) + end + + def expected_html_trace_contents(line_count) + "#{((200 - (line_count - 1))..200).map { |i| "Line #{i}" }.join('
')}
" + end + + context 'when last_lines is not set' do + let(:args) { {} } + + it 'shows the last 10 lines of trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10).and_call_original + end + + is_expected.to eq expected_html_trace_contents(10) + end + end + + context 'when last_lines is set to a negative number' do + let(:args) { { last_lines: -10 } } - expect(resolved_field).to eq("BUILD TRACE") + it 'shows the last line of trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 1).and_call_original + end + + is_expected.to eq expected_html_trace_contents(1) + end + end + + context 'when last_lines is set to 10' do + let(:args) { { last_lines: 10 } } + + it 'shows the correct trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 10).and_call_original + end + + is_expected.to eq expected_html_trace_contents(10) + end + end + + context 'when last_lines is set to 150' do + let(:args) { { last_lines: 150 } } + + it 'shows the last 100 lines of trace contents' do + expect_next_instance_of(Gitlab::Ci::Trace) do |trace| + expect(trace).to receive(:html).with(last_lines: 100).and_call_original + end + + is_expected.to eq expected_html_trace_contents(100) + end + end + end end end