1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
- job = build.present(current_user: current_user)
- pipeline = job.pipeline
- admin = local_assigns.fetch(:admin, false)
- ref = local_assigns.fetch(:ref, nil)
- commit_sha = local_assigns.fetch(:commit_sha, nil)
- retried = local_assigns.fetch(:retried, false)
- pipeline_link = local_assigns.fetch(:pipeline_link, false)
- stage = local_assigns.fetch(:stage, false)
- allow_retry = local_assigns.fetch(:allow_retry, false)
-# This prevents initializing another Ci::Status object where 'status' is used
- status = job.detailed_status(current_user)
%tr.build.commit{ class: ('retried' if retried) }
%td.status
-# Sending 'status' prevents calling the user relation inside the presenter, generating N+1,
-# see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68743
= render "ci/status/badge", status: status, title: job.status_title(status)
%td
- if can?(current_user, :read_build, job)
= link_to job.name, project_job_path(job.project, job), class: 'gl-text-blue-600!'
- else
%span.gl-text-blue-600!
= job.name
%td.branch-commit.gl-text-gray-900
%span.build-link ##{job.id}
- if ref
- if job.ref
.icon-container.gl-display-inline-block
= job.tag? ? sprite_icon('label', css_class: 'sprite') : sprite_icon('fork', css_class: 'sprite')
= link_to job.ref, project_ref_path(job.project, job.ref), class: "ref-name"
- else
.light= _('none')
.icon-container.commit-icon
= custom_icon("icon_commit")
- if commit_sha
= link_to job.short_sha, project_commit_path(job.project, job.sha), class: "commit-sha mr-0"
- if job.stuck?
%span.has-tooltip{ title: _('Job is stuck. Check runners.') }
= sprite_icon('warning', css_class: 'text-warning!')
- if retried
%span.has-tooltip{ title: _('Job was retried') }
= sprite_icon('retry', css_class: 'text-warning')
.label-container
- if job.tags.any?
- job.tags.each do |tag|
= gl_badge_tag tag, variant: :info, size: :sm
- if job.try(:trigger_request)
= gl_badge_tag _('triggered'), variant: :info, size: :sm
- if job.try(:allow_failure) && !job.success?
= gl_badge_tag _('allowed to fail'), variant: :warning, size: :sm
- if job.schedulable?
= gl_badge_tag s_('DelayedJobs|delayed'), variant: :info, size: :sm
- elsif job.action?
= gl_badge_tag _('manual'), variant: :info, size: :sm
- if pipeline_link
%td
= link_to pipeline_path(pipeline) do
%span.pipeline-id ##{pipeline.id}
%span by
- if pipeline.user
= user_avatar(user: pipeline.user, size: 20)
- else
%span.monospace API
- if admin
%td
- if job.project
= link_to job.project.full_name, admin_project_path(job.project)
%td
- if job.try(:runner)
= runner_link(job.runner)
- else
.light= _('none')
- if stage
%td
= job.stage_name
%td
- if job.duration
%p.duration
= sprite_icon("timer")
= duration_in_numbers(job.duration)
- if job.finished_at
%p.finished-at
= sprite_icon("calendar")
%span= time_ago_with_tooltip(job.finished_at)
%td.coverage
- if job.try(:coverage)
#{job.coverage}%
%td
.gl-text-right
.btn-group
- if can?(current_user, :read_job_artifacts, job) && job.artifacts?
= link_to download_project_job_artifacts_path(job.project, job), rel: 'nofollow', download: '', title: _('Download artifacts'), class: 'gl-button btn btn-default btn-icon' do
= sprite_icon('download', css_class: 'gl-icon')
- if can?(current_user, :update_build, job)
- if job.active?
= link_to cancel_project_job_path(job.project, job, continue: { to: request.fullpath }), method: :post, title: _('Cancel'), class: 'gl-button btn btn-default btn-icon' do
= sprite_icon('cancel', css_class: 'gl-icon')
- elsif job.scheduled?
.gl-button.btn.btn-default.btn-icon.disabled{ disabled: true }
= sprite_icon('planning', css_class: 'gl-icon')
%time.js-remaining-time{ datetime: job.scheduled_at.utc.iso8601 }
= duration_in_numbers(job.execute_in)
- confirmation_message = s_("DelayedJobs|Are you sure you want to run %{job_name} immediately? This job will run automatically after it's timer finishes.") % { job_name: job.name }
= link_to play_project_job_path(job.project, job, return_to: request.original_url),
method: :post,
title: s_('DelayedJobs|Start now'),
class: 'gl-button btn btn-default btn-icon has-tooltip',
data: { confirm: confirmation_message } do
= sprite_icon('play', css_class: 'gl-icon')
= link_to unschedule_project_job_path(job.project, job, return_to: request.original_url),
method: :post,
title: s_('DelayedJobs|Unschedule'),
class: 'gl-button btn btn-default btn-icon has-tooltip' do
= sprite_icon('time-out', css_class: 'gl-icon')
- elsif allow_retry
- if job.playable? && !admin && can?(current_user, :update_build, job)
= link_to play_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Play'), class: 'gl-button btn btn-default btn-icon' do
= sprite_icon('play', css_class: 'gl-icon')
- elsif job.retryable?
= link_to retry_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Retry'), class: 'gl-button btn btn-default btn-icon' do
= sprite_icon('retry', css_class: 'gl-icon')
|