Merge remote-tracking branch 'upstream/pipeline-hooks-without-slack' into wall-clock-time-for-showing-pipeline
* upstream/pipeline-hooks-without-slack: Make explicit call for all event types for ProjectHook factory Capitalise URL on web_hooks/form Remove changes not related to this MR Added documentation for pipeline hooks Rename queue to enqueue in tests Instrument Project.visible_to_user Fix build play failure Update ruby 2.3.1 Improve transition between states for event `enqueue` Use event `enqueue` instead of `queue` Fix test failures Fix bug where destroying a namespace would not always destroy projects Remove unused SpamReport model; this was renamed to SpamLog Corrected links/usernames in performance guide Add gravatars to build history Add deployment ID and gravatar to environments page Format environment history page Add avatar to commit message; environment style updates to match pipelines page Style deploy button
This commit is contained in:
commit
0ea81ae50a
37 changed files with 466 additions and 108 deletions
|
@ -1,7 +1,7 @@
|
||||||
image: "ruby:2.3"
|
image: "ruby:2.3.1"
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
key: "ruby-23"
|
key: "ruby-231"
|
||||||
paths:
|
paths:
|
||||||
- vendor/apt
|
- vendor/apt
|
||||||
- vendor/ruby
|
- vendor/ruby
|
||||||
|
|
|
@ -26,6 +26,7 @@ v 8.11.0 (unreleased)
|
||||||
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
|
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
|
||||||
- Show wall clock time when showing a pipeline. !5734
|
- Show wall clock time when showing a pipeline. !5734
|
||||||
- Show member roles to all users on members page
|
- Show member roles to all users on members page
|
||||||
|
- Project.visible_to_user is instrumented again
|
||||||
- Fix awardable button mutuality loading spinners (ClemMakesApps)
|
- Fix awardable button mutuality loading spinners (ClemMakesApps)
|
||||||
- Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable
|
- Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable
|
||||||
- Optimize maximum user access level lookup in loading of notes
|
- Optimize maximum user access level lookup in loading of notes
|
||||||
|
@ -94,6 +95,7 @@ v 8.11.0 (unreleased)
|
||||||
- Bump gitlab_git to lazy load compare commits
|
- Bump gitlab_git to lazy load compare commits
|
||||||
- Reduce number of queries made for merge_requests/:id/diffs
|
- Reduce number of queries made for merge_requests/:id/diffs
|
||||||
- Sensible state specific default sort order for issues and merge requests !5453 (tomb0y)
|
- Sensible state specific default sort order for issues and merge requests !5453 (tomb0y)
|
||||||
|
- Fix bug where destroying a namespace would not always destroy projects
|
||||||
- Fix RequestProfiler::Middleware error when code is reloaded in development
|
- Fix RequestProfiler::Middleware error when code is reloaded in development
|
||||||
- Catch what warden might throw when profiling requests to re-throw it
|
- Catch what warden might throw when profiling requests to re-throw it
|
||||||
- Avoid commit lookup on diff_helper passing existing local variable to the helper method
|
- Avoid commit lookup on diff_helper passing existing local variable to the helper method
|
||||||
|
|
|
@ -1,5 +1,35 @@
|
||||||
.environments {
|
.environments {
|
||||||
|
|
||||||
.commit-title {
|
.commit-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fa-play {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-new {
|
||||||
|
color: $table-text-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
margin-right: 6px;
|
||||||
|
color: $table-text-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.branch-name {
|
||||||
|
color: $gl-dark-link-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table.builds.environments {
|
||||||
|
min-width: 500px;
|
||||||
|
|
||||||
|
.icon-container {
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,9 @@ class Admin::GroupsController < Admin::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
DestroyGroupService.new(@group, current_user).execute
|
DestroyGroupService.new(@group, current_user).async_execute
|
||||||
|
|
||||||
redirect_to admin_groups_path, notice: 'Group was successfully deleted.'
|
redirect_to admin_groups_path, alert: "Group '#{@group.name}' was scheduled for deletion."
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -87,9 +87,9 @@ class GroupsController < Groups::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
DestroyGroupService.new(@group, current_user).execute
|
DestroyGroupService.new(@group, current_user).async_execute
|
||||||
|
|
||||||
redirect_to root_path, alert: "Group '#{@group.name}' was successfully deleted."
|
redirect_to root_path, alert: "Group '#{@group.name}' was scheduled for deletion."
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -7,8 +7,6 @@ module AvatarsHelper
|
||||||
}))
|
}))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def user_avatar(options = {})
|
def user_avatar(options = {})
|
||||||
avatar_size = options[:size] || 16
|
avatar_size = options[:size] || 16
|
||||||
user_name = options[:user].try(:name) || options[:user_name]
|
user_name = options[:user].try(:name) || options[:user_name]
|
||||||
|
|
|
@ -59,7 +59,7 @@ module Ci
|
||||||
when: build.when,
|
when: build.when,
|
||||||
user: user,
|
user: user,
|
||||||
environment: build.environment,
|
environment: build.environment,
|
||||||
status_event: 'queue'
|
status_event: 'enqueue'
|
||||||
)
|
)
|
||||||
MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build)
|
MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build)
|
||||||
new_build
|
new_build
|
||||||
|
@ -102,7 +102,7 @@ module Ci
|
||||||
|
|
||||||
def play(current_user = nil)
|
def play(current_user = nil)
|
||||||
# Try to queue a current build
|
# Try to queue a current build
|
||||||
if self.queue
|
if self.enqueue
|
||||||
self.update(user: current_user)
|
self.update(user: current_user)
|
||||||
self
|
self
|
||||||
else
|
else
|
||||||
|
|
|
@ -22,9 +22,9 @@ module Ci
|
||||||
delegate :stages, to: :statuses
|
delegate :stages, to: :statuses
|
||||||
|
|
||||||
state_machine :status, initial: :created do
|
state_machine :status, initial: :created do
|
||||||
event :queue do
|
event :enqueue do
|
||||||
transition created: :pending
|
transition created: :pending
|
||||||
transition any - [:created, :pending] => :running
|
transition [:success, :failed, :canceled, :skipped] => :running
|
||||||
end
|
end
|
||||||
|
|
||||||
event :run do
|
event :run do
|
||||||
|
@ -234,18 +234,12 @@ module Ci
|
||||||
|
|
||||||
def build_updated
|
def build_updated
|
||||||
case latest_builds_status
|
case latest_builds_status
|
||||||
when 'pending'
|
when 'pending' then enqueue
|
||||||
queue
|
when 'running' then run
|
||||||
when 'running'
|
when 'success' then succeed
|
||||||
run
|
when 'failed' then drop
|
||||||
when 'success'
|
when 'canceled' then cancel
|
||||||
succeed
|
when 'skipped' then skip
|
||||||
when 'failed'
|
|
||||||
drop
|
|
||||||
when 'canceled'
|
|
||||||
cancel
|
|
||||||
when 'skipped'
|
|
||||||
skip
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class CommitStatus < ActiveRecord::Base
|
||||||
scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) }
|
scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) }
|
||||||
|
|
||||||
state_machine :status do
|
state_machine :status do
|
||||||
event :queue do
|
event :enqueue do
|
||||||
transition [:created, :skipped] => :pending
|
transition [:created, :skipped] => :pending
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
class Namespace < ActiveRecord::Base
|
class Namespace < ActiveRecord::Base
|
||||||
|
acts_as_paranoid
|
||||||
|
|
||||||
include Sortable
|
include Sortable
|
||||||
include Gitlab::ShellAdapter
|
include Gitlab::ShellAdapter
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
class SpamReport < ActiveRecord::Base
|
|
||||||
belongs_to :user
|
|
||||||
|
|
||||||
validates :user, presence: true
|
|
||||||
end
|
|
|
@ -37,7 +37,7 @@ module Ci
|
||||||
return false unless Statuseable::COMPLETED_STATUSES.include?(current_status)
|
return false unless Statuseable::COMPLETED_STATUSES.include?(current_status)
|
||||||
|
|
||||||
if valid_statuses_for_when(build.when).include?(current_status)
|
if valid_statuses_for_when(build.when).include?(current_status)
|
||||||
build.queue
|
build.enqueue
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
build.skip
|
build.skip
|
||||||
|
|
|
@ -21,6 +21,11 @@ class DeleteUserService
|
||||||
::Projects::DestroyService.new(project, current_user, skip_repo: true).async_execute
|
::Projects::DestroyService.new(project, current_user, skip_repo: true).async_execute
|
||||||
end
|
end
|
||||||
|
|
||||||
user.destroy
|
# Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
|
||||||
|
namespace = user.namespace
|
||||||
|
user_data = user.destroy
|
||||||
|
namespace.really_destroy!
|
||||||
|
|
||||||
|
user_data
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,13 +5,23 @@ class DestroyGroupService
|
||||||
@group, @current_user = group, user
|
@group, @current_user = group, user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def async_execute
|
||||||
|
group.transaction do
|
||||||
|
# Soft delete via paranoia gem
|
||||||
|
group.destroy
|
||||||
|
job_id = GroupDestroyWorker.perform_async(group.id, current_user.id)
|
||||||
|
Rails.logger.info("User #{current_user.id} scheduled a deletion of group ID #{group.id} with job ID #{job_id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
group.projects.each do |project|
|
group.projects.each do |project|
|
||||||
|
# Execute the destruction of the models immediately to ensure atomic cleanup.
|
||||||
# Skip repository removal because we remove directory with namespace
|
# Skip repository removal because we remove directory with namespace
|
||||||
# that contain all this repositories
|
# that contain all these repositories
|
||||||
::Projects::DestroyService.new(project, current_user, skip_repo: true).async_execute
|
::Projects::DestroyService.new(project, current_user, skip_repo: true).execute
|
||||||
end
|
end
|
||||||
|
|
||||||
group.destroy
|
group.really_destroy!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
.pull-right
|
.pull-right
|
||||||
- actions = deployment.manual_actions
|
- actions = deployment.manual_actions
|
||||||
- if actions.present?
|
- if actions.present?
|
||||||
.btn-group.inline
|
.inline
|
||||||
.btn-group
|
.dropdown
|
||||||
%a.dropdown-toggle.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'}
|
%a.dropdown-new.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'}
|
||||||
= icon("play")
|
= icon("play")
|
||||||
%b.caret
|
%b.caret
|
||||||
%ul.dropdown-menu.dropdown-menu-align-right
|
%ul.dropdown-menu.dropdown-menu-align-right
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
%div.branch-commit
|
%div.branch-commit
|
||||||
- if deployment.ref
|
- if deployment.ref
|
||||||
= link_to deployment.ref, namespace_project_commits_path(@project.namespace, @project, deployment.ref), class: "monospace"
|
.icon-container
|
||||||
·
|
= deployment.tag? ? icon('tag') : icon('code-fork')
|
||||||
|
= link_to deployment.ref, namespace_project_commits_path(@project.namespace, @project, deployment.ref), class: "monospace branch-name"
|
||||||
|
.icon-container
|
||||||
|
= custom_icon("icon_commit")
|
||||||
= link_to deployment.short_sha, namespace_project_commit_path(@project.namespace, @project, deployment.sha), class: "commit-id monospace"
|
= link_to deployment.short_sha, namespace_project_commit_path(@project.namespace, @project, deployment.sha), class: "commit-id monospace"
|
||||||
|
|
||||||
%p.commit-title
|
%p.commit-title
|
||||||
%span
|
%span
|
||||||
- if commit_title = deployment.commit_title
|
- if commit_title = deployment.commit_title
|
||||||
|
= author_avatar(deployment.commit, size: 20)
|
||||||
= link_to_gfm commit_title, namespace_project_commit_path(@project.namespace, @project, deployment.sha), class: "commit-row-message"
|
= link_to_gfm commit_title, namespace_project_commit_path(@project.namespace, @project, deployment.sha), class: "commit-row-message"
|
||||||
- else
|
- else
|
||||||
Cant find HEAD commit for this branch
|
Cant find HEAD commit for this branch
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
%td
|
%td
|
||||||
- if deployment.deployable
|
- if deployment.deployable
|
||||||
= link_to [@project.namespace.becomes(Namespace), @project, deployment.deployable] do
|
= link_to [@project.namespace.becomes(Namespace), @project, deployment.deployable] do
|
||||||
|
= user_avatar(user: deployment.user, size: 20)
|
||||||
= "#{deployment.deployable.name} (##{deployment.deployable.id})"
|
= "#{deployment.deployable.name} (##{deployment.deployable.id})"
|
||||||
|
|
||||||
%td
|
%td
|
||||||
|
|
|
@ -2,8 +2,12 @@
|
||||||
|
|
||||||
%tr.environment
|
%tr.environment
|
||||||
%td
|
%td
|
||||||
%strong
|
= link_to environment.name, namespace_project_environment_path(@project.namespace, @project, environment)
|
||||||
= link_to environment.name, namespace_project_environment_path(@project.namespace, @project, environment)
|
|
||||||
|
%td
|
||||||
|
- if last_deployment
|
||||||
|
= user_avatar(user: last_deployment.user, size: 20)
|
||||||
|
%strong ##{last_deployment.id}
|
||||||
|
|
||||||
%td
|
%td
|
||||||
- if last_deployment
|
- if last_deployment
|
||||||
|
|
|
@ -23,10 +23,11 @@
|
||||||
New environment
|
New environment
|
||||||
- else
|
- else
|
||||||
.table-holder
|
.table-holder
|
||||||
%table.table.environments
|
%table.table.builds.environments
|
||||||
%tbody
|
%tbody
|
||||||
%th Environment
|
%th Environment
|
||||||
%th Last deployment
|
%th Last Deployment
|
||||||
%th Date
|
%th Commit
|
||||||
|
%th
|
||||||
%th
|
%th
|
||||||
= render @environments
|
= render @environments
|
||||||
|
|
|
@ -23,13 +23,13 @@
|
||||||
= link_to "Read more", help_page_path("ci/environments"), class: "btn btn-success"
|
= link_to "Read more", help_page_path("ci/environments"), class: "btn btn-success"
|
||||||
- else
|
- else
|
||||||
.table-holder
|
.table-holder
|
||||||
%table.table.environments
|
%table.table.builds.environments
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%th ID
|
%th ID
|
||||||
%th Commit
|
%th Commit
|
||||||
%th Build
|
%th Build
|
||||||
%th Date
|
%th
|
||||||
%th
|
%th
|
||||||
|
|
||||||
= render @deployments
|
= render @deployments
|
||||||
|
|
|
@ -29,56 +29,56 @@
|
||||||
= f.label :push_events, class: 'list-label' do
|
= f.label :push_events, class: 'list-label' do
|
||||||
%strong Push events
|
%strong Push events
|
||||||
%p.light
|
%p.light
|
||||||
This url will be triggered by a push to the repository
|
This URL will be triggered by a push to the repository
|
||||||
%li
|
%li
|
||||||
= f.check_box :tag_push_events, class: 'pull-left'
|
= f.check_box :tag_push_events, class: 'pull-left'
|
||||||
.prepend-left-20
|
.prepend-left-20
|
||||||
= f.label :tag_push_events, class: 'list-label' do
|
= f.label :tag_push_events, class: 'list-label' do
|
||||||
%strong Tag push events
|
%strong Tag push events
|
||||||
%p.light
|
%p.light
|
||||||
This url will be triggered when a new tag is pushed to the repository
|
This URL will be triggered when a new tag is pushed to the repository
|
||||||
%li
|
%li
|
||||||
= f.check_box :note_events, class: 'pull-left'
|
= f.check_box :note_events, class: 'pull-left'
|
||||||
.prepend-left-20
|
.prepend-left-20
|
||||||
= f.label :note_events, class: 'list-label' do
|
= f.label :note_events, class: 'list-label' do
|
||||||
%strong Comments
|
%strong Comments
|
||||||
%p.light
|
%p.light
|
||||||
This url will be triggered when someone adds a comment
|
This URL will be triggered when someone adds a comment
|
||||||
%li
|
%li
|
||||||
= f.check_box :issues_events, class: 'pull-left'
|
= f.check_box :issues_events, class: 'pull-left'
|
||||||
.prepend-left-20
|
.prepend-left-20
|
||||||
= f.label :issues_events, class: 'list-label' do
|
= f.label :issues_events, class: 'list-label' do
|
||||||
%strong Issues events
|
%strong Issues events
|
||||||
%p.light
|
%p.light
|
||||||
This url will be triggered when an issue is created/updated/merged
|
This URL will be triggered when an issue is created/updated/merged
|
||||||
%li
|
%li
|
||||||
= f.check_box :merge_requests_events, class: 'pull-left'
|
= f.check_box :merge_requests_events, class: 'pull-left'
|
||||||
.prepend-left-20
|
.prepend-left-20
|
||||||
= f.label :merge_requests_events, class: 'list-label' do
|
= f.label :merge_requests_events, class: 'list-label' do
|
||||||
%strong Merge Request events
|
%strong Merge Request events
|
||||||
%p.light
|
%p.light
|
||||||
This url will be triggered when a merge request is created/updated/merged
|
This URL will be triggered when a merge request is created/updated/merged
|
||||||
%li
|
%li
|
||||||
= f.check_box :build_events, class: 'pull-left'
|
= f.check_box :build_events, class: 'pull-left'
|
||||||
.prepend-left-20
|
.prepend-left-20
|
||||||
= f.label :build_events, class: 'list-label' do
|
= f.label :build_events, class: 'list-label' do
|
||||||
%strong Build events
|
%strong Build events
|
||||||
%p.light
|
%p.light
|
||||||
This url will be triggered when the build status changes
|
This URL will be triggered when the build status changes
|
||||||
%li
|
%li
|
||||||
= f.check_box :pipeline_events, class: 'pull-left'
|
= f.check_box :pipeline_events, class: 'pull-left'
|
||||||
.prepend-left-20
|
.prepend-left-20
|
||||||
= f.label :pipeline_events, class: 'list-label' do
|
= f.label :pipeline_events, class: 'list-label' do
|
||||||
%strong Pipeline events
|
%strong Pipeline events
|
||||||
%p.light
|
%p.light
|
||||||
This url will be triggered when the pipeline status changes
|
This URL will be triggered when the pipeline status changes
|
||||||
%li
|
%li
|
||||||
= f.check_box :wiki_page_events, class: 'pull-left'
|
= f.check_box :wiki_page_events, class: 'pull-left'
|
||||||
.prepend-left-20
|
.prepend-left-20
|
||||||
= f.label :wiki_page_events, class: 'list-label' do
|
= f.label :wiki_page_events, class: 'list-label' do
|
||||||
%strong Wiki Page events
|
%strong Wiki Page events
|
||||||
%p.light
|
%p.light
|
||||||
This url will be triggered when a wiki page is created/updated
|
This URL will be triggered when a wiki page is created/updated
|
||||||
.form-group
|
.form-group
|
||||||
= f.label :enable_ssl_verification, "SSL verification", class: 'label-light checkbox'
|
= f.label :enable_ssl_verification, "SSL verification", class: 'label-light checkbox'
|
||||||
.checkbox
|
.checkbox
|
||||||
|
|
17
app/workers/group_destroy_worker.rb
Normal file
17
app/workers/group_destroy_worker.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
class GroupDestroyWorker
|
||||||
|
include Sidekiq::Worker
|
||||||
|
|
||||||
|
sidekiq_options queue: :default
|
||||||
|
|
||||||
|
def perform(group_id, user_id)
|
||||||
|
begin
|
||||||
|
group = Group.with_deleted.find(group_id)
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
user = User.find(user_id)
|
||||||
|
|
||||||
|
DestroyGroupService.new(group, user).execute
|
||||||
|
end
|
||||||
|
end
|
|
@ -148,6 +148,9 @@ if Gitlab::Metrics.enabled?
|
||||||
|
|
||||||
config.instrument_methods(Gitlab::Highlight)
|
config.instrument_methods(Gitlab::Highlight)
|
||||||
config.instrument_instance_methods(Gitlab::Highlight)
|
config.instrument_instance_methods(Gitlab::Highlight)
|
||||||
|
|
||||||
|
# This is a Rails scope so we have to instrument it manually.
|
||||||
|
config.instrument_method(Project, :visible_to_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
GC::Profiler.enable
|
GC::Profiler.enable
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
# rubocop:disable all
|
# rubocop:disable all
|
||||||
class FixNamespaces < ActiveRecord::Migration
|
class FixNamespaces < ActiveRecord::Migration
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
def up
|
def up
|
||||||
Namespace.where('name <> path and type is null').each do |namespace|
|
namespaces = exec_query('SELECT id, path FROM namespaces WHERE name <> path and type is null')
|
||||||
namespace.update_attribute(:name, namespace.path)
|
|
||||||
|
namespaces.each do |row|
|
||||||
|
id = row['id']
|
||||||
|
path = row['path']
|
||||||
|
exec_query("UPDATE namespaces SET name = '#{path}' WHERE id = #{id}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
12
db/migrate/20160805041956_add_deleted_at_to_namespaces.rb
Normal file
12
db/migrate/20160805041956_add_deleted_at_to_namespaces.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
class AddDeletedAtToNamespaces < ActiveRecord::Migration
|
||||||
|
include Gitlab::Database::MigrationHelpers
|
||||||
|
|
||||||
|
DOWNTIME = false
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def change
|
||||||
|
add_column :namespaces, :deleted_at, :datetime
|
||||||
|
add_concurrent_index :namespaces, :deleted_at
|
||||||
|
end
|
||||||
|
end
|
|
@ -640,9 +640,11 @@ ActiveRecord::Schema.define(version: 20160810142633) do
|
||||||
t.boolean "share_with_group_lock", default: false
|
t.boolean "share_with_group_lock", default: false
|
||||||
t.integer "visibility_level", default: 20, null: false
|
t.integer "visibility_level", default: 20, null: false
|
||||||
t.boolean "request_access_enabled", default: true, null: false
|
t.boolean "request_access_enabled", default: true, null: false
|
||||||
|
t.datetime "deleted_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
|
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
|
||||||
|
add_index "namespaces", ["deleted_at"], name: "index_namespaces_on_deleted_at", using: :btree
|
||||||
add_index "namespaces", ["name"], name: "index_namespaces_on_name", unique: true, using: :btree
|
add_index "namespaces", ["name"], name: "index_namespaces_on_name", unique: true, using: :btree
|
||||||
add_index "namespaces", ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
|
add_index "namespaces", ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
|
||||||
add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
|
add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
|
||||||
|
|
|
@ -15,8 +15,8 @@ The process of solving performance problems is roughly as follows:
|
||||||
3. Add your findings based on the measurement period (screenshots of graphs,
|
3. Add your findings based on the measurement period (screenshots of graphs,
|
||||||
timings, etc) to the issue mentioned in step 1.
|
timings, etc) to the issue mentioned in step 1.
|
||||||
4. Solve the problem.
|
4. Solve the problem.
|
||||||
5. Create a merge request, assign the "performance" label and ping the right
|
5. Create a merge request, assign the "Performance" label and assign it to
|
||||||
people (e.g. [@yorickpeterse][yorickpeterse] and [@joshfng][joshfng]).
|
[@yorickpeterse][yorickpeterse] for reviewing.
|
||||||
6. Once a change has been deployed make sure to _again_ measure for at least 24
|
6. Once a change has been deployed make sure to _again_ measure for at least 24
|
||||||
hours to see if your changes have any impact on the production environment.
|
hours to see if your changes have any impact on the production environment.
|
||||||
7. Repeat until you're done.
|
7. Repeat until you're done.
|
||||||
|
@ -36,8 +36,8 @@ graphs/dashboards.
|
||||||
|
|
||||||
GitLab provides two built-in tools to aid the process of improving performance:
|
GitLab provides two built-in tools to aid the process of improving performance:
|
||||||
|
|
||||||
* [Sherlock](doc/development/profiling.md#sherlock)
|
* [Sherlock](profiling.md#sherlock)
|
||||||
* [GitLab Performance Monitoring](doc/monitoring/performance/monitoring.md)
|
* [GitLab Performance Monitoring](../monitoring/performance/monitoring.md)
|
||||||
|
|
||||||
GitLab employees can use GitLab.com's performance monitoring systems located at
|
GitLab employees can use GitLab.com's performance monitoring systems located at
|
||||||
<http://performance.gitlab.net>, this requires you to log in using your
|
<http://performance.gitlab.net>, this requires you to log in using your
|
||||||
|
@ -254,5 +254,4 @@ referencing an object directly may even slow code down.
|
||||||
|
|
||||||
[#15607]: https://gitlab.com/gitlab-org/gitlab-ce/issues/15607
|
[#15607]: https://gitlab.com/gitlab-org/gitlab-ce/issues/15607
|
||||||
[yorickpeterse]: https://gitlab.com/u/yorickpeterse
|
[yorickpeterse]: https://gitlab.com/u/yorickpeterse
|
||||||
[joshfng]: https://gitlab.com/u/joshfng
|
|
||||||
[anti-pattern]: https://en.wikipedia.org/wiki/Anti-pattern
|
[anti-pattern]: https://en.wikipedia.org/wiki/Anti-pattern
|
||||||
|
|
|
@ -754,6 +754,174 @@ X-Gitlab-Event: Wiki Page Hook
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Pipeline events
|
||||||
|
|
||||||
|
Triggered on status change of Pipeline.
|
||||||
|
|
||||||
|
**Request Header**:
|
||||||
|
|
||||||
|
```
|
||||||
|
X-Gitlab-Event: Pipeline Hook
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request Body**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"object_kind": "pipeline",
|
||||||
|
"object_attributes":{
|
||||||
|
"id": 31,
|
||||||
|
"ref": "master",
|
||||||
|
"tag": false,
|
||||||
|
"sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2",
|
||||||
|
"before_sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2",
|
||||||
|
"status": "success",
|
||||||
|
"stages":[
|
||||||
|
"build",
|
||||||
|
"test",
|
||||||
|
"deploy"
|
||||||
|
],
|
||||||
|
"created_at": "2016-08-12 15:23:28 UTC",
|
||||||
|
"finished_at": "2016-08-12 15:26:29 UTC",
|
||||||
|
"duration": 63
|
||||||
|
},
|
||||||
|
"user":{
|
||||||
|
"name": "Administrator",
|
||||||
|
"username": "root",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||||
|
},
|
||||||
|
"project":{
|
||||||
|
"name": "Gitlab Test",
|
||||||
|
"description": "Atque in sunt eos similique dolores voluptatem.",
|
||||||
|
"web_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test",
|
||||||
|
"avatar_url": null,
|
||||||
|
"git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git",
|
||||||
|
"git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git",
|
||||||
|
"namespace": "Gitlab Org",
|
||||||
|
"visibility_level": 20,
|
||||||
|
"path_with_namespace": "gitlab-org/gitlab-test",
|
||||||
|
"default_branch": "master"
|
||||||
|
},
|
||||||
|
"commit":{
|
||||||
|
"id": "bcbb5ec396a2c0f828686f14fac9b80b780504f2",
|
||||||
|
"message": "test\n",
|
||||||
|
"timestamp": "2016-08-12T17:23:21+02:00",
|
||||||
|
"url": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2",
|
||||||
|
"author":{
|
||||||
|
"name": "User",
|
||||||
|
"email": "user@gitlab.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"builds":[
|
||||||
|
{
|
||||||
|
"id": 380,
|
||||||
|
"stage": "deploy",
|
||||||
|
"name": "production",
|
||||||
|
"status": "skipped",
|
||||||
|
"created_at": "2016-08-12 15:23:28 UTC",
|
||||||
|
"started_at": null,
|
||||||
|
"finished_at": null,
|
||||||
|
"when": "manual",
|
||||||
|
"manual": true,
|
||||||
|
"user":{
|
||||||
|
"name": "Administrator",
|
||||||
|
"username": "root",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||||
|
},
|
||||||
|
"runner": null,
|
||||||
|
"artifacts_file":{
|
||||||
|
"filename": null,
|
||||||
|
"size": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 377,
|
||||||
|
"stage": "test",
|
||||||
|
"name": "test-image",
|
||||||
|
"status": "success",
|
||||||
|
"created_at": "2016-08-12 15:23:28 UTC",
|
||||||
|
"started_at": "2016-08-12 15:26:12 UTC",
|
||||||
|
"finished_at": null,
|
||||||
|
"when": "on_success",
|
||||||
|
"manual": false,
|
||||||
|
"user":{
|
||||||
|
"name": "Administrator",
|
||||||
|
"username": "root",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||||
|
},
|
||||||
|
"runner": null,
|
||||||
|
"artifacts_file":{
|
||||||
|
"filename": null,
|
||||||
|
"size": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 378,
|
||||||
|
"stage": "test",
|
||||||
|
"name": "test-build",
|
||||||
|
"status": "success",
|
||||||
|
"created_at": "2016-08-12 15:23:28 UTC",
|
||||||
|
"started_at": "2016-08-12 15:26:12 UTC",
|
||||||
|
"finished_at": "2016-08-12 15:26:29 UTC",
|
||||||
|
"when": "on_success",
|
||||||
|
"manual": false,
|
||||||
|
"user":{
|
||||||
|
"name": "Administrator",
|
||||||
|
"username": "root",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||||
|
},
|
||||||
|
"runner": null,
|
||||||
|
"artifacts_file":{
|
||||||
|
"filename": null,
|
||||||
|
"size": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 376,
|
||||||
|
"stage": "build",
|
||||||
|
"name": "build-image",
|
||||||
|
"status": "success",
|
||||||
|
"created_at": "2016-08-12 15:23:28 UTC",
|
||||||
|
"started_at": "2016-08-12 15:24:56 UTC",
|
||||||
|
"finished_at": "2016-08-12 15:25:26 UTC",
|
||||||
|
"when": "on_success",
|
||||||
|
"manual": false,
|
||||||
|
"user":{
|
||||||
|
"name": "Administrator",
|
||||||
|
"username": "root",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||||
|
},
|
||||||
|
"runner": null,
|
||||||
|
"artifacts_file":{
|
||||||
|
"filename": null,
|
||||||
|
"size": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 379,
|
||||||
|
"stage": "deploy",
|
||||||
|
"name": "staging",
|
||||||
|
"status": "created",
|
||||||
|
"created_at": "2016-08-12 15:23:28 UTC",
|
||||||
|
"started_at": null,
|
||||||
|
"finished_at": null,
|
||||||
|
"when": "on_success",
|
||||||
|
"manual": false,
|
||||||
|
"user":{
|
||||||
|
"name": "Administrator",
|
||||||
|
"username": "root",
|
||||||
|
"avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon"
|
||||||
|
},
|
||||||
|
"runner": null,
|
||||||
|
"artifacts_file":{
|
||||||
|
"filename": null,
|
||||||
|
"size": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### Example webhook receiver
|
#### Example webhook receiver
|
||||||
|
|
||||||
If you want to see GitLab's webhooks in action for testing purposes you can use
|
If you want to see GitLab's webhooks in action for testing purposes you can use
|
||||||
|
|
24
spec/controllers/admin/groups_controller_spec.rb
Normal file
24
spec/controllers/admin/groups_controller_spec.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Admin::GroupsController do
|
||||||
|
let(:group) { create(:group) }
|
||||||
|
let(:project) { create(:project, namespace: group) }
|
||||||
|
let(:admin) { create(:admin) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
sign_in(admin)
|
||||||
|
Sidekiq::Testing.fake!
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE #destroy' do
|
||||||
|
it 'schedules a group destroy' do
|
||||||
|
expect { delete :destroy, id: project.group.path }.to change(GroupDestroyWorker.jobs, :size).by(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to the admin group path' do
|
||||||
|
delete :destroy, id: project.group.path
|
||||||
|
|
||||||
|
expect(response).to redirect_to(admin_groups_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -75,4 +75,33 @@ describe GroupsController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'DELETE #destroy' do
|
||||||
|
context 'as another user' do
|
||||||
|
it 'returns 404' do
|
||||||
|
sign_in(create(:user))
|
||||||
|
|
||||||
|
delete :destroy, id: group.path
|
||||||
|
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as the group owner' do
|
||||||
|
before do
|
||||||
|
Sidekiq::Testing.fake!
|
||||||
|
sign_in(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'schedules a group destroy' do
|
||||||
|
expect { delete :destroy, id: group.path }.to change(GroupDestroyWorker.jobs, :size).by(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to the root path' do
|
||||||
|
delete :destroy, id: group.path
|
||||||
|
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,15 +7,13 @@ FactoryGirl.define do
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :all_events_enabled do
|
trait :all_events_enabled do
|
||||||
%w[push_events
|
push_events true
|
||||||
merge_requests_events
|
merge_requests_events true
|
||||||
tag_push_events
|
tag_push_events true
|
||||||
issues_events
|
issues_events true
|
||||||
note_events
|
note_events true
|
||||||
build_events
|
build_events true
|
||||||
pipeline_events].each do |event|
|
pipeline_events true
|
||||||
send(event, true)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -887,8 +887,10 @@ describe Ci::Build, models: true do
|
||||||
is_expected.to eq(build)
|
is_expected.to eq(build)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'for success build' do
|
context 'for successful build' do
|
||||||
before { build.queue }
|
before do
|
||||||
|
build.update(status: 'success')
|
||||||
|
end
|
||||||
|
|
||||||
it 'creates a new build' do
|
it 'creates a new build' do
|
||||||
is_expected.to be_pending
|
is_expected.to be_pending
|
||||||
|
|
|
@ -145,7 +145,7 @@ describe Ci::Pipeline, models: true do
|
||||||
expect(pipeline.reload.started_at).not_to be_nil
|
expect(pipeline.reload.started_at).not_to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'do not update on transitioning to success' do
|
it 'does not update on transitioning to success' do
|
||||||
build.success
|
build.success
|
||||||
|
|
||||||
expect(pipeline.reload.started_at).to be_nil
|
expect(pipeline.reload.started_at).to be_nil
|
||||||
|
@ -159,7 +159,7 @@ describe Ci::Pipeline, models: true do
|
||||||
expect(pipeline.reload.finished_at).not_to be_nil
|
expect(pipeline.reload.finished_at).not_to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'do not update on transitioning to running' do
|
it 'does not update on transitioning to running' do
|
||||||
build.run
|
build.run
|
||||||
|
|
||||||
expect(pipeline.reload.finished_at).to be_nil
|
expect(pipeline.reload.finished_at).to be_nil
|
||||||
|
@ -259,14 +259,16 @@ describe Ci::Pipeline, models: true do
|
||||||
subject { pipeline.reload.status }
|
subject { pipeline.reload.status }
|
||||||
|
|
||||||
context 'on queuing' do
|
context 'on queuing' do
|
||||||
before { build.queue }
|
before do
|
||||||
|
build.enqueue
|
||||||
|
end
|
||||||
|
|
||||||
it { is_expected.to eq('pending') }
|
it { is_expected.to eq('pending') }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'on run' do
|
context 'on run' do
|
||||||
before do
|
before do
|
||||||
build.queue
|
build.enqueue
|
||||||
build.run
|
build.run
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -296,6 +298,19 @@ describe Ci::Pipeline, models: true do
|
||||||
|
|
||||||
it { is_expected.to eq('canceled') }
|
it { is_expected.to eq('canceled') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'on failure and build retry' do
|
||||||
|
before do
|
||||||
|
build.drop
|
||||||
|
Ci::Build.retry(build)
|
||||||
|
end
|
||||||
|
|
||||||
|
# We are changing a state: created > failed > running
|
||||||
|
# Instead of: created > failed > pending
|
||||||
|
# Since the pipeline already run, so it should not be pending anymore
|
||||||
|
|
||||||
|
it { is_expected.to eq('running') }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#execute_hooks' do
|
describe '#execute_hooks' do
|
||||||
|
@ -320,8 +335,8 @@ describe Ci::Pipeline, models: true do
|
||||||
context 'with multiple builds' do
|
context 'with multiple builds' do
|
||||||
context 'when build is queued' do
|
context 'when build is queued' do
|
||||||
before do
|
before do
|
||||||
build_a.queue
|
build_a.enqueue
|
||||||
build_b.queue
|
build_b.enqueue
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'receive a pending event once' do
|
it 'receive a pending event once' do
|
||||||
|
@ -331,9 +346,9 @@ describe Ci::Pipeline, models: true do
|
||||||
|
|
||||||
context 'when build is run' do
|
context 'when build is run' do
|
||||||
before do
|
before do
|
||||||
build_a.queue
|
build_a.enqueue
|
||||||
build_a.run
|
build_a.run
|
||||||
build_b.queue
|
build_b.enqueue
|
||||||
build_b.run
|
build_b.run
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -367,8 +382,8 @@ describe Ci::Pipeline, models: true do
|
||||||
let(:enabled) { false }
|
let(:enabled) { false }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
build_a.queue
|
build_a.enqueue
|
||||||
build_b.queue
|
build_b.enqueue
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'did not execute pipeline_hook after touched' do
|
it 'did not execute pipeline_hook after touched' do
|
||||||
|
|
|
@ -564,12 +564,14 @@ describe API::API, api: true do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "DELETE /users/:id" do
|
describe "DELETE /users/:id" do
|
||||||
|
let!(:namespace) { user.namespace }
|
||||||
before { admin }
|
before { admin }
|
||||||
|
|
||||||
it "deletes user" do
|
it "deletes user" do
|
||||||
delete api("/users/#{user.id}", admin)
|
delete api("/users/#{user.id}", admin)
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound
|
expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound
|
||||||
|
expect { Namespace.find(namespace.id) }.to raise_error ActiveRecord::RecordNotFound
|
||||||
expect(json_response['email']).to eq(user.email)
|
expect(json_response['email']).to eq(user.email)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,11 @@ describe DeleteUserService, services: true do
|
||||||
|
|
||||||
context 'no options are given' do
|
context 'no options are given' do
|
||||||
it 'deletes the user' do
|
it 'deletes the user' do
|
||||||
DeleteUserService.new(current_user).execute(user)
|
user_data = DeleteUserService.new(current_user).execute(user)
|
||||||
|
|
||||||
expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
|
expect { user_data['email'].to eq(user.email) }
|
||||||
|
expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
expect { Namespace.with_deleted.find(user.namespace.id) }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'will delete the project in the near future' do
|
it 'will delete the project in the near future' do
|
||||||
|
|
|
@ -7,38 +7,52 @@ describe DestroyGroupService, services: true do
|
||||||
let!(:gitlab_shell) { Gitlab::Shell.new }
|
let!(:gitlab_shell) { Gitlab::Shell.new }
|
||||||
let!(:remove_path) { group.path + "+#{group.id}+deleted" }
|
let!(:remove_path) { group.path + "+#{group.id}+deleted" }
|
||||||
|
|
||||||
context 'database records' do
|
shared_examples 'group destruction' do |async|
|
||||||
before do
|
context 'database records' do
|
||||||
destroy_group(group, user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(Group.all).not_to include(group) }
|
|
||||||
it { expect(Project.all).not_to include(project) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'file system' do
|
|
||||||
context 'Sidekiq inline' do
|
|
||||||
before do
|
before do
|
||||||
# Run sidekiq immediatly to check that renamed dir will be removed
|
destroy_group(group, user, async)
|
||||||
Sidekiq::Testing.inline! { destroy_group(group, user) }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey }
|
it { expect(Group.all).not_to include(group) }
|
||||||
it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey }
|
it { expect(Project.all).not_to include(project) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'Sidekiq fake' do
|
context 'file system' do
|
||||||
before do
|
context 'Sidekiq inline' do
|
||||||
# Dont run sidekiq to check if renamed repository exists
|
before do
|
||||||
Sidekiq::Testing.fake! { destroy_group(group, user) }
|
# Run sidekiq immediatly to check that renamed dir will be removed
|
||||||
|
Sidekiq::Testing.inline! { destroy_group(group, user, async) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey }
|
||||||
|
it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey }
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey }
|
context 'Sidekiq fake' do
|
||||||
it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_truthy }
|
before do
|
||||||
|
# Dont run sidekiq to check if renamed repository exists
|
||||||
|
Sidekiq::Testing.fake! { destroy_group(group, user, async) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey }
|
||||||
|
it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_truthy }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy_group(group, user, async)
|
||||||
|
if async
|
||||||
|
DestroyGroupService.new(group, user).async_execute
|
||||||
|
else
|
||||||
|
DestroyGroupService.new(group, user).execute
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy_group(group, user)
|
describe 'asynchronous delete' do
|
||||||
DestroyGroupService.new(group, user).execute
|
it_behaves_like 'group destruction', true
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'synchronous delete' do
|
||||||
|
it_behaves_like 'group destruction', false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
19
spec/workers/group_destroy_worker_spec.rb
Normal file
19
spec/workers/group_destroy_worker_spec.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe GroupDestroyWorker do
|
||||||
|
let(:group) { create(:group) }
|
||||||
|
let(:user) { create(:admin) }
|
||||||
|
let!(:project) { create(:project, namespace: group) }
|
||||||
|
|
||||||
|
subject { GroupDestroyWorker.new }
|
||||||
|
|
||||||
|
describe "#perform" do
|
||||||
|
it "deletes the project" do
|
||||||
|
subject.perform(group.id, user.id)
|
||||||
|
|
||||||
|
expect(Group.all).not_to include(group)
|
||||||
|
expect(Project.all).not_to include(project)
|
||||||
|
expect(Dir.exist?(project.path)).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue