diff --git a/app/graphql/types/ci/code_quality_degradation_severity_enum.rb b/app/graphql/types/ci/code_quality_degradation_severity_enum.rb
new file mode 100644
index 0000000000000000000000000000000000000000..742ac9221988a75b1743859333259e62749fb250
--- /dev/null
+++ b/app/graphql/types/ci/code_quality_degradation_severity_enum.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ class CodeQualityDegradationSeverityEnum < BaseEnum
+ graphql_name 'CodeQualityDegradationSeverity'
+
+ ::Gitlab::Ci::Reports::CodequalityReports::SEVERITY_PRIORITIES.keys.each do |status|
+ value status.upcase,
+ description: "Code Quality degradation has a status of #{status}.",
+ value: status
+ end
+ end
+ end
+end
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 6aa1c50ded192603bc29d881fdf8af70667ed9ed..d37f045a95f9c8f61e5d0f32a80d91c67d6100aa 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -4688,6 +4688,30 @@ The edge type for [`CodeCoverageActivity`](#codecoverageactivity).
| `cursor` | [`String!`](#string) | A cursor for use in pagination. |
| `node` | [`CodeCoverageActivity`](#codecoverageactivity) | The item at the end of the edge. |
+#### `CodeQualityDegradationConnection`
+
+The connection type for [`CodeQualityDegradation`](#codequalitydegradation).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `count` | [`Int!`](#int) | Total count of collection. |
+| `edges` | [`[CodeQualityDegradationEdge]`](#codequalitydegradationedge) | A list of edges. |
+| `nodes` | [`[CodeQualityDegradation]`](#codequalitydegradation) | A list of nodes. |
+| `pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `CodeQualityDegradationEdge`
+
+The edge type for [`CodeQualityDegradation`](#codequalitydegradation).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| `node` | [`CodeQualityDegradation`](#codequalitydegradation) | The item at the end of the edge. |
+
#### `CommitConnection`
The connection type for [`Commit`](#commit).
@@ -7455,6 +7479,20 @@ Represents the code coverage summary for a project.
| `coverageCount` | [`Int`](#int) | Number of different code coverage results available. |
| `lastUpdatedOn` | [`Date`](#date) | Latest date when the code coverage was created for the project. |
+### `CodeQualityDegradation`
+
+Represents a code quality degradation on the pipeline.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `description` | [`String!`](#string) | A description of the code quality degradation. |
+| `fingerprint` | [`String!`](#string) | A unique fingerprint to identify the code quality degradation. For example, an MD5 hash. |
+| `line` | [`Int!`](#int) | The line on which the code quality degradation occurred. |
+| `path` | [`String!`](#string) | The relative path to the file containing the code quality degradation. |
+| `severity` | [`CodeQualityDegradationSeverity!`](#codequalitydegradationseverity) | Status of the degradation (BLOCKER, CRITICAL, MAJOR, MINOR, INFO). |
+
### `Commit`
#### Fields
@@ -10577,6 +10615,7 @@ Information about pagination in a connection.
| `active` | [`Boolean!`](#boolean) | Indicates if the pipeline is active. |
| `beforeSha` | [`String`](#string) | Base SHA of the source branch. |
| `cancelable` | [`Boolean!`](#boolean) | Specifies if a pipeline can be canceled. |
+| `codeQualityReports` | [`CodeQualityDegradationConnection`](#codequalitydegradationconnection) | Code Quality degradations reported on the pipeline. (see [Connections](#connections)) |
| `commitPath` | [`String`](#string) | Path to the commit that triggered the pipeline. |
| `committedAt` | [`Time`](#time) | Timestamp of the pipeline's commit. |
| `configSource` | [`PipelineConfigSourceEnum`](#pipelineconfigsourceenum) | Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE, COMPLIANCE_SOURCE). |
@@ -13551,6 +13590,16 @@ Values for YAML processor result.
| `INSTANCE_TYPE` | A runner that is instance type. |
| `PROJECT_TYPE` | A runner that is project type. |
+### `CodeQualityDegradationSeverity`
+
+| Value | Description |
+| ----- | ----------- |
+| `BLOCKER` | Code Quality degradation has a status of blocker. |
+| `CRITICAL` | Code Quality degradation has a status of critical. |
+| `INFO` | Code Quality degradation has a status of info. |
+| `MAJOR` | Code Quality degradation has a status of major. |
+| `MINOR` | Code Quality degradation has a status of minor. |
+
### `CommitActionMode`
Mode of a commit action.
diff --git a/ee/app/graphql/ee/types/ci/pipeline_type.rb b/ee/app/graphql/ee/types/ci/pipeline_type.rb
index f8bbfe1296eed9506d316e392074e2c288cb085b..2f489bc6e536e3874ca0947eb5813c18a1d9cdef 100644
--- a/ee/app/graphql/ee/types/ci/pipeline_type.rb
+++ b/ee/app/graphql/ee/types/ci/pipeline_type.rb
@@ -19,6 +19,15 @@ module PipelineType
null: true,
description: 'Vulnerability findings reported on the pipeline.',
resolver: ::Resolvers::PipelineSecurityReportFindingsResolver
+
+ field :code_quality_reports,
+ ::Types::Ci::CodeQualityDegradationType.connection_type,
+ null: true,
+ description: 'Code Quality degradations reported on the pipeline.'
+
+ def code_quality_reports
+ pipeline.codequality_reports.all_degradations.presence
+ end
end
end
end
diff --git a/ee/app/graphql/types/ci/code_quality_degradation_type.rb b/ee/app/graphql/types/ci/code_quality_degradation_type.rb
new file mode 100644
index 0000000000000000000000000000000000000000..519c38e53acaeb0fe6d42c9b2faf49817391e4de
--- /dev/null
+++ b/ee/app/graphql/types/ci/code_quality_degradation_type.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ # rubocop: disable Graphql/AuthorizeTypes
+ class CodeQualityDegradationType < BaseObject
+ graphql_name 'CodeQualityDegradation'
+ description 'Represents a code quality degradation on the pipeline.'
+
+ connection_type_class(Types::CountableConnectionType)
+
+ alias_method :degradation, :object
+
+ field :description, GraphQL::STRING_TYPE, null: false,
+ description: "A description of the code quality degradation."
+
+ field :fingerprint, GraphQL::STRING_TYPE, null: false,
+ description: 'A unique fingerprint to identify the code quality degradation. For example, an MD5 hash.'
+
+ field :severity, Types::Ci::CodeQualityDegradationSeverityEnum, null: false,
+ description: "Status of the degradation (#{::Gitlab::Ci::Reports::CodequalityReports::SEVERITY_PRIORITIES.keys.map(&:upcase).join(', ')})."
+
+ field :path, GraphQL::STRING_TYPE, null: false,
+ description: 'The relative path to the file containing the code quality degradation.'
+
+ def path
+ degradation.dig(:location, :path)
+ end
+
+ field :line, GraphQL::INT_TYPE, null: false,
+ description: 'The line on which the code quality degradation occurred.'
+
+ def line
+ degradation.dig(:location, :lines, :begin) || degradation.dig(:location, :positions, :begin, :line)
+ end
+ end
+ end
+end
diff --git a/ee/changelogs/unreleased/mo-add-codequality-to-graphql.yml b/ee/changelogs/unreleased/mo-add-codequality-to-graphql.yml
new file mode 100644
index 0000000000000000000000000000000000000000..48d4931350f7028d0517384de0effa760d192d44
--- /dev/null
+++ b/ee/changelogs/unreleased/mo-add-codequality-to-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Add codequality reports endpoint to graphql
+merge_request: 61383
+author:
+type: added
diff --git a/ee/spec/graphql/types/ci/code_quality_degradation_severity_enum_spec.rb b/ee/spec/graphql/types/ci/code_quality_degradation_severity_enum_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..875f0b8af1e4a0152a1f14b63ca2af998ebb17e3
--- /dev/null
+++ b/ee/spec/graphql/types/ci/code_quality_degradation_severity_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CodeQualityDegradationSeverity'] do
+ it 'exposes all code quality degradation severity types' do
+ expect(described_class.values.keys).to eq(
+ ::Gitlab::Ci::Reports::CodequalityReports::SEVERITY_PRIORITIES.keys.map(&:upcase)
+ )
+ end
+end
diff --git a/ee/spec/graphql/types/ci/code_quality_degradation_type_spec.rb b/ee/spec/graphql/types/ci/code_quality_degradation_type_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fbc809ac25ff7f94698eafc3ecbb82f58e2948f8
--- /dev/null
+++ b/ee/spec/graphql/types/ci/code_quality_degradation_type_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CodeQualityDegradation'] do
+ it do
+ expect(described_class).to have_graphql_fields(
+ :description,
+ :fingerprint,
+ :severity,
+ :path,
+ :line
+ )
+ end
+end
diff --git a/ee/spec/graphql/types/ci/pipeline_type_spec.rb b/ee/spec/graphql/types/ci/pipeline_type_spec.rb
index d29037ad1ee73ff715c5c634a5c99e4fdff99e0a..abd372733badcdad51429990ff988524f3acdbf0 100644
--- a/ee/spec/graphql/types/ci/pipeline_type_spec.rb
+++ b/ee/spec/graphql/types/ci/pipeline_type_spec.rb
@@ -9,6 +9,7 @@
expected_fields = %w[
security_report_summary
security_report_findings
+ code_quality_reports
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/ee/spec/requests/api/graphql/project/pipeline/code_quality_reports_spec.rb b/ee/spec/requests/api/graphql/project/pipeline/code_quality_reports_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c09bec5d118f2ebf28ab88bfa189c72ff760df08
--- /dev/null
+++ b/ee/spec/requests/api/graphql/project/pipeline/code_quality_reports_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Query.project(fullPath).pipeline(iid).codeQualityReports' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:current_user) { create(:user) }
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ pipeline(iid: "#{pipeline.iid}") {
+ codeQualityReports {
+ nodes {
+ #{all_graphql_fields_for('CodeQualityDegradation')}
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ let(:codequality_degradations) { graphql_data_at(:project, :pipeline, :codeQualityReports, :nodes) }
+
+ context 'when pipeline has a code quality report' do
+ let_it_be(:pipeline) { create(:ci_pipeline, :success, :with_codequality_reports, project: project) }
+
+ context 'when user is member of the project' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'returns all the code quality degradations' do
+ post_graphql(query, current_user: current_user)
+
+ expect(codequality_degradations.size).to eq(3)
+ end
+
+ it 'returns all the queried fields', :aggregate_failures do
+ post_graphql(query, current_user: current_user)
+
+ codequality_degradations.each do |degradation|
+ expect(degradation['description']).not_to be_nil
+ expect(degradation['fingerprint']).not_to be_nil
+ expect(degradation['severity']).not_to be_nil
+ expect(degradation['path']).not_to be_nil
+ expect(degradation['line']).not_to be_nil
+ end
+ end
+ end
+
+ context 'when user is not a member of the project' do
+ it 'returns no code quality degradations' do
+ post_graphql(query, current_user: current_user)
+
+ expect(codequality_degradations).to be_nil
+ end
+ end
+ end
+
+ context 'when pipeline does not have a code quality report' do
+ let_it_be(:pipeline) { create(:ci_pipeline, :success, project: project) }
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'returns an empty result' do
+ post_graphql(query, current_user: current_user)
+
+ expect(codequality_degradations).to be_nil
+ end
+ end
+end
diff --git a/spec/graphql/types/ci/pipeline_type_spec.rb b/spec/graphql/types/ci/pipeline_type_spec.rb
index 45d2748a23513b27206205916b3248c67c003261..c67e86a7ee111008000c870c6012b774668b05d1 100644
--- a/spec/graphql/types/ci/pipeline_type_spec.rb
+++ b/spec/graphql/types/ci/pipeline_type_spec.rb
@@ -18,7 +18,7 @@
]
if Gitlab.ee?
- expected_fields += %w[security_report_summary security_report_findings]
+ expected_fields += %w[security_report_summary security_report_findings code_quality_reports]
end
expect(described_class).to have_graphql_fields(*expected_fields)