Add implementation of manual actions

This commit is contained in:
Kamil Trzcinski 2016-07-16 18:39:58 +02:00
parent 4e898b9b5e
commit 7d0fe1f04e
12 changed files with 96 additions and 17 deletions

View file

@ -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)

View file

@ -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

View file

@ -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?

View file

@ -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

View file

@ -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')

View file

@ -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

View file

@ -21,3 +21,5 @@
Retry Retry
- else - else
Rollback Rollback
= render 'playable', deployment: deployment

View 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

View file

@ -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

View file

@ -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

View file

@ -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])

View file

@ -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