From 42f76ca8db5e8fbc76907cdbcce3617b4ea6c1a8 Mon Sep 17 00:00:00 2001
From: Pedro Pombeiro <noreply@pedro.pombei.ro>
Date: Thu, 3 Oct 2024 20:59:02 +0000
Subject: [PATCH] GraphQL: Deprecate CiRunnerUsage.ciUsedMinutes in favor of
 ciDuration

Changelog: deprecated
---
 ...-5-deprecate-ciUsedMinutes-graphql-field.yml | 17 +++++++++++++++++
 doc/api/graphql/reference/index.md              |  5 +++--
 doc/update/deprecations.md                      | 17 +++++++++++++++++
 ee/app/graphql/types/ci/runner_usage_type.rb    | 11 +++++++++--
 .../graphql/ci/runner_usage_by_project_spec.rb  | 10 ++++++++++
 .../api/graphql/ci/runner_usage_spec.rb         | 10 ++++++++++
 6 files changed, 66 insertions(+), 4 deletions(-)
 create mode 100644 data/deprecations/17-5-deprecate-ciUsedMinutes-graphql-field.yml

diff --git a/data/deprecations/17-5-deprecate-ciUsedMinutes-graphql-field.yml b/data/deprecations/17-5-deprecate-ciUsedMinutes-graphql-field.yml
new file mode 100644
index 0000000000000..6994ed6f16fe2
--- /dev/null
+++ b/data/deprecations/17-5-deprecate-ciUsedMinutes-graphql-field.yml
@@ -0,0 +1,17 @@
+- title: '`ciUsedMinutes` GraphQL field renamed to `ciDuration`'
+  removal_milestone: '18.0'
+  announcement_milestone: '17.5'
+  breaking_change: true
+  reporter: pedropombeiro
+  stage: verify
+  issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/497364
+  impact: medium
+  scope: instance
+  resolution_role: Admin
+  manual_task: true
+  body: |
+    The `ciDuration` field of the `CiRunnerUsage` and `CiRunnerUsageByProject` types replaces the former `ciUsedMinutes` field.
+    Update all references to `ciUsedMinutes` from these types to `ciDuration`.
+
+  tiers: Ultimate
+  documentation_url: https://docs.gitlab.com/ee/api/graphql/reference/#cirunnerusage
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 1b5f60cb38215..ba4370c63d83f 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -19607,8 +19607,9 @@ Runner usage.
 
 | Name | Type | Description |
 | ---- | ---- | ----------- |
-| <a id="cirunnerusagecibuildcount"></a>`ciBuildCount` | [`BigInt!`](#bigint) | Amount of builds executed during the selected period, encoded as a string. |
-| <a id="cirunnerusageciminutesused"></a>`ciMinutesUsed` | [`BigInt!`](#bigint) | Amount of minutes used during the selected period, encoded as a string. |
+| <a id="cirunnerusagecibuildcount"></a>`ciBuildCount` | [`BigInt!`](#bigint) | Amount of builds executed during the selected period. Encoded as a string. |
+| <a id="cirunnerusageciduration"></a>`ciDuration` | [`BigInt!`](#bigint) | Number of minutes spent to process jobs during the selected period. Encoded as a string. |
+| <a id="cirunnerusageciminutesused"></a>`ciMinutesUsed` **{warning-solid}** | [`BigInt!`](#bigint) | **Deprecated** in GitLab 17.5. Use `ciDuration`. |
 | <a id="cirunnerusagerunner"></a>`runner` | [`CiRunner`](#cirunner) | Runner that the usage refers to. Null means "Other runners". |
 
 ### `CiRunnerUsageByProject`
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index f0ee8c34a0916..b3ba139f1941c 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -943,6 +943,23 @@ With the [upcoming default behavior change to the CI/CD job token](https://docs.
 
 <div class="deprecation breaking-change" data-milestone="18.0">
 
+### `ciUsedMinutes` GraphQL field renamed to `ciDuration`
+
+<div class="deprecation-notes">
+
+- Announced in GitLab <span class="milestone">17.5</span>
+- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/497364).
+
+</div>
+
+The `ciDuration` field of the `CiRunnerUsage` and `CiRunnerUsageByProject` types replaces the former `ciUsedMinutes` field.
+Update all references to `ciUsedMinutes` from these types to `ciDuration`.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="18.0">
+
 ### `require_password_to_approve` field
 
 <div class="deprecation-notes">
diff --git a/ee/app/graphql/types/ci/runner_usage_type.rb b/ee/app/graphql/types/ci/runner_usage_type.rb
index 7e1553956b152..b240951cce07d 100644
--- a/ee/app/graphql/types/ci/runner_usage_type.rb
+++ b/ee/app/graphql/types/ci/runner_usage_type.rb
@@ -10,11 +10,18 @@ class RunnerUsageType < BaseObject
       field :runner, ::Types::Ci::RunnerType,
         null: true, description: 'Runner that the usage refers to. Null means "Other runners".'
 
+      field :ci_duration, GraphQL::Types::BigInt,
+        null: false,
+        description: 'Number of minutes spent to process jobs during the selected period. Encoded as a string.',
+        hash_key: :ci_minutes_used
+
+      # TODO: Remove in 18.0. For more details read https://gitlab.com/gitlab-org/gitlab/-/issues/497364
       field :ci_minutes_used, GraphQL::Types::BigInt,
-        null: false, description: 'Amount of minutes used during the selected period, encoded as a string.'
+        null: false, description: 'Amount of minutes used during the selected period. Encoded as a string.',
+        deprecated: { reason: 'Use `ciDuration`', milestone: '17.5' }
 
       field :ci_build_count, GraphQL::Types::BigInt,
-        null: false, description: 'Amount of builds executed during the selected period, encoded as a string.'
+        null: false, description: 'Amount of builds executed during the selected period. Encoded as a string.'
 
       def runner
         return unless object[:runner_id]
diff --git a/ee/spec/requests/api/graphql/ci/runner_usage_by_project_spec.rb b/ee/spec/requests/api/graphql/ci/runner_usage_by_project_spec.rb
index 50eb453920c39..4a1f3db55abc0 100644
--- a/ee/spec/requests/api/graphql/ci/runner_usage_by_project_spec.rb
+++ b/ee/spec/requests/api/graphql/ci/runner_usage_by_project_spec.rb
@@ -42,6 +42,7 @@
         name
         fullPath
       }
+      ciDuration
       ciMinutesUsed
       ciBuildCount
     QUERY
@@ -137,11 +138,13 @@
       expected_result = top_projects.flat_map.with_index(1) do |project, index|
         {
           'project' => a_graphql_entity_for(project, :name, :full_path),
+          'ciDuration' => (20 * index).to_s,
           'ciMinutesUsed' => (20 * index).to_s,
           'ciBuildCount' => index.to_s
         }
       end.reverse + [{
         'project' => nil,
+        'ciDuration' => (other_projects.count * 3 * 2).to_s,
         'ciMinutesUsed' => (other_projects.count * 3 * 2).to_s,
         'ciBuildCount' => (other_projects.count * 3).to_s
       }]
@@ -166,6 +169,7 @@
 
       expect(runner_usage_by_project).to contain_exactly({
         'project' => a_graphql_entity_for(project, :name, :full_path),
+        'ciDuration' => '5',
         'ciMinutesUsed' => '5',
         'ciBuildCount' => '2'
       })
@@ -200,6 +204,7 @@
 
         expect(runner_usage_by_project).to contain_exactly({
           'project' => a_graphql_entity_for(project, :name, :full_path),
+          'ciDuration' => '5',
           'ciMinutesUsed' => '5',
           'ciBuildCount' => '2'
         })
@@ -219,6 +224,7 @@
 
         expect(runner_usage_by_project).to contain_exactly({
           'project' => a_graphql_entity_for(project, :name, :full_path),
+          'ciDuration' => '33',
           'ciMinutesUsed' => '33',
           'ciBuildCount' => '1'
         })
@@ -325,6 +331,7 @@
           it "returns only group's projects" do
             expect(runner_usage_by_project).to contain_exactly({
               'project' => a_graphql_entity_for(project, :name, :full_path),
+              'ciDuration' => '21',
               'ciMinutesUsed' => '21',
               'ciBuildCount' => '1'
             })
@@ -337,6 +344,7 @@
           it "returns only group2's projects" do
             expect(runner_usage_by_project).to contain_exactly({
               'project' => a_graphql_entity_for(project2, :name, :full_path),
+              'ciDuration' => '33',
               'ciMinutesUsed' => '33',
               'ciBuildCount' => '1'
             })
@@ -376,6 +384,7 @@
           it "returns only stats referring to project" do
             expect(runner_usage_by_project).to contain_exactly({
               'project' => a_graphql_entity_for(project, :name, :full_path),
+              'ciDuration' => '21',
               'ciMinutesUsed' => '21',
               'ciBuildCount' => '1'
             })
@@ -388,6 +397,7 @@
           it "returns only stats referring to project2" do
             expect(runner_usage_by_project).to contain_exactly({
               'project' => a_graphql_entity_for(project2, :name, :full_path),
+              'ciDuration' => '33',
               'ciMinutesUsed' => '33',
               'ciBuildCount' => '1'
             })
diff --git a/ee/spec/requests/api/graphql/ci/runner_usage_spec.rb b/ee/spec/requests/api/graphql/ci/runner_usage_spec.rb
index f7866651c58be..95280a2cd9a59 100644
--- a/ee/spec/requests/api/graphql/ci/runner_usage_spec.rb
+++ b/ee/spec/requests/api/graphql/ci/runner_usage_spec.rb
@@ -41,6 +41,7 @@
         id
         description
       }
+      ciDuration
       ciMinutesUsed
       ciBuildCount
     QUERY
@@ -118,12 +119,14 @@
       expected_result = top_runners.flat_map.with_index(1) do |runner, index|
         {
           'runner' => a_graphql_entity_for(runner, :description),
+          'ciDuration' => (20 * index).to_s,
           'ciMinutesUsed' => (20 * index).to_s,
           'ciBuildCount' => index.to_s
         }
       end.reverse + [
         {
           'runner' => nil,
+          'ciDuration' => (other_runners.count * 3 * 2).to_s,
           'ciMinutesUsed' => (other_runners.count * 3 * 2).to_s,
           'ciBuildCount' => (other_runners.count * 3).to_s
         }
@@ -167,6 +170,7 @@
 
       expect(runner_usage).to contain_exactly({
         'runner' => a_graphql_entity_for(instance_runners.first, :description),
+        'ciDuration' => '5',
         'ciMinutesUsed' => '5',
         'ciBuildCount' => '2'
       })
@@ -196,6 +200,7 @@
 
         expect(runner_usage).to contain_exactly({
           'runner' => a_graphql_entity_for(instance_runners.first, :description),
+          'ciDuration' => '5',
           'ciMinutesUsed' => '5',
           'ciBuildCount' => '2'
         })
@@ -215,6 +220,7 @@
 
         expect(runner_usage).to contain_exactly({
           'runner' => a_graphql_entity_for(group1_runners.first, :description),
+          'ciDuration' => '33',
           'ciMinutesUsed' => '33',
           'ciBuildCount' => '1'
         })
@@ -309,6 +315,7 @@
           it "returns only group1's runners" do
             expect(runner_usage).to contain_exactly({
               'runner' => a_graphql_entity_for(group1_runners.first, :description),
+              'ciDuration' => '21',
               'ciMinutesUsed' => '21',
               'ciBuildCount' => '1'
             })
@@ -321,6 +328,7 @@
           it "returns only group2's runners" do
             expect(runner_usage).to contain_exactly({
               'runner' => a_graphql_entity_for(group2_runner, :description),
+              'ciDuration' => '33',
               'ciMinutesUsed' => '33',
               'ciBuildCount' => '1'
             })
@@ -380,6 +388,7 @@
           it "returns only stats referring to project" do
             expect(runner_usage).to contain_exactly({
               'runner' => a_graphql_entity_for(group1_runners.first, :description),
+              'ciDuration' => '21',
               'ciMinutesUsed' => '21',
               'ciBuildCount' => '1'
             })
@@ -392,6 +401,7 @@
           it "returns only stats referring to project2" do
             expect(runner_usage).to contain_exactly({
               'runner' => a_graphql_entity_for(group1_runners.second, :description),
+              'ciDuration' => '33',
               'ciMinutesUsed' => '33',
               'ciBuildCount' => '1'
             })
-- 
GitLab