Allow to pause,resume,show,edit,destroy group runners (#10244)
This commit is contained in:
		
							parent
							
								
									1ef9e9c2aa
								
							
						
					
					
						commit
						91f358942e
					
				|  | @ -0,0 +1,54 @@ | |||
| class Groups::RunnersController < Groups::ApplicationController | ||||
|   before_action :authorize_admin_pipeline! | ||||
|   before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show] | ||||
| 
 | ||||
|   def show | ||||
|   end | ||||
| 
 | ||||
|   def edit | ||||
|   end | ||||
| 
 | ||||
|   def update | ||||
|     if Ci::UpdateRunnerService.new(@runner).update(runner_params) | ||||
|       redirect_to group_runner_path(@group, @runner), notice: 'Runner was successfully updated.' | ||||
|     else | ||||
|       render 'edit' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def destroy | ||||
|     @runner.destroy | ||||
| 
 | ||||
|     redirect_to group_settings_ci_cd_path(@group), status: 302 | ||||
|   end | ||||
| 
 | ||||
|   def resume | ||||
|     if Ci::UpdateRunnerService.new(@runner).update(active: true) | ||||
|       redirect_to group_settings_ci_cd_path(@group), notice: 'Runner was successfully updated.' | ||||
|     else | ||||
|       redirect_to group_settings_ci_cd_path(@group), alert: 'Runner was not updated.' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def pause | ||||
|     if Ci::UpdateRunnerService.new(@runner).update(active: false) | ||||
|       redirect_to group_settings_ci_cd_path(@group), notice: 'Runner was successfully updated.' | ||||
|     else | ||||
|       redirect_to group_settings_ci_cd_path(@group), alert: 'Runner was not updated.' | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   private | ||||
| 
 | ||||
|   def set_runner | ||||
|     @runner ||= @group.runners.find(params[:id]) | ||||
|   end | ||||
| 
 | ||||
|   def authorize_admin_pipeline! | ||||
|     return render_404 unless can?(current_user, :admin_pipeline, group) | ||||
|   end | ||||
| 
 | ||||
|   def runner_params | ||||
|     params.require(:runner).permit(Ci::Runner::FORM_EDITABLE) | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,38 @@ | |||
| = form_for runner, url: runner_form_url, html: { class: 'form-horizontal' } do |f| | ||||
|   = form_errors(runner) | ||||
|   .form-group | ||||
|     = label :active, "Active", class: 'control-label' | ||||
|     .col-sm-10 | ||||
|       .checkbox | ||||
|         = f.check_box :active | ||||
|         %span.light Paused Runners don't accept new jobs | ||||
|   .form-group | ||||
|     = label :protected, "Protected", class: 'control-label' | ||||
|     .col-sm-10 | ||||
|       .checkbox | ||||
|         = f.check_box :access_level, {}, 'ref_protected', 'not_protected' | ||||
|         %span.light This runner will only run on pipelines triggered on protected branches | ||||
|   .form-group | ||||
|     = label :run_untagged, 'Run untagged jobs', class: 'control-label' | ||||
|     .col-sm-10 | ||||
|       .checkbox | ||||
|         = f.check_box :run_untagged | ||||
|         %span.light Indicates whether this runner can pick jobs without tags | ||||
|   .form-group | ||||
|     = label_tag :token, class: 'control-label' do | ||||
|       Token | ||||
|     .col-sm-10 | ||||
|       = f.text_field :token, class: 'form-control', readonly: true | ||||
|   .form-group | ||||
|     = label_tag :description, class: 'control-label' do | ||||
|       Description | ||||
|     .col-sm-10 | ||||
|       = f.text_field :description, class: 'form-control' | ||||
|   .form-group | ||||
|     = label_tag :tag_list, class: 'control-label' do | ||||
|       Tags | ||||
|     .col-sm-10 | ||||
|       = f.text_field :tag_list, value: runner.tag_list.sort.join(', '), class: 'form-control' | ||||
|       .help-block You can setup jobs to only use Runners with specific tags. Separate tags with commas. | ||||
|   .form-actions | ||||
|     = f.submit 'Save changes', class: 'btn btn-save' | ||||
|  | @ -2,9 +2,18 @@ | |||
|   %h4 | ||||
|     = runner_status_icon(runner) | ||||
| 
 | ||||
|   %span.commit-sha | ||||
|     = runner.short_sha | ||||
|     = link_to runner.short_sha, group_runner_path(@group, runner), class: 'commit-sha' | ||||
| 
 | ||||
|     %small.edit-runner | ||||
|       = link_to edit_group_runner_path(@group, runner) do | ||||
|         %i.fa.fa-edit.btn | ||||
| 
 | ||||
|     .pull-right | ||||
|       - if runner.active? | ||||
|         = link_to 'Pause', pause_group_runner_path(@group, runner), method: :post, class: 'btn btn-sm btn-danger', data: { confirm: "Are you sure?" } | ||||
|       - else | ||||
|         = link_to 'Resume', resume_group_runner_path(@group, runner), method: :post, class: 'btn btn-success btn-sm' | ||||
|       = link_to 'Remove Runner', group_runner_path(@group, runner), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm' | ||||
|   .pull-right | ||||
|     %small.light | ||||
|       \##{runner.id} | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| - page_title "Edit", "#{@runner.description} ##{@runner.id}", "Runners" | ||||
| 
 | ||||
| %h4 Runner ##{@runner.id} | ||||
| 
 | ||||
| %hr | ||||
|   = render 'form', runner: @runner, runner_form_url: group_runner_path(@group, @runner) | ||||
|  | @ -0,0 +1,51 @@ | |||
| - page_title "#{@runner.description} ##{@runner.id}", "Runners" | ||||
| 
 | ||||
| %h3.page-title | ||||
|   Runner ##{@runner.id} | ||||
| 
 | ||||
| .table-holder | ||||
|   %table.table | ||||
|     %thead | ||||
|       %tr | ||||
|         %th Property Name | ||||
|         %th Value | ||||
|     %tr | ||||
|       %td Active | ||||
|       %td= @runner.active? ? 'Yes' : 'No' | ||||
|     %tr | ||||
|       %td Protected | ||||
|       %td= @runner.ref_protected? ? 'Yes' : 'No' | ||||
|     %tr | ||||
|       %td Can run untagged jobs | ||||
|       %td= @runner.run_untagged? ? 'Yes' : 'No' | ||||
|     %tr | ||||
|       %td Tags | ||||
|       %td | ||||
|         - @runner.tag_list.sort.each do |tag| | ||||
|           %span.label.label-primary | ||||
|             = tag | ||||
|     %tr | ||||
|       %td Name | ||||
|       %td= @runner.name | ||||
|     %tr | ||||
|       %td Version | ||||
|       %td= @runner.version | ||||
|     %tr | ||||
|       %td Revision | ||||
|       %td= @runner.revision | ||||
|     %tr | ||||
|       %td Platform | ||||
|       %td= @runner.platform | ||||
|     %tr | ||||
|       %td Architecture | ||||
|       %td= @runner.architecture | ||||
|     %tr | ||||
|       %td Description | ||||
|       %td= @runner.description | ||||
|     %tr | ||||
|       %td Last contact | ||||
|       %td | ||||
|         - if @runner.contacted_at | ||||
|           #{time_ago_in_words(@runner.contacted_at)} ago | ||||
|         - else | ||||
|           Never | ||||
|  | @ -58,6 +58,13 @@ constraints(::Constraints::GroupUrlConstrainer.new) do | |||
| 
 | ||||
|     # On CE only index and show actions are needed | ||||
|     resources :boards, only: [:index, :show] | ||||
| 
 | ||||
|     resources :runners, only: [:index, :edit, :update, :destroy, :show] do | ||||
|       member do | ||||
|         post :resume | ||||
|         post :pause | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   scope(path: '*id', | ||||
|  |  | |||
|  | @ -0,0 +1,74 @@ | |||
| require 'spec_helper' | ||||
| 
 | ||||
| describe Groups::RunnersController do | ||||
|   let(:user) { create(:user) } | ||||
|   let(:group) { create(:group) } | ||||
|   let(:runner) { create(:ci_runner) } | ||||
| 
 | ||||
|   let(:params) do | ||||
|     { | ||||
|       group_id: group, | ||||
|       id: runner | ||||
|     } | ||||
|   end | ||||
| 
 | ||||
|   before do | ||||
|     sign_in(user) | ||||
|     group.add_master(user) | ||||
|     group.runners << runner | ||||
|   end | ||||
| 
 | ||||
|   describe '#update' do | ||||
|     it 'updates the runner and ticks the queue' do | ||||
|       new_desc = runner.description.swapcase | ||||
| 
 | ||||
|       expect do | ||||
|         post :update, params.merge(runner: { description: new_desc } ) | ||||
|       end.to change { runner.ensure_runner_queue_value } | ||||
| 
 | ||||
|       runner.reload | ||||
| 
 | ||||
|       expect(response).to have_gitlab_http_status(302) | ||||
|       expect(runner.description).to eq(new_desc) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#destroy' do | ||||
|     it 'destroys the runner' do | ||||
|       delete :destroy, params | ||||
| 
 | ||||
|       expect(response).to have_gitlab_http_status(302) | ||||
|       expect(Ci::Runner.find_by(id: runner.id)).to be_nil | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#resume' do | ||||
|     it 'marks the runner as active and ticks the queue' do | ||||
|       runner.update(active: false) | ||||
| 
 | ||||
|       expect do | ||||
|         post :resume, params | ||||
|       end.to change { runner.ensure_runner_queue_value } | ||||
| 
 | ||||
|       runner.reload | ||||
| 
 | ||||
|       expect(response).to have_gitlab_http_status(302) | ||||
|       expect(runner.active).to eq(true) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#pause' do | ||||
|     it 'marks the runner as inactive and ticks the queue' do | ||||
|       runner.update(active: true) | ||||
| 
 | ||||
|       expect do | ||||
|         post :pause, params | ||||
|       end.to change { runner.ensure_runner_queue_value } | ||||
| 
 | ||||
|       runner.reload | ||||
| 
 | ||||
|       expect(response).to have_gitlab_http_status(302) | ||||
|       expect(runner.active).to eq(false) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -182,7 +182,7 @@ feature 'Runners' do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'group runners' do | ||||
|   context 'group runners in project settings' do | ||||
|     background do | ||||
|       project.add_master(user) | ||||
|     end | ||||
|  | @ -200,10 +200,10 @@ feature 'Runners' do | |||
|         scenario 'group runners are not available' do | ||||
|           visit project_runners_path(project) | ||||
| 
 | ||||
|           expect(page).to have_content 'This group does not provide any group Runners yet.' | ||||
|           expect(page).to have_content 'This group does not provide any group Runners yet' | ||||
| 
 | ||||
|           expect(page).to have_content 'Setup a group Runner manually' | ||||
|           expect(page).not_to have_content 'Ask your group master to setup a group Runner.' | ||||
|           expect(page).to have_content 'Group masters can register group runners in the Group CI/CD settings' | ||||
|           expect(page).not_to have_content 'Ask your group master to setup a group Runner' | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|  | @ -228,7 +228,7 @@ feature 'Runners' do | |||
| 
 | ||||
|           expect(page).to have_content 'This group does not provide any group Runners yet.' | ||||
| 
 | ||||
|           expect(page).not_to have_content 'Setup a group Runner manually' | ||||
|           expect(page).not_to have_content 'Group masters can register group runners in the Group CI/CD settings' | ||||
|           expect(page).to have_content 'Ask your group master to setup a group Runner.' | ||||
|         end | ||||
|       end | ||||
|  | @ -261,4 +261,98 @@ feature 'Runners' do | |||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context 'group runners in group settings' do | ||||
|     given(:group) { create :group } | ||||
|     background do | ||||
|       group.add_master(user) | ||||
|     end | ||||
| 
 | ||||
|     context 'group with no runners' do | ||||
|       scenario 'there are no runners displayed' do | ||||
|         visit group_settings_ci_cd_path(group) | ||||
| 
 | ||||
|         expect(page).to have_content 'This group does not provide any group Runners yet' | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'group with a runner' do | ||||
|       let!(:runner) { create :ci_runner, groups: [group], description: 'group-runner' } | ||||
| 
 | ||||
|       scenario 'the runner is visible' do | ||||
|         visit group_settings_ci_cd_path(group) | ||||
| 
 | ||||
|         expect(page).not_to have_content 'This group does not provide any group Runners yet' | ||||
|         expect(page).to have_content 'Available group Runners : 1' | ||||
|         expect(page).to have_content 'group-runner' | ||||
|       end | ||||
| 
 | ||||
|       scenario 'user can pause and resume the group runner' do | ||||
|         visit group_settings_ci_cd_path(group) | ||||
| 
 | ||||
|         expect(page).to have_content('Pause') | ||||
|         expect(page).not_to have_content('Resume') | ||||
| 
 | ||||
|         click_on 'Pause' | ||||
| 
 | ||||
|         expect(page).not_to have_content('Pause') | ||||
|         expect(page).to have_content('Resume') | ||||
| 
 | ||||
|         click_on 'Resume' | ||||
| 
 | ||||
|         expect(page).to have_content('Pause') | ||||
|         expect(page).not_to have_content('Resume') | ||||
|       end | ||||
| 
 | ||||
|       scenario 'user can view runner details' do | ||||
|         visit group_settings_ci_cd_path(group) | ||||
| 
 | ||||
|         expect(page).to have_content(runner.display_name) | ||||
| 
 | ||||
|         click_on runner.short_sha | ||||
| 
 | ||||
|         expect(page).to have_content(runner.platform) | ||||
|       end | ||||
| 
 | ||||
|       scenario 'user can remove a group runner' do | ||||
|         visit group_settings_ci_cd_path(group) | ||||
| 
 | ||||
|         click_on 'Remove Runner' | ||||
| 
 | ||||
|         expect(page).not_to have_content(runner.display_name) | ||||
|       end | ||||
| 
 | ||||
|       scenario 'user edits the runner to be protected' do | ||||
|         visit group_settings_ci_cd_path(group) | ||||
| 
 | ||||
|         first('.edit-runner > a').click | ||||
| 
 | ||||
|         expect(page.find_field('runner[access_level]')).not_to be_checked | ||||
| 
 | ||||
|         check 'runner_access_level' | ||||
|         click_button 'Save changes' | ||||
| 
 | ||||
|         expect(page).to have_content 'Protected Yes' | ||||
|       end | ||||
| 
 | ||||
|       context 'when a runner has a tag' do | ||||
|         background do | ||||
|           runner.update(tag_list: ['tag']) | ||||
|         end | ||||
| 
 | ||||
|         scenario 'user edits runner not to run untagged jobs' do | ||||
|           visit group_settings_ci_cd_path(group) | ||||
| 
 | ||||
|           first('.edit-runner > a').click | ||||
| 
 | ||||
|           expect(page.find_field('runner[run_untagged]')).to be_checked | ||||
| 
 | ||||
|           uncheck 'runner_run_untagged' | ||||
|           click_button 'Save changes' | ||||
| 
 | ||||
|           expect(page).to have_content 'Can run untagged jobs No' | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue