Merge branch '41249-clearing-the-cache' into 'master'
Resolve "Clearing the cache" Closes #41249 See merge request gitlab-org/gitlab-ce!16067
This commit is contained in:
commit
a7a7f8b159
|
@ -17,6 +17,11 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
|
||||
resetCachePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
ciLintPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -45,6 +50,14 @@ export default {
|
|||
Get started with Pipelines
|
||||
</a>
|
||||
|
||||
<a
|
||||
data-method="post"
|
||||
rel="nofollow"
|
||||
:href="resetCachePath"
|
||||
class="btn btn-default">
|
||||
Clear runner caches
|
||||
</a>
|
||||
|
||||
<a
|
||||
:href="ciLintPath"
|
||||
class="btn btn-default">
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
canCreatePipeline: pipelinesData.canCreatePipeline,
|
||||
hasCi: pipelinesData.hasCi,
|
||||
ciLintPath: pipelinesData.ciLintPath,
|
||||
resetCachePath: pipelinesData.resetCachePath,
|
||||
state: this.store.state,
|
||||
scope: getParameterByName('scope') || 'all',
|
||||
page: getParameterByName('page') || '1',
|
||||
|
@ -220,6 +221,7 @@
|
|||
:new-pipeline-path="newPipelinePath"
|
||||
:has-ci-enabled="hasCiEnabled"
|
||||
:help-page-path="helpPagePath"
|
||||
:resetCachePath="resetCachePath"
|
||||
:ci-lint-path="ciLintPath"
|
||||
:can-create-pipeline="canCreatePipelineParsed "
|
||||
/>
|
||||
|
|
|
@ -11,6 +11,16 @@ module Projects
|
|||
define_auto_devops_variables
|
||||
end
|
||||
|
||||
def reset_cache
|
||||
if ResetProjectCacheService.new(@project, current_user).execute
|
||||
flash[:notice] = _("Project cache successfully reset.")
|
||||
else
|
||||
flash[:error] = _("Unable to reset project cache.")
|
||||
end
|
||||
|
||||
redirect_to project_pipelines_path(@project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def define_runners_variables
|
||||
|
|
|
@ -461,7 +461,14 @@ module Ci
|
|||
end
|
||||
|
||||
def cache
|
||||
[options[:cache]]
|
||||
cache = options[:cache]
|
||||
|
||||
if cache && project.jobs_cache_index
|
||||
cache = cache.merge(
|
||||
key: "#{cache[:key]}:#{project.jobs_cache_index}")
|
||||
end
|
||||
|
||||
[cache]
|
||||
end
|
||||
|
||||
def credentials
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class ResetProjectCacheService < BaseService
|
||||
def execute
|
||||
@project.increment!(:jobs_cache_index)
|
||||
end
|
||||
end
|
|
@ -10,7 +10,8 @@
|
|||
"new-pipeline-path" => new_project_pipeline_path(@project),
|
||||
"can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
|
||||
"has-ci" => @repository.gitlab_ci_yml,
|
||||
"ci-lint-path" => ci_lint_path } }
|
||||
"ci-lint-path" => ci_lint_path,
|
||||
"reset-cache-path" => reset_cache_project_settings_ci_cd_path(@project) } }
|
||||
|
||||
= page_specific_javascript_bundle_tag('common_vue')
|
||||
= page_specific_javascript_bundle_tag('pipelines')
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Implement project jobs cache reset
|
||||
merge_request: 16067
|
||||
author:
|
||||
type: added
|
|
@ -408,7 +408,9 @@ constraints(ProjectUrlConstrainer.new) do
|
|||
end
|
||||
namespace :settings do
|
||||
get :members, to: redirect("%{namespace_id}/%{project_id}/project_members")
|
||||
resource :ci_cd, only: [:show], controller: 'ci_cd'
|
||||
resource :ci_cd, only: [:show], controller: 'ci_cd' do
|
||||
post :reset_cache
|
||||
end
|
||||
resource :integrations, only: [:show]
|
||||
resource :repository, only: [:show], controller: :repository
|
||||
end
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class AddJobsCacheIndexToProject < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
# Set this constant to true if this migration requires downtime.
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
add_column :projects, :jobs_cache_index, :integer
|
||||
end
|
||||
end
|
|
@ -1451,6 +1451,7 @@ ActiveRecord::Schema.define(version: 20171230123729) do
|
|||
t.boolean "repository_read_only"
|
||||
t.boolean "merge_requests_ff_only_enabled", default: false
|
||||
t.boolean "merge_requests_rebase_enabled", default: false, null: false
|
||||
t.integer "jobs_cache_index"
|
||||
end
|
||||
|
||||
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
|
||||
|
|
|
@ -17,4 +17,51 @@ describe Projects::Settings::CiCdController do
|
|||
expect(response).to render_template(:show)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reset_cache' do
|
||||
before do
|
||||
sign_in(user)
|
||||
|
||||
project.add_master(user)
|
||||
|
||||
allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true)
|
||||
end
|
||||
|
||||
subject { post :reset_cache, namespace_id: project.namespace, project_id: project }
|
||||
|
||||
it 'calls reset project cache service' do
|
||||
expect(ResetProjectCacheService).to receive_message_chain(:new, :execute)
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
it 'redirects to project pipelines path' do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:redirect)
|
||||
expect(response).to redirect_to(project_pipelines_path(project))
|
||||
end
|
||||
|
||||
context 'when service returns successfully' do
|
||||
it 'sets the flash notice variable' do
|
||||
subject
|
||||
|
||||
expect(controller).to set_flash[:notice]
|
||||
expect(controller).not_to set_flash[:error]
|
||||
end
|
||||
end
|
||||
|
||||
context 'when service does not return successfully' do
|
||||
before do
|
||||
allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false)
|
||||
end
|
||||
|
||||
it 'sets the flash error variable' do
|
||||
subject
|
||||
|
||||
expect(controller).not_to set_flash[:notice]
|
||||
expect(controller).to set_flash[:error]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -545,6 +545,40 @@ describe 'Pipelines', :js do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Reset runner caches' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
before do
|
||||
create(:ci_empty_pipeline, status: 'success', project: project, sha: project.commit.id, ref: 'master')
|
||||
project.add_master(user)
|
||||
visit project_pipelines_path(project)
|
||||
end
|
||||
|
||||
it 'has a clear caches button' do
|
||||
expect(page).to have_link 'Clear runner caches'
|
||||
end
|
||||
|
||||
describe 'user clicks the button' do
|
||||
context 'when project already has jobs_cache_index' do
|
||||
before do
|
||||
project.update_attributes(jobs_cache_index: 1)
|
||||
end
|
||||
|
||||
it 'increments jobs_cache_index' do
|
||||
click_link 'Clear runner caches'
|
||||
expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project does not have jobs_cache_index' do
|
||||
it 'sets jobs_cache_index to 1' do
|
||||
click_link 'Clear runner caches'
|
||||
expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not logged in' do
|
||||
|
|
|
@ -7,4 +7,6 @@
|
|||
"new-pipeline-path" => 'foo',
|
||||
"can-create-pipeline" => 'true',
|
||||
"has-ci" => 'foo',
|
||||
"ci-lint-path" => 'foo' } }
|
||||
"ci-lint-path" => 'foo',
|
||||
"reset-cache-path" => 'foo' } }
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ describe('Pipelines Nav Controls', () => {
|
|||
hasCiEnabled: true,
|
||||
helpPagePath: 'foo',
|
||||
ciLintPath: 'foo',
|
||||
resetCachePath: 'foo',
|
||||
canCreatePipeline: true,
|
||||
};
|
||||
|
||||
|
@ -31,6 +32,7 @@ describe('Pipelines Nav Controls', () => {
|
|||
hasCiEnabled: true,
|
||||
helpPagePath: 'foo',
|
||||
ciLintPath: 'foo',
|
||||
resetCachePath: 'foo',
|
||||
canCreatePipeline: false,
|
||||
};
|
||||
|
||||
|
@ -41,12 +43,31 @@ describe('Pipelines Nav Controls', () => {
|
|||
expect(component.$el.querySelector('.btn-create')).toEqual(null);
|
||||
});
|
||||
|
||||
it('should render link for resetting runner caches', () => {
|
||||
const mockData = {
|
||||
newPipelinePath: 'foo',
|
||||
hasCiEnabled: true,
|
||||
helpPagePath: 'foo',
|
||||
ciLintPath: 'foo',
|
||||
resetCachePath: 'foo',
|
||||
canCreatePipeline: false,
|
||||
};
|
||||
|
||||
const component = new NavControlsComponent({
|
||||
propsData: mockData,
|
||||
}).$mount();
|
||||
|
||||
expect(component.$el.querySelectorAll('.btn-default')[0].textContent).toContain('Clear runner caches');
|
||||
expect(component.$el.querySelectorAll('.btn-default')[0].getAttribute('href')).toEqual(mockData.resetCachePath);
|
||||
});
|
||||
|
||||
it('should render link for CI lint', () => {
|
||||
const mockData = {
|
||||
newPipelinePath: 'foo',
|
||||
hasCiEnabled: true,
|
||||
helpPagePath: 'foo',
|
||||
ciLintPath: 'foo',
|
||||
resetCachePath: 'foo',
|
||||
canCreatePipeline: true,
|
||||
};
|
||||
|
||||
|
@ -54,8 +75,8 @@ describe('Pipelines Nav Controls', () => {
|
|||
propsData: mockData,
|
||||
}).$mount();
|
||||
|
||||
expect(component.$el.querySelector('.btn-default').textContent).toContain('CI Lint');
|
||||
expect(component.$el.querySelector('.btn-default').getAttribute('href')).toEqual(mockData.ciLintPath);
|
||||
expect(component.$el.querySelectorAll('.btn-default')[1].textContent).toContain('CI Lint');
|
||||
expect(component.$el.querySelectorAll('.btn-default')[1].getAttribute('href')).toEqual(mockData.ciLintPath);
|
||||
});
|
||||
|
||||
it('should render link to help page when CI is not enabled', () => {
|
||||
|
@ -64,6 +85,7 @@ describe('Pipelines Nav Controls', () => {
|
|||
hasCiEnabled: false,
|
||||
helpPagePath: 'foo',
|
||||
ciLintPath: 'foo',
|
||||
resetCachePath: 'foo',
|
||||
canCreatePipeline: true,
|
||||
};
|
||||
|
||||
|
@ -81,6 +103,7 @@ describe('Pipelines Nav Controls', () => {
|
|||
hasCiEnabled: true,
|
||||
helpPagePath: 'foo',
|
||||
ciLintPath: 'foo',
|
||||
resetCachePath: 'foo',
|
||||
canCreatePipeline: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -459,6 +459,7 @@ Project:
|
|||
- delete_error
|
||||
- merge_requests_ff_only_enabled
|
||||
- merge_requests_rebase_enabled
|
||||
- jobs_cache_index
|
||||
Author:
|
||||
- name
|
||||
ProjectFeature:
|
||||
|
|
|
@ -255,6 +255,42 @@ describe Ci::Build do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#cache' do
|
||||
let(:options) { { cache: { key: "key", paths: ["public"], policy: "pull-push" } } }
|
||||
|
||||
subject { build.cache }
|
||||
|
||||
context 'when build has cache' do
|
||||
before do
|
||||
allow(build).to receive(:options).and_return(options)
|
||||
end
|
||||
|
||||
context 'when project has jobs_cache_index' do
|
||||
before do
|
||||
allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1)
|
||||
end
|
||||
|
||||
it { is_expected.to be_an(Array).and all(include(key: "key:1")) }
|
||||
end
|
||||
|
||||
context 'when project does not have jobs_cache_index' do
|
||||
before do
|
||||
allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(nil)
|
||||
end
|
||||
|
||||
it { is_expected.to eq([options[:cache]]) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when build does not have cache' do
|
||||
before do
|
||||
allow(build).to receive(:options).and_return({})
|
||||
end
|
||||
|
||||
it { is_expected.to eq([nil]) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#depends_on_builds' do
|
||||
let!(:build) { create(:ci_build, pipeline: pipeline, name: 'build', stage_idx: 0, stage: 'build') }
|
||||
let!(:rspec_test) { create(:ci_build, pipeline: pipeline, name: 'rspec', stage_idx: 1, stage: 'test') }
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ResetProjectCacheService do
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
subject { described_class.new(project, user).execute }
|
||||
|
||||
context 'when project cache_index is nil' do
|
||||
before do
|
||||
project.jobs_cache_index = nil
|
||||
end
|
||||
|
||||
it 'sets project cache_index to one' do
|
||||
expect { subject }.to change { project.reload.jobs_cache_index }.from(nil).to(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project cache_index is a numeric value' do
|
||||
before do
|
||||
project.update_attributes(jobs_cache_index: 1)
|
||||
end
|
||||
|
||||
it 'increments project cache index' do
|
||||
expect { subject }.to change { project.reload.jobs_cache_index }.by(1)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue