diff options
Diffstat (limited to 'app/graphql/types/ci')
-rw-r--r-- | app/graphql/types/ci/config_variable_type.rb | 1 | ||||
-rw-r--r-- | app/graphql/types/ci/freeze_period_status_enum.rb | 13 | ||||
-rw-r--r-- | app/graphql/types/ci/freeze_period_type.rb | 41 | ||||
-rw-r--r-- | app/graphql/types/ci/pipeline_schedule_type.rb | 46 | ||||
-rw-r--r-- | app/graphql/types/ci/pipeline_schedule_variable_type.rb | 13 | ||||
-rw-r--r-- | app/graphql/types/ci/pipeline_type.rb | 2 | ||||
-rw-r--r-- | app/graphql/types/ci/runner_job_execution_status_enum.rb | 19 | ||||
-rw-r--r-- | app/graphql/types/ci/runner_type.rb | 93 |
8 files changed, 176 insertions, 52 deletions
diff --git a/app/graphql/types/ci/config_variable_type.rb b/app/graphql/types/ci/config_variable_type.rb index 5b5890fd5a5..020af5b2444 100644 --- a/app/graphql/types/ci/config_variable_type.rb +++ b/app/graphql/types/ci/config_variable_type.rb @@ -19,6 +19,7 @@ module Types description: 'Value of the variable.' field :value_options, [GraphQL::Types::String], + hash_key: :options, null: true, description: 'Value options for the variable.' end diff --git a/app/graphql/types/ci/freeze_period_status_enum.rb b/app/graphql/types/ci/freeze_period_status_enum.rb new file mode 100644 index 00000000000..aebd0f537e9 --- /dev/null +++ b/app/graphql/types/ci/freeze_period_status_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module Ci + class FreezePeriodStatusEnum < BaseEnum + graphql_name 'CiFreezePeriodStatus' + description 'Deploy freeze period status' + + value 'ACTIVE', value: :active, description: 'Freeze period is active.' + value 'INACTIVE', value: :inactive, description: 'Freeze period is inactive.' + end + end +end diff --git a/app/graphql/types/ci/freeze_period_type.rb b/app/graphql/types/ci/freeze_period_type.rb new file mode 100644 index 00000000000..6a3f2ed8fa4 --- /dev/null +++ b/app/graphql/types/ci/freeze_period_type.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Types + module Ci + class FreezePeriodType < BaseObject + graphql_name 'CiFreezePeriod' + description 'Represents a deployment freeze window of a project' + + authorize :read_freeze_period + + present_using ::Ci::FreezePeriodPresenter + + field :status, Types::Ci::FreezePeriodStatusEnum, + description: 'Freeze period status.', + null: false + + field :start_cron, GraphQL::Types::String, + description: 'Start of the freeze period in cron format.', + null: false, + method: :freeze_start + + field :end_cron, GraphQL::Types::String, + description: 'End of the freeze period in cron format.', + null: false, + method: :freeze_end + + field :cron_timezone, GraphQL::Types::String, + description: 'Time zone for the cron fields, defaults to UTC if not provided.', + null: true + + field :start_time, Types::TimeType, + description: 'Timestamp (UTC) of when the current/next active period starts.', + null: true + + field :end_time, Types::TimeType, + description: 'Timestamp (UTC) of when the current/next active period ends.', + null: true, + method: :time_end_from_now + end + end +end diff --git a/app/graphql/types/ci/pipeline_schedule_type.rb b/app/graphql/types/ci/pipeline_schedule_type.rb index 04f9fc78a92..904fa3f1c72 100644 --- a/app/graphql/types/ci/pipeline_schedule_type.rb +++ b/app/graphql/types/ci/pipeline_schedule_type.rb @@ -5,6 +5,8 @@ module Types class PipelineScheduleType < BaseObject graphql_name 'PipelineSchedule' + description 'Represents a pipeline schedule' + connection_type_class(Types::CountableConnectionType) expose_permissions Types::PermissionTypes::Ci::PipelineSchedules @@ -17,7 +19,9 @@ module Types field :owner, ::Types::UserType, null: false, description: 'Owner of the pipeline schedule.' - field :active, GraphQL::Types::Boolean, null: false, description: 'Indicates if a pipeline schedule is active.' + field :active, GraphQL::Types::Boolean, null: false, description: 'Indicates if the pipeline schedule is active.' + + field :project, ::Types::ProjectType, null: true, description: 'Project of the pipeline schedule.' field :next_run_at, Types::TimeType, null: false, description: 'Time when the next pipeline will run.' @@ -26,20 +30,50 @@ module Types field :last_pipeline, PipelineType, null: true, description: 'Last pipeline object.' field :ref_for_display, GraphQL::Types::String, - null: true, description: 'Git ref for the pipeline schedule.', method: :ref_for_display - - field :ref_path, GraphQL::Types::String, null: true, description: 'Path to the ref that triggered the pipeline.' + null: true, description: 'Git ref for the pipeline schedule.' field :for_tag, GraphQL::Types::Boolean, null: false, description: 'Indicates if a pipelines schedule belongs to a tag.', method: :for_tag? - field :cron, GraphQL::Types::String, null: false, description: 'Cron notation for the schedule.' + field :edit_path, GraphQL::Types::String, + null: true, + description: 'Edit path of the pipeline schedule.', + authorize: :update_pipeline_schedule + + field :variables, + Types::Ci::PipelineScheduleVariableType.connection_type, + null: true, + description: 'Pipeline schedule variables.', + authorize: :read_pipeline_schedule_variables + + field :ref, GraphQL::Types::String, + null: true, description: 'Ref of the pipeline schedule.', method: :ref_for_display + + field :ref_path, GraphQL::Types::String, + null: true, + description: 'Path to the ref that triggered the pipeline.' - field :cron_timezone, GraphQL::Types::String, null: false, description: 'Timezone for the pipeline schedule.' + field :cron, GraphQL::Types::String, + null: false, + description: 'Cron notation for the schedule.' + + field :cron_timezone, GraphQL::Types::String, + null: false, + description: 'Timezone for the pipeline schedule.' + + field :created_at, Types::TimeType, + null: false, description: 'Timestamp of when the pipeline schedule was created.' + + field :updated_at, Types::TimeType, + null: false, description: 'Timestamp of when the pipeline schedule was last updated.' def ref_path ::Gitlab::Routing.url_helpers.project_commits_path(object.project, object.ref_for_display) end + + def edit_path + ::Gitlab::Routing.url_helpers.edit_project_pipeline_schedule_path(object.project, object) + end end end end diff --git a/app/graphql/types/ci/pipeline_schedule_variable_type.rb b/app/graphql/types/ci/pipeline_schedule_variable_type.rb new file mode 100644 index 00000000000..1cb407bc2e4 --- /dev/null +++ b/app/graphql/types/ci/pipeline_schedule_variable_type.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module Ci + class PipelineScheduleVariableType < BaseObject + graphql_name 'PipelineScheduleVariable' + + authorize :read_pipeline_schedule_variables + + implements(VariableInterface) + end + end +end diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index 4a523f2edd9..cb561f48b3b 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -78,7 +78,7 @@ module Types resolver: Resolvers::Ci::PipelineStagesResolver field :user, - type: Types::UserType, + type: 'Types::UserType', null: true, description: 'Pipeline user.' diff --git a/app/graphql/types/ci/runner_job_execution_status_enum.rb b/app/graphql/types/ci/runner_job_execution_status_enum.rb new file mode 100644 index 00000000000..686ea085199 --- /dev/null +++ b/app/graphql/types/ci/runner_job_execution_status_enum.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Types + module Ci + class RunnerJobExecutionStatusEnum < BaseEnum + graphql_name 'CiRunnerJobExecutionStatus' + + value 'IDLE', + description: "Runner is idle.", + value: :idle, + deprecated: { milestone: '15.7', reason: :alpha } + + value 'RUNNING', + description: 'Runner is executing jobs.', + value: :running, + deprecated: { milestone: '15.7', reason: :alpha } + end + end +end diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index a9c76974850..5d34906f7b8 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -23,6 +23,9 @@ module Types deprecated: { reason: 'Use paused', milestone: '14.8' } field :admin_url, GraphQL::Types::String, null: true, description: 'Admin URL of the runner. Only available for administrators.' + field :architecture_name, GraphQL::Types::String, null: true, + description: 'Architecture provided by the the runner.', + method: :architecture field :contacted_at, Types::TimeType, null: true, description: 'Timestamp of last contact from this runner.', method: :contacted_at @@ -35,32 +38,39 @@ module Types field :executor_name, GraphQL::Types::String, null: true, description: 'Executor last advertised by the runner.', method: :executor_name - field :platform_name, GraphQL::Types::String, null: true, - description: 'Platform provided by the runner.', - method: :platform - field :architecture_name, GraphQL::Types::String, null: true, - description: 'Architecture provided by the the runner.', - method: :architecture - field :maintenance_note, GraphQL::Types::String, null: true, - description: 'Runner\'s maintenance notes.' - field :groups, ::Types::GroupType.connection_type, null: true, - description: 'Groups the runner is associated with. For group runners only.' + field :groups, 'Types::GroupConnection', + null: true, + resolver: ::Resolvers::Ci::RunnerGroupsResolver, + description: 'Groups the runner is associated with. For group runners only.' field :id, ::Types::GlobalIDType[::Ci::Runner], null: false, description: 'ID of the runner.' field :ip_address, GraphQL::Types::String, null: true, description: 'IP address of the runner.' field :job_count, GraphQL::Types::Int, null: true, description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist)." + field :job_execution_status, + Types::Ci::RunnerJobExecutionStatusEnum, + null: true, + description: 'Job execution status of the runner.', + deprecated: { milestone: '15.7', reason: :alpha } field :jobs, ::Types::Ci::JobType.connection_type, null: true, description: 'Jobs assigned to the runner. This field can only be resolved for one runner in any single request.', authorize: :read_builds, resolver: ::Resolvers::Ci::RunnerJobsResolver field :locked, GraphQL::Types::Boolean, null: true, description: 'Indicates the runner is locked.' + field :maintenance_note, GraphQL::Types::String, null: true, + description: 'Runner\'s maintenance notes.' field :maximum_timeout, GraphQL::Types::Int, null: true, description: 'Maximum timeout (in seconds) for jobs processed by the runner.' + field :owner_project, ::Types::ProjectType, null: true, + description: 'Project that owns the runner. For project runners only.', + resolver: ::Resolvers::Ci::RunnerOwnerProjectResolver field :paused, GraphQL::Types::Boolean, null: false, description: 'Indicates the runner is paused and not available to run jobs.' + field :platform_name, GraphQL::Types::String, null: true, + description: 'Platform provided by the runner.', + method: :platform field :project_count, GraphQL::Types::Int, null: true, description: 'Number of projects that the runner is associated with.' field :projects, @@ -88,9 +98,6 @@ module Types method: :token_expires_at field :version, GraphQL::Types::String, null: true, description: 'Version of the runner.' - field :owner_project, ::Types::ProjectType, null: true, - description: 'Project that owns the runner. For project runners only.', - resolver: ::Resolvers::Ci::RunnerOwnerProjectResolver markdown_field :maintenance_note_html, null: true @@ -99,8 +106,25 @@ module Types end def job_count - # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT - runner.builds.limit(JOB_COUNT_LIMIT + 1).count + BatchLoader::GraphQL.for(runner.id).batch(key: :job_count) do |runner_ids, loader, _args| + # rubocop: disable CodeReuse/ActiveRecord + # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT + builds_tbl = ::Ci::Build.arel_table + runners_tbl = ::Ci::Runner.arel_table + lateral_query = ::Ci::Build.select(1) + .where(builds_tbl['runner_id'].eq(runners_tbl['id'])) + .limit(JOB_COUNT_LIMIT + 1) + counts = ::Ci::Runner.joins("JOIN LATERAL (#{lateral_query.to_sql}) builds_with_limit ON true") + .id_in(runner_ids) + .select(:id, Arel.star.count.as('count')) + .group(:id) + .index_by(&:id) + # rubocop: enable CodeReuse/ActiveRecord + + runner_ids.each do |runner_id| + loader.call(runner_id, counts[runner_id]&.count || 0) + end + end end def admin_url @@ -111,14 +135,13 @@ module Types Gitlab::Routing.url_helpers.edit_admin_runner_url(runner) if can_admin_runners? end - # rubocop: disable CodeReuse/ActiveRecord def project_count BatchLoader::GraphQL.for(runner.id).batch(key: :runner_project_count) do |ids, loader, args| counts = ::Ci::Runner.project_type .select(:id, 'COUNT(ci_runner_projects.id) as count') .left_outer_joins(:runner_projects) - .where(id: ids) - .group(:id) + .id_in(ids) + .group(:id) # rubocop: disable CodeReuse/ActiveRecord .index_by(&:id) ids.each do |id| @@ -126,12 +149,15 @@ module Types end end end - # rubocop: enable CodeReuse/ActiveRecord - def groups - return unless runner.group_type? + def job_execution_status + BatchLoader::GraphQL.for(runner.id).batch(key: :running_builds_exist) do |runner_ids, loader| + statuses = ::Ci::Runner.id_in(runner_ids).with_running_builds.index_by(&:id) - batched_owners(::Ci::RunnerNamespace, Group, :runner_groups, :namespace_id) + runner_ids.each do |runner_id| + loader.call(runner_id, statuses[runner_id] ? :running : :idle) + end + end end private @@ -139,29 +165,6 @@ module Types def can_admin_runners? context[:current_user]&.can_admin_all_resources? end - - # rubocop: disable CodeReuse/ActiveRecord - def batched_owners(runner_assoc_type, assoc_type, key, column_name) - BatchLoader::GraphQL.for(runner.id).batch(key: key) do |runner_ids, loader| - plucked_runner_and_owner_ids = runner_assoc_type - .select(:runner_id, column_name) - .where(runner_id: runner_ids) - .pluck(:runner_id, column_name) - # In plucked_runner_and_owner_ids, first() represents the runner ID, and second() the owner ID, - # so let's group the owner IDs by runner ID - runner_owner_ids_by_runner_id = plucked_runner_and_owner_ids - .group_by(&:first) - .transform_values { |runner_and_owner_id| runner_and_owner_id.map(&:second) } - - owner_ids = runner_owner_ids_by_runner_id.values.flatten.uniq - owners = assoc_type.where(id: owner_ids).index_by(&:id) - - runner_ids.each do |runner_id| - loader.call(runner_id, runner_owner_ids_by_runner_id[runner_id]&.map { |owner_id| owners[owner_id] } || []) - end - end - end - # rubocop: enable CodeReuse/ActiveRecord end end end |