diff --git a/app/jobs/deploy_job.rb b/app/jobs/deploy_job.rb index 27ee30ca..b241f25c 100644 --- a/app/jobs/deploy_job.rb +++ b/app/jobs/deploy_job.rb @@ -40,12 +40,16 @@ class DeployJob < ApplicationJob } # No es opcional - unless @deployed[:deploy_local] + unless @deployed[:deploy_local][:status] # Hacer fallar la tarea - raise DeployException, deploy_local.build_stats.last.log + raise DeployException, "#{@site.name}: Falló la compilación" end deploy_others + rescue DeployTimedOutException => e + notify_exception e + rescue DeployException => e + notify_exception e, deploy_local ensure @site&.update status: 'waiting' @@ -56,6 +60,18 @@ class DeployJob < ApplicationJob private + # @param :exception [StandardError] + # @param :deploy [Deploy] + def notify_exception(exception, deploy = nil) + data = { + site: @site.id, + deploy: deploy&.type, + log: deploy&.build_stats&.last&.log + } + + ExceptionNotifier.notify_exception(exception, data: data) + end + def deploy_local @deploy_local ||= @site.deploys.find_by(type: 'DeployLocal') end @@ -66,14 +82,21 @@ class DeployJob < ApplicationJob def deploy_others @site.deploys.where.not(type: 'DeployLocal').find_each do |d| - status = d.deploy(output: @output) - build_stat = d.build_stats.last + begin + status = d.deploy(output: @output) + seconds = d.build_stats.last.try(:seconds) + rescue StandardError => e + status = false + seconds = 0 + + notify_exception e, d + end @deployed[d.type.underscore.to_sym] = { status: status, - seconds: build_stat.try(:seconds) || 0, + seconds: seconds || 0, size: d.size, - urls: d.respond_to?(:urls) ? d.urls : [d.url] + urls: d.respond_to?(:urls) ? d.urls : [d.url].compact } end end diff --git a/app/jobs/gitlab_notifier_job.rb b/app/jobs/gitlab_notifier_job.rb index 7218f68a..701c6789 100644 --- a/app/jobs/gitlab_notifier_job.rb +++ b/app/jobs/gitlab_notifier_job.rb @@ -3,6 +3,8 @@ # Notifica excepciones a una instancia de Gitlab, como incidencias # nuevas o como comentarios a las incidencias pre-existentes. class GitlabNotifierJob < ApplicationJob + class GitlabNotifierError < StandardError; end + include ExceptionNotifier::BacktraceCleaner # Variables que vamos a acceder luego @@ -18,22 +20,28 @@ class GitlabNotifierJob < ApplicationJob @issue_data = { count: 1 } # Necesitamos saber si el issue ya existía @cached = false + @issue = {} # Traemos los datos desde la caché si existen, sino generamos un # issue nuevo e inicializamos la caché @issue_data = Rails.cache.fetch(cache_key) do - issue = client.new_issue confidential: true, title: title, description: description, issue_type: 'incident' + @issue = client.new_issue confidential: true, title: title, description: description, issue_type: 'incident' @cached = true { count: 1, - issue: issue['iid'], + issue: @issue['iid'], user_agents: [user_agent].compact, params: [request&.filtered_parameters].compact, urls: [url].compact } end + unless @issue['iid'] + Rails.cache.delete(cache_key) + raise GitlabNotifierError, @issue.dig('message', 'title')&.join(', ') + end + # No seguimos actualizando si acabamos de generar el issue return if cached @@ -104,6 +112,7 @@ class GitlabNotifierJob < ApplicationJob # @return [String] def description @description ||= ''.dup.tap do |d| + d << log_section d << request_section d << javascript_section d << javascript_footer @@ -151,6 +160,19 @@ class GitlabNotifierJob < ApplicationJob @client ||= GitlabApiClient.new end + # @return [String] + def log_section + return '' unless options[:log] + + <<~LOG + # Log + + ``` + #{options[:log]} + ``` + LOG + end + # Muestra información de la petición # # @return [String] diff --git a/app/mailers/deploy_mailer.rb b/app/mailers/deploy_mailer.rb index aeb13676..7d939940 100644 --- a/app/mailers/deploy_mailer.rb +++ b/app/mailers/deploy_mailer.rb @@ -18,46 +18,46 @@ class DeployMailer < ApplicationMailer subject = t('.subject', site: site.name) hostname = site.hostname - @hi = t('.hi') - @explanation = t('.explanation', fqdn: hostname) - @help = t('.help') - - @headers = %w[type status url seconds size].map do |header| - t(".th.#{header}") - end - - @table = deploys.each_pair.map do |deploy, value| - { - title: t(".#{deploy}.title"), - status: t(".#{deploy}.#{value[:status] ? 'success' : 'error'}"), - urls: value[:urls], - seconds: { - human: distance_of_time_in_words(value[:seconds].seconds), - machine: "PT#{value[:seconds]}S" - }, - size: number_to_human_size(value[:size], precision: 2) - } - end - - @terminal_table = Terminal::Table.new do |t| - t << @headers - t.add_separator - @table.each do |row| - row[:urls].each do |url| - t << (row.map do |k, v| - case k - when :seconds then v[:human] - when :urls then url - else v - end - end) - end - end - end - # Informamos a cada quien en su idioma y damos una dirección de # respuesta porque a veces les usuaries nos escriben I18n.with_locale(usuarie.lang) do + @hi = t('.hi') + @explanation = t('.explanation', fqdn: hostname) + @help = t('.help') + + @headers = %w[type status url seconds size].map do |header| + t(".th.#{header}") + end + + @table = deploys.each_pair.map do |deploy, value| + { + title: t(".#{deploy}.title"), + status: t(".#{deploy}.#{value[:status] ? 'success' : 'error'}"), + urls: value[:urls], + seconds: { + human: distance_of_time_in_words(value[:seconds].seconds), + machine: "PT#{value[:seconds]}S" + }, + size: number_to_human_size(value[:size], precision: 2) + } + end + + @terminal_table = Terminal::Table.new do |t| + t << @headers + t.add_separator + @table.each do |row| + row[:urls].each do |url| + t << (row.map do |k, v| + case k + when :seconds then v[:human] + when :urls then url + else v + end + end) + end + end + end + mail(to: usuarie.email, reply_to: "sutty@#{Site.domain}", subject: subject) end end