Skip to content
Snippets Groups Projects
Commit 177d847c authored by Mayra Cabrera's avatar Mayra Cabrera Committed by Kamil Trzciński
Browse files

Automatically disable Auto DevOps for project upon first pipeline failure

parent a286e20d
No related branches found
No related tags found
1 merge request!10495Merge Requests - Assignee
Showing
with 298 additions and 34 deletions
# frozen_string_literal: true
module Emails
module AutoDevops
def autodevops_disabled_email(pipeline, recipient)
@pipeline = pipeline
@project = pipeline.project
add_project_headers
mail(to: recipient,
subject: auto_devops_disabled_subject(@project.name)) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
end
private
def auto_devops_disabled_subject(project_name)
subject("Auto DevOps pipeline was disabled for #{project_name}")
end
end
end
Loading
Loading
@@ -12,6 +12,7 @@ class Notify < BaseMailer
include Emails::Profile
include Emails::Pipelines
include Emails::Members
include Emails::AutoDevops
 
helper MergeRequestsHelper
helper DiffHelper
Loading
Loading
Loading
Loading
@@ -125,6 +125,10 @@ class NotifyPreview < ActionMailer::Preview
Notify.pipeline_failed_email(pipeline, pipeline.user.try(:email))
end
 
def autodevops_disabled_email
Notify.autodevops_disabled_email(pipeline, user.email).message
end
private
 
def project
Loading
Loading
Loading
Loading
@@ -161,6 +161,12 @@ module Ci
PipelineNotificationWorker.perform_async(pipeline.id)
end
end
after_transition any => [:failed] do |pipeline|
next unless pipeline.auto_devops_source?
pipeline.run_after_commit { AutoDevops::DisableWorker.perform_async(pipeline.id) }
end
end
 
scope :internal, -> { where(source: internal_sources) }
Loading
Loading
Loading
Loading
@@ -407,6 +407,12 @@ class NotificationService
end
end
 
def autodevops_disabled(pipeline, recipients)
recipients.each do |recipient|
mailer.autodevops_disabled_email(pipeline, recipient).deliver_later
end
end
def pages_domain_verification_succeeded(domain)
recipients_for_pages_domain(domain).each do |user|
mailer.pages_domain_verification_succeeded_email(domain, user).deliver_later
Loading
Loading
# frozen_string_literal: true
module Projects
module AutoDevops
class DisableService < BaseService
def execute
return false unless implicitly_enabled_and_first_pipeline_failure?
disable_auto_devops
end
private
def implicitly_enabled_and_first_pipeline_failure?
project.has_auto_devops_implicitly_enabled? &&
first_pipeline_failure?
end
# We're using `limit` to optimize `auto_devops pipeline` query,
# since we only care about the first element, and using only `.count`
# is an expensive operation. See
# https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21172#note_99037378
# for more context.
def first_pipeline_failure?
auto_devops_pipelines.success.limit(1).count.zero? &&
auto_devops_pipelines.failed.limit(1).count.nonzero?
end
def disable_auto_devops
project.auto_devops_attributes = { enabled: false }
project.save!
end
def auto_devops_pipelines
@auto_devops_pipelines ||= project.pipelines.auto_devops_source
end
end
end
end
%tr
%td{ colspan: 2, style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #333333; font-size: 14px; font-weight: 400; line-height: 1.4; padding: 0 8px 16px; text-align: center;" }
had
= failed.size
failed
#{'build'.pluralize(failed.size)}.
%tr.table-warning
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; border: 1px solid #ededed; border-bottom: 0; border-radius: 4px 4px 0 0; overflow: hidden; background-color: #fdf4f6; color: #d22852; font-size: 14px; line-height: 1.4; text-align: center; padding: 8px 16px;" }
Logs may contain sensitive data. Please consider before forwarding this email.
%tr.section
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; padding: 0 16px; border: 1px solid #ededed; border-radius: 4px; overflow: hidden; border-top: 0; border-radius: 0 0 4px 4px;" }
%table.builds{ border: "0", cellpadding: "0", cellspacing: "0", style: "width: 100%; border-collapse: collapse;" }
%tbody
- failed.each do |build|
%tr.build-state
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; padding: 16px 0; color: #8c8c8c; font-weight: 500; font-size: 14px;" }
%table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse: collapse;" }
%tbody
%tr
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #d22f57; font-weight: 500; font-size: 16px; vertical-align: middle; padding-right: 8px; line-height: 10px" }
%img{ alt: "✖", height: "10", src: image_url('mailers/ci_pipeline_notif_v1/icon-x-red.gif'), style: "display: block;", width: "10" }/
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #8c8c8c; font-weight: 500; font-size: 14px; vertical-align: middle;" }
= build.stage
%td{ align: "right", style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; padding: 16px 0; color: #8c8c8c; font-weight: 500; font-size: 14px;" }
= render "notify/links/#{build.to_partial_path}", pipeline: pipeline, build: build
%tr.build-log
- if build.has_trace?
%td{ colspan: "2", style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; padding: 0 0 16px;" }
%pre{ style: "font-family: Monaco,'Lucida Console','Courier New',Courier,monospace; background-color: #fafafa; border-radius: 4px; overflow: hidden; white-space: pre-wrap; word-break: break-all; font-size:13px; line-height: 1.4; padding: 16px 8px; color: #333333; margin: 0;" }
= build.trace.html(last_lines: 10).html_safe
- else
%td{ colspan: "2" }
%tr.alert
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; padding: 8px 16px; border-radius: 4px; font-size: 14px; line-height: 1.3; text-align: center; overflow: hidden; background-color: #d22f57; color: #ffffff;" }
%table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse: collapse; margin: 0 auto;" }
%tbody
%tr
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; vertical-align: middle; color: #ffffff; text-align: center;" }
Auto DevOps pipeline was disabled for #{@project.name}
%tr.pre-section
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; color: #333333; font-size: 14px; font-weight: 400; line-height: 1.7; padding: 16px 8px 0;" }
The Auto DevOps pipeline failed for pipeline
%a{ href: pipeline_url(@pipeline), style: "color: #1b69b6; text-decoration:none;" }
= "\##{@pipeline.iid}"
and has been disabled for
%a{ href: project_url(@project), style: "color: #1b69b6; text-decoration: none;" }
= @project.name + "."
In order to use the Auto DevOps pipeline with your project, please review the
%a{ href: 'https://docs.gitlab.com/ee/topics/autodevops/#currently-supported-languages', style: "color:#1b69b6;text-decoration:none;" } currently supported languages,
adjust your project accordingly, and turn on the Auto DevOps pipeline within your
%a{ href: project_settings_ci_cd_url(@project), style: "color: #1b69b6; text-decoration: none;" }
CI/CD project settings.
%tr.pre-section
%td{ style: 'text-align: center;border-bottom:1px solid #ededed' }
%a{ href: 'https://docs.gitlab.com/ee/topics/autodevops/', style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" }
%button{ type: 'button', style: 'border-color: #dfdfdf; border-style: solid; border-width: 1px; border-radius: 4px; font-size: 14px; padding: 8px 16px; background-color:#fff; margin: 8px 0; cursor: pointer;' }
Learn more about Auto DevOps
%tr.pre-section
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; color: #333333; font-size: 14px; font-weight: 400; line-height: 1.4; padding: 16px 8px; text-align: center;" }
%table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;margin:0 auto;" }
%tbody
%tr
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; font-size:14px; font-weight:500;line-height: 1.4; vertical-align: baseline;" }
Pipeline
%a{ href: pipeline_url(@pipeline), style: "color: #1b69b6; text-decoration: none;" }
= "\##{@pipeline.id}"
triggered by
- if @pipeline.user
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; font-size: 15px; line-height: 1.4; vertical-align: middle; padding-right: 8px; padding-left:8px", width: "24" }
%img.avatar{ height: "24", src: avatar_icon_for_user(@pipeline.user, 24, only_path: false), style: "display: block; border-radius: 12px; margin: -2px 0;", width: "24", alt: "" }/
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; font-size: 14px; font-weight: 500; line-height: 1.4; vertical-align: baseline;" }
%a.muted{ href: user_url(@pipeline.user), style: "color: #333333; text-decoration: none;" }
= @pipeline.user.name
- else
%td{ style: "font-family: 'Menlo','Liberation Mono','Consolas','DejaVu Sans Mono','Ubuntu Mono','Courier New','andale mono','lucida console',monospace; font-size: 14px; line-height: 1.4; vertical-align: baseline; padding:0 8px;" }
API
= render 'notify/failed_builds', pipeline: @pipeline, failed: @pipeline.statuses.latest.failed
Auto DevOps pipeline was disabled for <%= @project.name %>
The Auto DevOps pipeline failed for pipeline <%= @pipeline.iid %> (<%= pipeline_url(@pipeline) %>) and has been disabled for <%= @project.name %>. In order to use the Auto DevOps pipeline with your project, please review the currently supported languagues (https://docs.gitlab.com/ee/topics/autodevops/#currently-supported-languages), adjust your project accordingly, and turn on the Auto DevOps pipeline within your CI/CD project settings (<%= project_settings_ci_cd_url(@project) %>).
<% if @pipeline.user -%>
Pipeline #<%= @pipeline.id %> ( <%= pipeline_url(@pipeline) %> ) triggered by <%= @pipeline.user.name %> ( <%= user_url(@pipeline.user) %> )
<% else -%>
Pipeline #<%= @pipeline.id %> ( <%= pipeline_url(@pipeline) %> ) triggered by API
<% end -%>
<% failed = @pipeline.statuses.latest.failed -%>
had <%= failed.size %> failed <%= 'build'.pluralize(failed.size) %>.
<% failed.each do |build| -%>
<%= render "notify/links/#{build.to_partial_path}", pipeline: @pipeline, build: build %>
Stage: <%= build.stage %>
Name: <%= build.name %>
<% if build.has_trace? -%>
Trace: <%= build.trace.raw(last_lines: 10) %>
<% end -%>
<% end -%>
Loading
Loading
@@ -107,36 +107,5 @@
- else
%td{ style: "font-family:'Menlo','Liberation Mono','Consolas','DejaVu Sans Mono','Ubuntu Mono','Courier New','andale mono','lucida console',monospace;font-size:14px;line-height:1.4;vertical-align:baseline;padding:0 5px;" }
API
- failed = @pipeline.statuses.latest.failed
%tr
%td{ colspan: 2, style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#333333;font-size:15px;font-weight:300;line-height:1.4;padding:15px 5px;text-align:center;" }
had
= failed.size
failed
#{'build'.pluralize(failed.size)}.
%tr.table-warning
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;border:1px solid #ededed;border-bottom:0;border-radius:3px 3px 0 0;overflow:hidden;background-color:#fdf4f6;color:#d22852;font-size:14px;line-height:1.4;text-align:center;padding:8px 15px;" }
Logs may contain sensitive data. Please consider before forwarding this email.
%tr.section
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;border-top:0;border-radius:0 0 3px 3px;" }
%table.builds{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;border-collapse:collapse;" }
%tbody
- failed.each do |build|
%tr.build-state
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:20px 0;color:#8c8c8c;font-weight:500;font-size:15px;" }
%table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" }
%tbody
%tr
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#d22f57;font-weight:500;font-size:15px;vertical-align:middle;padding-right:5px;line-height:10px" }
%img{ alt: "✖", height: "10", src: image_url('mailers/ci_pipeline_notif_v1/icon-x-red.gif'), style: "display:block;", width: "10" }/
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#8c8c8c;font-weight:500;font-size:15px;vertical-align:middle;" }
= build.stage
%td{ align: "right", style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:20px 0;color:#8c8c8c;font-weight:500;font-size:15px;" }
= render "notify/links/#{build.to_partial_path}", pipeline: @pipeline, build: build
%tr.build-log
- if build.has_trace?
%td{ colspan: "2", style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 0 15px;" }
%pre{ style: "font-family:Monaco,'Lucida Console','Courier New',Courier,monospace;background-color:#fafafa;border-radius:3px;overflow:hidden;white-space:pre-wrap;word-break:break-all;font-size:13px;line-height:1.4;padding:12px;color:#333333;margin:0;" }
= build.trace.html(last_lines: 10).html_safe
- else
%td{ colspan: "2" }
= render 'notify/failed_builds', pipeline: @pipeline, failed: @pipeline.statuses.latest.failed
---
- auto_devops:auto_devops_disable
- cronjob:admin_email
- cronjob:expire_build_artifacts
- cronjob:gitlab_usage_ping
Loading
Loading
# frozen_string_literal: true
module AutoDevops
class DisableWorker
include ApplicationWorker
include AutoDevopsQueue
def perform(pipeline_id)
pipeline = Ci::Pipeline.find(pipeline_id)
project = pipeline.project
send_notification_email(pipeline, project) if disable_service(project).execute
end
private
def disable_service(project)
Projects::AutoDevops::DisableService.new(project)
end
def send_notification_email(pipeline, project)
recipients = email_receivers_for(pipeline, project)
return unless recipients.any?
NotificationService.new.autodevops_disabled(pipeline, recipients)
end
def email_receivers_for(pipeline, project)
recipients = [pipeline.user&.email]
recipients << project.owner.email unless project.group
recipients.uniq.compact
end
end
end
# frozen_string_literal: true
#
module AutoDevopsQueue
extend ActiveSupport::Concern
included do
queue_namespace :auto_devops
end
end
---
title: Disable Auto DevOps for project upon first pipeline failure
merge_request: 21172
author:
type: added
Loading
Loading
@@ -78,3 +78,4 @@
- [create_note_diff_file, 1]
- [delete_diff_files, 1]
- [detect_repository_languages, 1]
- [auto_devops, 2]
# frozen_string_literal: true
class AddProjectConfigSourceStatusIndexToPipeline < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_pipelines, [:project_id, :status, :config_source]
end
def down
remove_concurrent_index :ci_pipelines, [:project_id, :status, :config_source]
end
end
Loading
Loading
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
 
ActiveRecord::Schema.define(version: 20180826111825) do
ActiveRecord::Schema.define(version: 20180901171833) do
 
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Loading
Loading
@@ -476,6 +476,7 @@ ActiveRecord::Schema.define(version: 20180826111825) do
add_index "ci_pipelines", ["project_id", "iid"], name: "index_ci_pipelines_on_project_id_and_iid", unique: true, where: "(iid IS NOT NULL)", using: :btree
add_index "ci_pipelines", ["project_id", "ref", "status", "id"], name: "index_ci_pipelines_on_project_id_and_ref_and_status_and_id", using: :btree
add_index "ci_pipelines", ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree
add_index "ci_pipelines", ["project_id", "status", "config_source"], name: "index_ci_pipelines_on_project_id_and_status_and_config_source", using: :btree
add_index "ci_pipelines", ["project_id"], name: "index_ci_pipelines_on_project_id", using: :btree
add_index "ci_pipelines", ["status"], name: "index_ci_pipelines_on_status", using: :btree
add_index "ci_pipelines", ["user_id"], name: "index_ci_pipelines_on_user_id", using: :btree
Loading
Loading
Loading
Loading
@@ -77,6 +77,14 @@ FactoryBot.define do
pipeline.builds << build(:ci_build, :test_reports, pipeline: pipeline, project: pipeline.project)
end
end
trait :auto_devops_source do
config_source { Ci::Pipeline.config_sources[:auto_devops_source] }
end
trait :repository_source do
config_source { Ci::Pipeline.config_sources[:repository_source] }
end
end
end
end
Loading
Loading
@@ -260,6 +260,10 @@ FactoryBot.define do
trait(:repository_enabled) { repository_access_level ProjectFeature::ENABLED }
trait(:repository_disabled) { repository_access_level ProjectFeature::DISABLED }
trait(:repository_private) { repository_access_level ProjectFeature::PRIVATE }
trait :auto_devops do
association :auto_devops, factory: :project_auto_devops
end
end
 
# Project with empty repository
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe Emails::AutoDevops do
include EmailSpec::Matchers
describe '#auto_devops_disabled_email' do
let(:owner) { create(:user) }
let(:namespace) { create(:namespace, owner: owner) }
let(:project) { create(:project, :repository, :auto_devops) }
let(:pipeline) { create(:ci_pipeline, :failed, project: project) }
subject { Notify.autodevops_disabled_email(pipeline, owner.email) }
it 'sents email with correct subject' do
is_expected.to have_subject("#{project.name} | Auto DevOps pipeline was disabled for #{project.name}")
end
it 'sents an email to the user' do
recipient = subject.header[:to].addrs.map(&:address).first
expect(recipient).to eq(owner.email)
end
it 'is sent as GitLab email' do
sender = subject.header[:from].addrs[0].address
expect(sender).to match(/gitlab/)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment