Show timeout information on job's page

This commit is contained in:
Tomasz Maczukin 2018-02-21 04:03:12 +01:00
parent d633bc8134
commit 78a4189ece
No known key found for this signature in database
GPG Key ID: 7E9EB2E4B0F625CD
8 changed files with 84 additions and 20 deletions

View File

@ -39,6 +39,15 @@
runnerId() { runnerId() {
return `#${this.job.runner.id}`; return `#${this.job.runner.id}`;
}, },
timeout() {
let t = `${this.job.timeout.value}`;
if (this.job.timeout.source != null) {
t += ` (from ${this.job.timeout.source})`;
}
return t;
},
renderBlock() { renderBlock() {
return this.job.merge_request || return this.job.merge_request ||
this.job.duration || this.job.duration ||
@ -114,6 +123,12 @@
title="Queued" title="Queued"
:value="queued" :value="queued"
/> />
<detail-row
class="js-job-timeout"
v-if="job.timeout"
title="Timeout"
:value="timeout"
/>
<detail-row <detail-row
class="js-job-runner" class="js-job-runner"
v-if="job.runner" v-if="job.runner"

View File

@ -6,6 +6,7 @@ module Ci
include ObjectStorage::BackgroundMove include ObjectStorage::BackgroundMove
include Presentable include Presentable
include Importable include Importable
include ChronicDurationAttribute
MissingDependenciesError = Class.new(StandardError) MissingDependenciesError = Class.new(StandardError)
@ -90,6 +91,8 @@ module Ci
after_commit :update_project_statistics_after_save, on: [:create, :update] after_commit :update_project_statistics_after_save, on: [:create, :update]
after_commit :update_project_statistics, on: :destroy after_commit :update_project_statistics, on: :destroy
chronic_duration_attribute_reader :used_timeout_user_readable, :used_timeout
class << self class << self
# This is needed for url_for to work, # This is needed for url_for to work,
# as the controller is JobsController # as the controller is JobsController
@ -120,6 +123,10 @@ module Ci
end end
after_transition pending: :running do |build| after_transition pending: :running do |build|
build.used_timeout = build.timeout
build.timeout_source = build.should_use_runner_timeout? ? 'Runner' : 'Project'
build.save!
build.run_after_commit do build.run_after_commit do
BuildHooksWorker.perform_async(id) BuildHooksWorker.perform_async(id)
end end
@ -232,15 +239,14 @@ module Ci
end end
def timeout def timeout
return runner.maximum_job_timeout if should_use_runner_timeout return runner.maximum_job_timeout if should_use_runner_timeout?
project.build_timeout project.build_timeout
end end
def should_use_runner_timeout def should_use_runner_timeout?
!runner.nil? && runner.defines_maximum_job_timeout? && runner.maximum_job_timeout < project.build_timeout !runner.nil? && runner.defines_maximum_job_timeout? && runner.maximum_job_timeout < project.build_timeout
end end
private :should_use_runner_timeout
def triggered_by?(current_user) def triggered_by?(current_user)
user == current_user user == current_user

View File

@ -5,6 +5,11 @@ class BuildDetailsEntity < JobEntity
expose :runner, using: RunnerEntity expose :runner, using: RunnerEntity
expose :pipeline, using: PipelineEntity expose :pipeline, using: PipelineEntity
expose :timeout, if: -> (*) { !build.used_timeout.nil? } do |build|
{ value: build.used_timeout_user_readable,
source: build.timeout_source }
end
expose :erased_by, if: -> (*) { build.erased? }, using: UserEntity expose :erased_by, if: -> (*) { build.erased? }, using: UserEntity
expose :erase_path, if: -> (*) { build.erasable? && can?(current_user, :erase_build, build) } do |build| expose :erase_path, if: -> (*) { build.erasable? && can?(current_user, :erase_build, build) } do |build|
erase_project_job_path(project, build) erase_project_job_path(project, build)

View File

@ -0,0 +1,15 @@
class AddUsedTimeoutAndTimeoutSourceColumnsToCiBuilds < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
add_column :ci_builds, :used_timeout, :integer
add_column :ci_builds, :timeout_source, :string
end
def down
remove_column :ci_builds, :used_timeout
remove_column :ci_builds, :timeout_source
end
end

View File

@ -311,6 +311,8 @@ ActiveRecord::Schema.define(version: 20180327101207) do
t.integer "artifacts_metadata_store" t.integer "artifacts_metadata_store"
t.boolean "protected" t.boolean "protected"
t.integer "failure_reason" t.integer "failure_reason"
t.integer "used_timeout"
t.string "timeout_source"
end end
add_index "ci_builds", ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)", using: :btree add_index "ci_builds", ["artifacts_expire_at"], name: "index_ci_builds_on_artifacts_expire_at", where: "(artifacts_file <> ''::text)", using: :btree

View File

@ -283,6 +283,8 @@ CommitStatus:
- retried - retried
- protected - protected
- failure_reason - failure_reason
- used_timeout
- timeout_source
Ci::Variable: Ci::Variable:
- id - id
- project_id - project_id

View File

@ -1,28 +1,46 @@
require 'spec_helper' require 'spec_helper'
shared_examples 'ChronicDurationAttribute' do shared_examples 'ChronicDurationAttribute reader' do
describe 'dynamically defined methods' do it 'contains dynamically created reader method' do
it { expect(subject.class).to be_public_method_defined(virtual_field) } expect(subject.class).to be_public_method_defined(virtual_field)
it { expect(subject.class).to be_public_method_defined("#{virtual_field}=") } end
it 'parses chronic duration input' do it 'outputs chronic duration formated value' do
subject.send("#{virtual_field}=", "10m") subject.send("#{source_field}=", 120)
expect(subject.send(source_field)).to eq(600) expect(subject.send(virtual_field)).to eq('2m')
end end
end
it 'outputs chronic duration formated value' do shared_examples 'ChronicDurationAttribute writer' do
subject.send("#{source_field}=", 120) it 'contains dynamically created writer method' do
expect(subject.class).to be_public_method_defined("#{virtual_field}=")
end
expect(subject.send(virtual_field)).to eq('2m') it 'parses chronic duration input' do
end subject.send("#{virtual_field}=", "10m")
expect(subject.send(source_field)).to eq(600)
end end
end end
describe 'ChronicDurationAttribute' do describe 'ChronicDurationAttribute' do
let(:source_field) { :maximum_job_timeout } let(:source_field) {:maximum_job_timeout}
let(:virtual_field) { :maximum_job_timeout_user_readable } let(:virtual_field) {:maximum_job_timeout_user_readable}
subject { Ci::Runner.new } subject {Ci::Runner.new}
it_behaves_like 'ChronicDurationAttribute' it_behaves_like 'ChronicDurationAttribute reader'
it_behaves_like 'ChronicDurationAttribute writer'
end
describe 'ChronicDurationAttribute - reader' do
let(:source_field) {:used_timeout}
let(:virtual_field) {:used_timeout_user_readable}
subject {Ci::Build.new}
it "doesn't contain dynamically created writer method" do
expect(subject.class).not_to be_public_method_defined("#{virtual_field}=")
end
it_behaves_like 'ChronicDurationAttribute reader'
end end

View File

@ -29,7 +29,8 @@ describe Ci::RetryBuildService do
commit_id deployments erased_by_id last_deployment project_id commit_id deployments erased_by_id last_deployment project_id
runner_id tag_taggings taggings tags trigger_request_id runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id retried failure_reason user_id auto_canceled_by_id retried failure_reason
artifacts_file_store artifacts_metadata_store].freeze artifacts_file_store artifacts_metadata_store
used_timeout timeout_source].freeze
shared_examples 'build duplication' do shared_examples 'build duplication' do
let(:another_pipeline) { create(:ci_empty_pipeline, project: project) } let(:another_pipeline) { create(:ci_empty_pipeline, project: project) }