diff --git a/app/finders/ci/runners_finder.rb b/app/finders/ci/runners_finder.rb index 4c4bd3fc5a62cd32de5ed496f805ba613624d7ee..356915722fe3add6f58fc3fa101f35402ad6ff87 100644 --- a/app/finders/ci/runners_finder.rb +++ b/app/finders/ci/runners_finder.rb @@ -4,7 +4,7 @@ module Ci class RunnersFinder < UnionFinder include Gitlab::Allowable - ALLOWED_SORTS = %w[contacted_asc contacted_desc created_at_asc created_at_desc created_date].freeze + ALLOWED_SORTS = %w[contacted_asc contacted_desc created_at_asc created_at_desc created_date token_expires_at_asc token_expires_at_desc].freeze DEFAULT_SORT = 'created_at_desc' def initialize(current_user:, params:) diff --git a/app/graphql/types/ci/runner_sort_enum.rb b/app/graphql/types/ci/runner_sort_enum.rb index 95ec1867fea8c883ed24cf706a597d3a9709b955..8f2a13bd69995a347b5fed4fc0ccf3161c572b97 100644 --- a/app/graphql/types/ci/runner_sort_enum.rb +++ b/app/graphql/types/ci/runner_sort_enum.rb @@ -10,6 +10,8 @@ class RunnerSortEnum < BaseEnum value 'CONTACTED_DESC', 'Ordered by contacted_at in descending order.', value: :contacted_desc value 'CREATED_ASC', 'Ordered by created_at in ascending order.', value: :created_at_asc value 'CREATED_DESC', 'Ordered by created_at in descending order.', value: :created_at_desc + value 'TOKEN_EXPIRES_AT_ASC', 'Ordered by token_expires_at in ascending order.', value: :token_expires_at_asc + value 'TOKEN_EXPIRES_AT_DESC', 'Ordered by token_expires_at in descending order.', value: :token_expires_at_desc end end end diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index f3b7b067c93535a13a974aa8145282fc6cdfa7be..9094c6b96e470b69ee671c0aedc30a56baebcc8d 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -25,6 +25,9 @@ class RunnerType < BaseObject field :contacted_at, Types::TimeType, null: true, description: 'Timestamp of last contact from this runner.', method: :contacted_at + field :token_expires_at, Types::TimeType, null: true, + description: 'Runner token expiration time.', + method: :token_expires_at field :maximum_timeout, GraphQL::Types::Int, null: true, description: 'Maximum timeout (in seconds) for jobs processed by the runner.' field :access_level, ::Types::Ci::RunnerAccessLevelEnum, null: false, diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index bb12816e0fe176090b3d6573d092de3f88b656d3..24cde068619f70d000b401fd923bdb8dcbf1327c 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -9201,6 +9201,7 @@ Represents the total number of issues and their weights for a particular day. | `runnerType` | [`CiRunnerType!`](#cirunnertype) | Type of the runner. | | `shortSha` | [`String`](#string) | First eight characters of the runner's token used to authenticate new job requests. Used as the runner's unique ID. | | `tagList` | [`[String!]`](#string) | Tags associated with the runner. | +| `tokenExpiresAt` | [`Time`](#time) | Runner token expiration time. | | `userPermissions` | [`RunnerPermissions!`](#runnerpermissions) | Permissions for the current user on the resource. | | `version` | [`String`](#string) | Version of the runner. | @@ -16796,6 +16797,8 @@ Values for sorting runners. | `CONTACTED_DESC` | Ordered by contacted_at in descending order. | | `CREATED_ASC` | Ordered by created_at in ascending order. | | `CREATED_DESC` | Ordered by created_at in descending order. | +| `TOKEN_EXPIRES_AT_ASC` | Ordered by token_expires_at in ascending order. | +| `TOKEN_EXPIRES_AT_DESC` | Ordered by token_expires_at in descending order. | ### `CiRunnerStatus` diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb index 6665b7b76a0ce76436e51df919a2469b42bdb6a0..180264122617323c1c1b4c68733089f5b472f883 100644 --- a/spec/factories/ci/runners.rb +++ b/spec/factories/ci/runners.rb @@ -13,6 +13,7 @@ transient do groups { [] } projects { [] } + token_expires_at { nil } end after(:build) do |runner, evaluator| @@ -25,6 +26,10 @@ end end + after(:create) do |runner, evaluator| + runner.update!(token_expires_at: evaluator.token_expires_at) if evaluator.token_expires_at + end + trait :online do contacted_at { Time.now } end diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb index 7e3c1abd6d1e94fab3624b5be75d1cb254afe8c6..e7ec4f019959d8963e553b377691c2acc94ef75c 100644 --- a/spec/finders/ci/runners_finder_spec.rb +++ b/spec/finders/ci/runners_finder_spec.rb @@ -91,8 +91,8 @@ end context 'sorting' do - let_it_be(:runner1) { create :ci_runner, created_at: '2018-07-12 07:00', contacted_at: 1.minute.ago } - let_it_be(:runner2) { create :ci_runner, created_at: '2018-07-12 08:00', contacted_at: 3.minutes.ago } + let_it_be(:runner1) { create :ci_runner, created_at: '2018-07-12 07:00', contacted_at: 1.minute.ago, token_expires_at: '2022-02-15 07:00' } + let_it_be(:runner2) { create :ci_runner, created_at: '2018-07-12 08:00', contacted_at: 3.minutes.ago, token_expires_at: '2022-02-15 06:00' } let_it_be(:runner3) { create :ci_runner, created_at: '2018-07-12 09:00', contacted_at: 2.minutes.ago } subject do @@ -142,6 +142,22 @@ is_expected.to eq [runner1, runner3, runner2] end end + + context 'with sort param equal to token_expires_at_asc' do + let(:params) { { sort: 'token_expires_at_asc' } } + + it 'sorts by contacted_at ascending' do + is_expected.to eq [runner2, runner1, runner3] + end + end + + context 'with sort param equal to token_expires_at_desc' do + let(:params) { { sort: 'token_expires_at_desc' } } + + it 'sorts by contacted_at descending' do + is_expected.to eq [runner3, runner1, runner2] + end + end end context 'by non admin user' do diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb index 77eac658c1984e4a320974f1f74d44672d8021e2..7697cd0ef7924d851435dc1d72fba7bd4b726850 100644 --- a/spec/graphql/types/ci/runner_type_spec.rb +++ b/spec/graphql/types/ci/runner_type_spec.rb @@ -12,7 +12,7 @@ id description created_at contacted_at maximum_timeout access_level active paused status version short_sha revision locked run_untagged ip_address runner_type tag_list project_count job_count admin_url edit_admin_url user_permissions executor_name - groups projects jobs + groups projects jobs token_expires_at ] expect(described_class).to include_graphql_fields(*expected_fields)