Commit 47a0276e authored by Z.J. van de Weg's avatar Z.J. van de Weg

Initial implementation for real time job view

Added the needed keys and paths to a new entity, BuildDetailsEntity.
Not renaming BuildEntity to BuildBasicEntity on explicit request. Most
code now has test coverage, but not all. This will be added on later
commits on this branch.

Resolves gitlab-org/gitlab-ce#31397
parent f06daa26
......@@ -45,6 +45,17 @@ class Projects::JobsController < Projects::ApplicationController
@builds = @project.pipelines.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id)
@pipeline = @build.pipeline
respond_to do |format|
format.html
format.json do
Gitlab::PollingInterval.set_header(response, interval: 10_000)
render json: BuildSerializer
.new(project: @project, current_user: @current_user)
.represent_status(@build, {}, BuildDetailsEntity)
end
end
end
def trace
......
......@@ -204,6 +204,8 @@ module Ci
end
def merge_request
@merge_request ||=
begin
merge_requests = MergeRequest.includes(:merge_request_diff)
.where(source_branch: ref,
source_project: pipeline.project)
......@@ -213,6 +215,7 @@ module Ci
merge_request.commits_sha.include?(pipeline.sha)
end
end
end
def repo_url
auth = "gitlab-ci-token:#{ensure_token!}@"
......
class BuildDetailsEntity < BuildEntity
expose :coverage, :erased_at, :duration
expose :tag_list, as: :tags
expose :artifacts, using: BuildArtifactEntity
expose :runner, using: RunnerEntity
expose :pipeline, using: PipelineEntity
expose :merge_request_path do |build|
merge_request = build.merge_request
project = build.project
if merge_request.nil? || !can?(request.current_user, :read_merge_request, project)
nil
else
namespace_project_merge_request_path(project.namespace, project, merge_request)
end
end
expose :new_issue_path do |build|
project = build.project
unless build.failed? && can?(request.current_user, :create_issue, project)
nil
else
new_namespace_project_issue_path(project.namespace, project)
end
end
expose :raw_path do |build|
project = build.project
raw_namespace_project_build_path(project.namespace, project, build)
end
end
class BuildSerializer < BaseSerializer
entity BuildEntity
def represent_status(resource)
def represent_status(resource, opts = {}, entity_class = nil)
data = represent(resource, { only: [:status] })
data.fetch(:status, {})
represent(resource, opts, entity_class)
end
end
class RunnerEntity < Grape::Entity
expose :id, :name, :description
end
---
title: Job details page update real time
merge_request: 11651
author:
......@@ -9,7 +9,9 @@ module Gitlab
# - Ending in `noteable/issue/<id>/notes` for the `issue_notes` route
# - Ending in `issues/id`/realtime_changes` for the `issue_title` route
USED_IN_ROUTES = %w[noteable issue notes issues realtime_changes
commit pipelines merge_requests new].freeze
commit pipelines merge_requests builds
new].freeze
RESERVED_WORDS = Gitlab::PathRegex::ILLEGAL_PROJECT_PATH_WORDS - USED_IN_ROUTES
RESERVED_WORDS_REGEX = Regexp.union(*RESERVED_WORDS.map(&Regexp.method(:escape)))
ROUTES = [
......@@ -40,6 +42,10 @@ module Gitlab
Gitlab::EtagCaching::Router::Route.new(
%r(^(?!.*(#{RESERVED_WORDS_REGEX})).*/pipelines/\d+\.json\z),
'project_pipeline'
),
Gitlab::EtagCaching::Router::Route.new(
%r(^(?!.*(#{RESERVED_WORDS_REGEX})).*/builds/\d+\.json\z),
'project_build'
)
].freeze
......
......@@ -101,9 +101,10 @@ describe Projects::JobsController do
end
describe 'GET show' do
context 'when build exists' do
let!(:build) { create(:ci_build, pipeline: pipeline) }
let!(:build) { create(:ci_build, :failed, pipeline: pipeline) }
context 'when requesting HTML' do
context 'when build exists' do
before do
get_show(id: build.id)
end
......@@ -123,6 +124,27 @@ describe Projects::JobsController do
expect(response).to have_http_status(:not_found)
end
end
end
context 'when requesting JSON' do
let(:merge_request) { create(:merge_request, source_project: project) }
before do
project.add_developer(user)
sign_in(user)
allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
get_show(id: build.id, format: :json)
end
it 'exposes needed information' do
expect(response).to have_http_status(:ok)
expect(json_response['new_issue_path']).to end_with('/issues/new')
expect(json_response['raw_path']).to match(/builds\/\d+\/raw\z/)
expect(json_response['merge_request_path']).to match(/merge_requests\/\d+\z/)
end
end
def get_show(**extra_params)
params = {
......
......@@ -67,6 +67,17 @@ describe Gitlab::EtagCaching::Router do
expect(result.name).to eq 'merge_request_pipelines'
end
it 'matches build endpoint' do
env = build_env(
'/my-group/my-project/builds/234.json'
)
result = described_class.match(env)
expect(result).to be_present
expect(result.name).to eq 'project_build'
end
it 'does not match blob with confusing name' do
env = build_env(
'/my-group/my-project/blob/master/pipelines.json'
......
require 'spec_helper'
describe BuildDetailsEntity do
it 'inherits from BuildEntity' do
expect(described_class).to be < BuildEntity
end
describe '#as_json' do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let!(:build) { create(:ci_build, :failed, project: project) }
let(:request) { double('request') }
let(:entity) { described_class.new(build, request: request, current_user: user, project: project) }
subject { entity.as_json }
before do
allow(request).to receive(:current_user).and_return(user)
project.add_master(user)
end
context 'when the user has access to issues and merge requests' do
let!(:merge_request) { create(:merge_request, source_project: project) }
it 'contains the needed key value pairs' do
expect(subject).to include(:coverage, :erased_at, :duration)
expect(subject).to include(:artifacts, :runner, :pipeline)
expect(subject).to include(:raw_path, :merge_request_path, :new_issue_path)
end
end
context 'when the user can only read the build' do
it "won't display the paths to issues and merge requests" do
expect(subject['new_issue_path']).to be_nil
expect(subject['merge_request_path']).to be_nil
end
end
end
end
require 'spec_helper'
describe RunnerEntity do
let(:runner) { build(:ci_runner) }
let(:entity) { described_class.represent(runner) }
describe '#as_json' do
subject { entity.as_json }
it 'contains required fields' do
expect(subject).to include(:id, :name, :description)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment