Add implementation of manual actions
This commit is contained in:
parent
4e898b9b5e
commit
7d0fe1f04e
12 changed files with 96 additions and 17 deletions
|
@ -57,6 +57,15 @@ class Projects::BuildsController < Projects::ApplicationController
|
||||||
redirect_to build_path(build)
|
redirect_to build_path(build)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def play
|
||||||
|
unless @build.playable?
|
||||||
|
return render_404
|
||||||
|
end
|
||||||
|
|
||||||
|
build = @build.play(current_user)
|
||||||
|
redirect_to build_path(build)
|
||||||
|
end
|
||||||
|
|
||||||
def cancel
|
def cancel
|
||||||
@build.cancel
|
@build.cancel
|
||||||
redirect_to build_path(@build)
|
redirect_to build_path(@build)
|
||||||
|
|
|
@ -15,6 +15,7 @@ module Ci
|
||||||
scope :with_artifacts, ->() { where.not(artifacts_file: nil) }
|
scope :with_artifacts, ->() { where.not(artifacts_file: nil) }
|
||||||
scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) }
|
scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) }
|
||||||
scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) }
|
scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) }
|
||||||
|
scope :manual_actions, ->() { where(when: :manual).without_created }
|
||||||
|
|
||||||
mount_uploader :artifacts_file, ArtifactUploader
|
mount_uploader :artifacts_file, ArtifactUploader
|
||||||
mount_uploader :artifacts_metadata, ArtifactUploader
|
mount_uploader :artifacts_metadata, ArtifactUploader
|
||||||
|
@ -91,6 +92,29 @@ module Ci
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def manual?
|
||||||
|
self.when == 'manual'
|
||||||
|
end
|
||||||
|
|
||||||
|
def playable_actions
|
||||||
|
pipeline.playable_actions
|
||||||
|
end
|
||||||
|
|
||||||
|
def playable?
|
||||||
|
project.builds_enabled? && commands.present? && manual?
|
||||||
|
end
|
||||||
|
|
||||||
|
def play(current_user = nil)
|
||||||
|
if skipped?
|
||||||
|
# We can run skipped build
|
||||||
|
new_build.user = current_user
|
||||||
|
new_build.queue
|
||||||
|
else
|
||||||
|
# Otherwise we need to create a duplicate
|
||||||
|
Ci::Build.retry(self, current_user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def retryable?
|
def retryable?
|
||||||
project.builds_enabled? && commands.present? && complete?
|
project.builds_enabled? && commands.present? && complete?
|
||||||
end
|
end
|
||||||
|
|
|
@ -65,6 +65,10 @@ module Ci
|
||||||
!tag?
|
!tag?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def playable_actions
|
||||||
|
builds.manual_actions.latest
|
||||||
|
end
|
||||||
|
|
||||||
def retryable?
|
def retryable?
|
||||||
builds.latest.any? do |build|
|
builds.latest.any? do |build|
|
||||||
build.failed? && build.retryable?
|
build.failed? && build.retryable?
|
||||||
|
|
|
@ -32,4 +32,8 @@ class Deployment < ActiveRecord::Base
|
||||||
def keep_around_commit
|
def keep_around_commit
|
||||||
project.repository.keep_around(self.sha)
|
project.repository.keep_around(self.sha)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def playable_actions
|
||||||
|
deployable.try(:playable_actions)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
%span.label.label-danger allowed to fail
|
%span.label.label-danger allowed to fail
|
||||||
- if defined?(retried) && retried
|
- if defined?(retried) && retried
|
||||||
%span.label.label-warning retried
|
%span.label.label-warning retried
|
||||||
|
- if build.manual?
|
||||||
|
%span.label.label-info manual
|
||||||
|
|
||||||
|
|
||||||
- if defined?(runner) && runner
|
- if defined?(runner) && runner
|
||||||
|
@ -79,6 +81,11 @@
|
||||||
- if build.active?
|
- if build.active?
|
||||||
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
|
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
|
||||||
= icon('remove', class: 'cred')
|
= icon('remove', class: 'cred')
|
||||||
- elsif defined?(allow_retry) && allow_retry && build.retryable?
|
- elsif defined?(allow_retry) && allow_retry
|
||||||
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
|
- if build.retryable?
|
||||||
= icon('repeat')
|
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
|
||||||
|
= icon('repeat')
|
||||||
|
- elsif build.playable?
|
||||||
|
= link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
|
||||||
|
= icon('play')
|
||||||
|
|
||||||
|
|
|
@ -57,18 +57,30 @@
|
||||||
%td.pipeline-actions
|
%td.pipeline-actions
|
||||||
.controls.hidden-xs.pull-right
|
.controls.hidden-xs.pull-right
|
||||||
- artifacts = pipeline.builds.latest.select { |b| b.artifacts? }
|
- artifacts = pipeline.builds.latest.select { |b| b.artifacts? }
|
||||||
- if artifacts.present?
|
- playable = pipeline.playable_actions
|
||||||
.inline
|
- if artifacts.present? || playable.any?
|
||||||
.btn-group
|
.btn-group.inline
|
||||||
%a.dropdown-toggle.btn.btn-default.build-artifacts{type: 'button', 'data-toggle' => 'dropdown'}
|
- if playable.any?
|
||||||
= icon("download")
|
.btn-group
|
||||||
%b.caret
|
%a.dropdown-toggle.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'}
|
||||||
%ul.dropdown-menu.dropdown-menu-align-right
|
= icon("play")
|
||||||
- artifacts.each do |build|
|
%b.caret
|
||||||
|
%ul.dropdown-menu.dropdown-menu-align-right
|
||||||
%li
|
%li
|
||||||
= link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, build), rel: 'nofollow' do
|
= link_to play_namespace_project_build_path(@project.namespace, @project, build), rel: 'nofollow' do
|
||||||
= icon("download")
|
= icon("play")
|
||||||
%span Download '#{build.name}' artifacts
|
%span= playable.name.titleize
|
||||||
|
- if artifacts.present?
|
||||||
|
.btn-group
|
||||||
|
%a.dropdown-toggle.btn.btn-default.build-artifacts{type: 'button', 'data-toggle' => 'dropdown'}
|
||||||
|
= icon("download")
|
||||||
|
%b.caret
|
||||||
|
%ul.dropdown-menu.dropdown-menu-align-right
|
||||||
|
- artifacts.each do |build|
|
||||||
|
%li
|
||||||
|
= link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, build), rel: 'nofollow' do
|
||||||
|
= icon("download")
|
||||||
|
%span Download '#{build.name}' artifacts
|
||||||
|
|
||||||
- if can?(current_user, :update_pipeline, @project)
|
- if can?(current_user, :update_pipeline, @project)
|
||||||
.cancel-retry-btns.inline
|
.cancel-retry-btns.inline
|
||||||
|
|
|
@ -21,3 +21,5 @@
|
||||||
Retry
|
Retry
|
||||||
- else
|
- else
|
||||||
Rollback
|
Rollback
|
||||||
|
|
||||||
|
= render 'playable', deployment: deployment
|
||||||
|
|
12
app/views/projects/deployments/_playable.html.haml
Normal file
12
app/views/projects/deployments/_playable.html.haml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
- playable = deployment.playable_actions
|
||||||
|
- if playable.any?
|
||||||
|
.btn-group.inline
|
||||||
|
.btn-group
|
||||||
|
%a.dropdown-toggle.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'}
|
||||||
|
= icon("play")
|
||||||
|
%b.caret
|
||||||
|
%ul.dropdown-menu.dropdown-menu-align-right
|
||||||
|
%li
|
||||||
|
= link_to play_namespace_project_build_path(@project.namespace, @project, build), rel: 'nofollow' do
|
||||||
|
= icon("play")
|
||||||
|
%span= playable.name.titleize
|
|
@ -15,3 +15,7 @@
|
||||||
%td
|
%td
|
||||||
- if last_deployment
|
- if last_deployment
|
||||||
#{time_ago_with_tooltip(last_deployment.created_at)}
|
#{time_ago_with_tooltip(last_deployment.created_at)}
|
||||||
|
|
||||||
|
%td
|
||||||
|
- if can?(current_user, :create_deployment, last_deployment) && last_deployment.deployable
|
||||||
|
= render 'projects/deployments/playable', deployment: last_deployment
|
||||||
|
|
|
@ -750,6 +750,7 @@ Rails.application.routes.draw do
|
||||||
get :status
|
get :status
|
||||||
post :cancel
|
post :cancel
|
||||||
post :retry
|
post :retry
|
||||||
|
post :play
|
||||||
post :erase
|
post :erase
|
||||||
get :trace
|
get :trace
|
||||||
get :raw
|
get :raw
|
||||||
|
|
|
@ -194,8 +194,8 @@ module Ci
|
||||||
raise ValidationError, "#{name} job: allow_failure parameter should be an boolean"
|
raise ValidationError, "#{name} job: allow_failure parameter should be an boolean"
|
||||||
end
|
end
|
||||||
|
|
||||||
if job[:when] && !job[:when].in?(%w[on_success on_failure always])
|
if job[:when] && !job[:when].in?(%w[on_success on_failure always manual])
|
||||||
raise ValidationError, "#{name} job: when parameter should be on_success, on_failure or always"
|
raise ValidationError, "#{name} job: when parameter should be on_success, on_failure, always or manual"
|
||||||
end
|
end
|
||||||
|
|
||||||
if job[:environment] && !validate_environment(job[:environment])
|
if job[:environment] && !validate_environment(job[:environment])
|
||||||
|
|
|
@ -1141,7 +1141,7 @@ EOT
|
||||||
config = YAML.dump({ rspec: { script: "test", when: 1 } })
|
config = YAML.dump({ rspec: { script: "test", when: 1 } })
|
||||||
expect do
|
expect do
|
||||||
GitlabCiYamlProcessor.new(config, path)
|
GitlabCiYamlProcessor.new(config, path)
|
||||||
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always")
|
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure, always or manual")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns errors if job artifacts:name is not an a string" do
|
it "returns errors if job artifacts:name is not an a string" do
|
||||||
|
|
Loading…
Reference in a new issue