This instance will be upgraded to Heptapod 0.31.0 (final) on 2022-05-24 at 14:00 UTC+2 (a few minutes of down time)

Commit 111748ea authored by Z.J. van de Weg's avatar Z.J. van de Weg
Browse files

Rename Builds to Jobs in the API

Fixes gitlab-org/gitlab-ce#28515

[ci skip]
parent fab463fcdcef
......@@ -9,6 +9,7 @@ class API < Grape::API
mount ::API::V3::Boards
mount ::API::V3::Branches
mount ::API::V3::BroadcastMessages
mount ::API::V3::Builds
mount ::API::V3::Commits
mount ::API::V3::DeployKeys
mount ::API::V3::Environments
......@@ -77,7 +78,6 @@ class API < Grape::API
mount ::API::Boards
mount ::API::Branches
mount ::API::BroadcastMessages
mount ::API::Builds
mount ::API::Commits
mount ::API::CommitStatuses
mount ::API::DeployKeys
......@@ -87,6 +87,7 @@ class API < Grape::API
mount ::API::Groups
mount ::API::Internal
mount ::API::Issues
mount ::API::Jobs
mount ::API::Keys
mount ::API::Labels
mount ::API::Lint
......
......@@ -49,7 +49,8 @@ class Hook < Grape::Entity
class ProjectHook < Hook
expose :project_id, :issues_events, :merge_requests_events
expose :note_events, :build_events, :pipeline_events, :wiki_page_events
expose :note_events, :pipeline_events, :wiki_page_events
expose :job_events, as: :build_events
end
class BasicProjectDetails < Grape::Entity
......@@ -80,7 +81,7 @@ class Project < Grape::Entity
expose(:issues_enabled) { |project, options| project.feature_available?(:issues, options[:current_user]) }
expose(:merge_requests_enabled) { |project, options| project.feature_available?(:merge_requests, options[:current_user]) }
expose(:wiki_enabled) { |project, options| project.feature_available?(:wiki, options[:current_user]) }
expose(:builds_enabled) { |project, options| project.feature_available?(:builds, options[:current_user]) }
expose(:jobs_enabled) { |project, options| project.feature_available?(:builds, options[:current_user]) }
expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:current_user]) }
expose :created_at, :last_activity_at
......@@ -93,7 +94,7 @@ class Project < Grape::Entity
expose :star_count, :forks_count
expose :open_issues_count, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) && project.default_issues_tracker? }
expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] }
expose :public_builds
expose :public_jobs, as: :public_builds
expose :shared_with_groups do |project, options|
SharedGroup.represent(project.project_group_links.all, options)
end
......@@ -109,7 +110,7 @@ class ProjectStatistics < Grape::Entity
expose :storage_size
expose :repository_size
expose :lfs_objects_size
expose :build_artifacts_size
expose :job_artifacts_size, as: :build_artifacts_size
end
class Member < UserBasic
......@@ -144,7 +145,7 @@ class Group < Grape::Entity
expose :storage_size
expose :repository_size
expose :lfs_objects_size
expose :build_artifacts_size
expose :job_artifacts_size, as: :build_artifacts_size
end
end
end
......@@ -448,7 +449,8 @@ class GlobalNotificationSetting < NotificationSetting
class ProjectService < Grape::Entity
expose :id, :title, :created_at, :updated_at, :active
expose :push_events, :issues_events, :merge_requests_events
expose :tag_push_events, :note_events, :build_events, :pipeline_events
expose :tag_push_events, :note_events, :pipeline_events
expose :job_events, as: :build_events
# Expose serialized properties
expose :properties do |service, options|
field_names = service.fields.
......@@ -616,11 +618,15 @@ class RunnerDetails < Runner
end
end
<<<<<<< HEAD
class RunnerRegistrationDetails < Grape::Entity
expose :id, :token
end
class BuildArtifactFile < Grape::Entity
=======
class JobArtifactFile < Grape::Entity
>>>>>>> 239b5f49c5... Rename Builds to Jobs in the API
expose :filename, :size
end
......@@ -628,11 +634,11 @@ class PipelineBasic < Grape::Entity
expose :id, :sha, :ref, :status
end
class Build < Grape::Entity
class Job < Grape::Entity
expose :id, :status, :stage, :name, :ref, :tag, :coverage
expose :created_at, :started_at, :finished_at
expose :user, with: User
expose :artifacts_file, using: BuildArtifactFile, if: -> (build, opts) { build.artifacts? }
expose :artifacts_file, using: JobArtifactFile, if: -> (build, opts) { build.artifacts? }
expose :commit, with: RepoCommit
expose :runner, with: Runner
expose :pipeline, with: PipelineBasic
......@@ -670,7 +676,7 @@ class Deployment < Grape::Entity
expose :id, :iid, :ref, :sha, :created_at
expose :user, using: Entities::UserBasic
expose :environment, using: Entities::EnvironmentBasic
expose :deployable, using: Entities::Build
expose :deployable, using: Entities::Job
end
class RepoLicense < Grape::Entity
......
module API
class Builds < Grape::API
class Jobs < Grape::API
include PaginationParams
before { authenticate! }
......@@ -13,9 +13,10 @@ class Builds < Grape::API
optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show',
values: ::CommitStatus::AVAILABLE_STATUSES,
coerce_with: ->(scope) {
if scope.is_a?(String)
case scope
when String
[scope]
elsif scope.is_a?(Hashie::Mash)
when Hashie::Mash
scope.values
else
['unknown']
......@@ -24,30 +25,30 @@ class Builds < Grape::API
end
end
desc 'Get a project builds' do
success Entities::Build
desc 'Get a projects jobs' do
success Entities::Job
end
params do
use :optional_scope
use :pagination
end
get ':id/builds' do
get ':id/jobs' do
builds = user_project.builds.order('id DESC')
builds = filter_builds(builds, params[:scope])
present paginate(builds), with: Entities::Build,
present paginate(builds), with: Entities::Job,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Get builds for a specific commit of a project' do
success Entities::Build
desc 'Get jobs for a specific commit of a project' do
success Entities::Job
end
params do
requires :sha, type: String, desc: 'The SHA id of a commit'
use :optional_scope
use :pagination
end
get ':id/repository/commits/:sha/builds' do
get ':id/repository/commits/:sha/jobs' do
authorize_read_builds!
return not_found! unless user_project.commit(params[:sha])
......@@ -56,47 +57,47 @@ class Builds < Grape::API
builds = user_project.builds.where(pipeline: pipelines).order('id DESC')
builds = filter_builds(builds, params[:scope])
present paginate(builds), with: Entities::Build,
present paginate(builds), with: Entities::Job,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Get a specific build of a project' do
success Entities::Build
desc 'Get a specific job of a project' do
success Entities::Job
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
requires :job_id, type: Integer, desc: 'The ID of a job'
end
get ':id/builds/:build_id' do
get ':id/jobs/:job_id' do
authorize_read_builds!
build = get_build!(params[:build_id])
build = get_build!(params[:job_id])
present build, with: Entities::Build,
present build, with: Entities::Job,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Download the artifacts file from build' do
desc 'Download the artifacts file from a job' do
detail 'This feature was introduced in GitLab 8.5'
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
requires :job_id, type: Integer, desc: 'The ID of a job'
end
get ':id/builds/:build_id/artifacts' do
get ':id/jobs/:job_id/artifacts' do
authorize_read_builds!
build = get_build!(params[:build_id])
build = get_build!(params[:job_id])
present_artifacts!(build.artifacts_file)
end
desc 'Download the artifacts file from build' do
desc 'Download the artifacts file from a job' do
detail 'This feature was introduced in GitLab 8.10'
end
params do
requires :ref_name, type: String, desc: 'The ref from repository'
requires :job, type: String, desc: 'The name for the build'
requires :job, type: String, desc: 'The name for the job'
end
get ':id/builds/artifacts/:ref_name/download',
get ':id/jobs/artifacts/:ref_name/download',
requirements: { ref_name: /.+/ } do
authorize_read_builds!
......@@ -109,14 +110,14 @@ class Builds < Grape::API
# TODO: We should use `present_file!` and leave this implementation for backward compatibility (when build trace
# is saved in the DB instead of file). But before that, we need to consider how to replace the value of
# `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse.
desc 'Get a trace of a specific build of a project'
desc 'Get a trace of a specific job of a project'
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
requires :job_id, type: Integer, desc: 'The ID of a job'
end
get ':id/builds/:build_id/trace' do
get ':id/jobs/:job_id/trace' do
authorize_read_builds!
build = get_build!(params[:build_id])
build = get_build!(params[:job_id])
header 'Content-Disposition', "infile; filename=\"#{build.id}.log\""
content_type 'text/plain'
......@@ -126,95 +127,95 @@ class Builds < Grape::API
body trace
end
desc 'Cancel a specific build of a project' do
success Entities::Build
desc 'Cancel a specific job of a project' do
success Entities::Job
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
requires :job_id, type: Integer, desc: 'The ID of a job'
end
post ':id/builds/:build_id/cancel' do
post ':id/jobs/:job_id/cancel' do
authorize_update_builds!
build = get_build!(params[:build_id])
build = get_build!(params[:job_id])
build.cancel
present build, with: Entities::Build,
present build, with: Entities::Job,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Retry a specific build of a project' do
success Entities::Build
success Entities::Job
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
requires :job_id, type: Integer, desc: 'The ID of a build'
end
post ':id/builds/:build_id/retry' do
post ':id/jobs/:job_id/retry' do
authorize_update_builds!
build = get_build!(params[:build_id])
return forbidden!('Build is not retryable') unless build.retryable?
build = get_build!(params[:job_id])
return forbidden!('Job is not retryable') unless build.retryable?
build = Ci::Build.retry(build, current_user)
present build, with: Entities::Build,
present build, with: Entities::Job,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Erase build (remove artifacts and build trace)' do
success Entities::Build
desc 'Erase job (remove artifacts and the trace)' do
success Entities::Job
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
requires :job_id, type: Integer, desc: 'The ID of a build'
end
post ':id/builds/:build_id/erase' do
post ':id/jobs/:job_id/erase' do
authorize_update_builds!
build = get_build!(params[:build_id])
return forbidden!('Build is not erasable!') unless build.erasable?
build = get_build!(params[:job_id])
return forbidden!('Job is not erasable!') unless build.erasable?
build.erase(erased_by: current_user)
present build, with: Entities::Build,
present build, with: Entities::Job,
user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project)
end
desc 'Keep the artifacts to prevent them from being deleted' do
success Entities::Build
success Entities::Job
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
requires :job_id, type: Integer, desc: 'The ID of a job'
end
post ':id/builds/:build_id/artifacts/keep' do
post ':id/jobs/:job_id/artifacts/keep' do
authorize_update_builds!
build = get_build!(params[:build_id])
build = get_build!(params[:job_id])
return not_found!(build) unless build.artifacts?
build.keep_artifacts!
status 200
present build, with: Entities::Build,
present build, with: Entities::Job,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Trigger a manual build' do
success Entities::Build
desc 'Trigger a manual job' do
success Entities::Job
detail 'This feature was added in GitLab 8.11'
end
params do
requires :build_id, type: Integer, desc: 'The ID of a Build'
requires :job_id, type: Integer, desc: 'The ID of a Job'
end
post ":id/builds/:build_id/play" do
post ":id/jobs/:job_id/play" do
authorize_read_builds!
build = get_build!(params[:build_id])
build = get_build!(params[:job_id])
bad_request!("Unplayable Job") unless build.playable?
build.play(current_user)
status 200
present build, with: Entities::Build,
present build, with: Entities::Job,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
end
......
module API
module V3
class Builds < Grape::API
include PaginationParams
before { authenticate! }
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects do
helpers do
params :optional_scope do
optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show',
values: ['pending', 'running', 'failed', 'success', 'canceled'],
coerce_with: ->(scope) {
if scope.is_a?(String)
[scope]
elsif scope.is_a?(Hashie::Mash)
scope.values
else
['unknown']
end
}
end
end
desc 'Get a project builds' do
success V3::Entities::Build
end
params do
use :optional_scope
use :pagination
end
get ':id/builds' do
builds = user_project.builds.order('id DESC')
builds = filter_builds(builds, params[:scope])
present paginate(builds), with: Entities::Build,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Get builds for a specific commit of a project' do
success Entities::Build
end
params do
requires :sha, type: String, desc: 'The SHA id of a commit'
use :optional_scope
use :pagination
end
get ':id/repository/commits/:sha/builds' do
authorize_read_builds!
return not_found! unless user_project.commit(params[:sha])
pipelines = user_project.pipelines.where(sha: params[:sha])
builds = user_project.builds.where(pipeline: pipelines).order('id DESC')
builds = filter_builds(builds, params[:scope])
present paginate(builds), with: Entities::Build,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Get a specific build of a project' do
success Entities::Build
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
end
get ':id/builds/:build_id' do
authorize_read_builds!
build = get_build!(params[:build_id])
present build, with: Entities::Build,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Download the artifacts file from build' do
detail 'This feature was introduced in GitLab 8.5'
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
end
get ':id/builds/:build_id/artifacts' do
authorize_read_builds!
build = get_build!(params[:build_id])
present_artifacts!(build.artifacts_file)
end
desc 'Download the artifacts file from build' do
detail 'This feature was introduced in GitLab 8.10'
end
params do
requires :ref_name, type: String, desc: 'The ref from repository'
requires :job, type: String, desc: 'The name for the build'
end
get ':id/builds/artifacts/:ref_name/download',
requirements: { ref_name: /.+/ } do
authorize_read_builds!
builds = user_project.latest_successful_builds_for(params[:ref_name])
latest_build = builds.find_by!(name: params[:job])
present_artifacts!(latest_build.artifacts_file)
end
# TODO: We should use `present_file!` and leave this implementation for backward compatibility (when build trace
# is saved in the DB instead of file). But before that, we need to consider how to replace the value of
# `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse.
desc 'Get a trace of a specific build of a project'
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
end
get ':id/builds/:build_id/trace' do
authorize_read_builds!
build = get_build!(params[:build_id])
header 'Content-Disposition', "infile; filename=\"#{build.id}.log\""
content_type 'text/plain'
env['api.format'] = :binary
trace = build.trace
body trace
end
desc 'Cancel a specific build of a project' do
success Entities::Build
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
end
post ':id/builds/:build_id/cancel' do
authorize_update_builds!
build = get_build!(params[:build_id])
build.cancel
present build, with: Entities::Build,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Retry a specific build of a project' do
success Entities::Build
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
end
post ':id/builds/:build_id/retry' do
authorize_update_builds!
build = get_build!(params[:build_id])
return forbidden!('Build is not retryable') unless build.retryable?
build = Ci::Build.retry(build, current_user)
present build, with: Entities::Build,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Erase build (remove artifacts and build trace)' do
success Entities::Build
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
end
post ':id/builds/:build_id/erase' do
authorize_update_builds!
build = get_build!(params[:build_id])
return forbidden!('Build is not erasable!') unless build.erasable?
build.erase(erased_by: current_user)
present build, with: Entities::Build,
user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project)
end
desc 'Keep the artifacts to prevent them from being deleted' do
success Entities::Build
end
params do
requires :build_id, type: Integer, desc: 'The ID of a build'
end
post ':id/builds/:build_id/artifacts/keep' do
authorize_update_builds!
build = get_build!(params[:build_id])
return not_found!(build) unless build.artifacts?
build.keep_artifacts!
status 200
present build, with: Entities::Build,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
desc 'Trigger a manual build' do
success Entities::Build
detail 'This feature was added in GitLab 8.11'
end
params do
requires :build_id, type: Integer, desc: 'The ID of a Build'
end
post ":id/builds/:build_id/play" do
authorize_read_builds!
build = get_build!(params[:build_id])
bad_request!("Unplayable Job") unless build.playable?
build.play(current_user)
status 200
present build, with: Entities::Build,
user_can_download_artifacts: can?(current_user, :read_build, user_project)
end
end
helpers do
def get_build(id)
user_project.builds.find_by(id: id.to_i)
end
def get_build!(id)
get_build(id) || not_found!
end
def present_artifacts!(artifacts_file)
if !artifacts_file.file_storage?
redirect_to(build.artifacts_file.url)
elsif artifacts_file.exists?
present_file!(artifacts_file.path, artifacts_file.filename)
else
not_found!
end
end
def filter_builds(builds, scope)
return builds if scope.nil? || scope.empty?
available_statuses = ::CommitStatus::AVAILABLE_STATUSES