5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-16 14:51:41 +00:00

Merge branch 'informative-deploys' into 'rails'

enviar más información

See merge request sutty/sutty!86
This commit is contained in:
fauno 2023-03-23 22:07:11 +00:00
commit 0075113c23
14 changed files with 176 additions and 45 deletions

View file

@ -3,6 +3,7 @@
# Realiza el deploy de un sitio # Realiza el deploy de un sitio
class DeployJob < ApplicationJob class DeployJob < ApplicationJob
class DeployException < StandardError; end class DeployException < StandardError; end
class DeployTimedOutException < DeployException; end
# rubocop:disable Metrics/MethodLength # rubocop:disable Metrics/MethodLength
def perform(site, notify = true, time = Time.now) def perform(site, notify = true, time = Time.now)
@ -16,8 +17,8 @@ class DeployJob < ApplicationJob
# hora original para poder ir haciendo timeouts. # hora original para poder ir haciendo timeouts.
if @site.building? if @site.building?
if 10.minutes.ago >= time if 10.minutes.ago >= time
@site.update status: 'waiting' notify = false
raise DeployException, raise DeployTimedOutException,
"#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original" "#{@site.name} la tarea estuvo más de 10 minutos esperando, volviendo al estado original"
end end
@ -27,21 +28,28 @@ class DeployJob < ApplicationJob
@site.update status: 'building' @site.update status: 'building'
# Asegurarse que DeployLocal sea el primero! # Asegurarse que DeployLocal sea el primero!
@deployed = { deploy_local: deploy_locally } @deployed = {
deploy_local: {
status: deploy_locally,
seconds: deploy_local.build_stats.last.seconds,
size: deploy_local.size,
urls: [deploy_local.url]
}
}
# No es opcional # No es opcional
unless @deployed[:deploy_local] unless @deployed[:deploy_local][:status]
@site.update status: 'waiting'
notify_usuaries if notify
# Hacer fallar la tarea # Hacer fallar la tarea
raise DeployException, deploy_local.build_stats.last.log raise DeployException, "#{@site.name}: Falló la compilación"
end end
deploy_others deploy_others
rescue DeployTimedOutException => e
# Volver a la espera notify_exception e
@site.update status: 'waiting' rescue DeployException => e
notify_exception e, deploy_local
ensure
@site&.update status: 'waiting'
notify_usuaries if notify notify_usuaries if notify
end end
@ -50,6 +58,18 @@ class DeployJob < ApplicationJob
private 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 def deploy_local
@deploy_local ||= @site.deploys.find_by(type: 'DeployLocal') @deploy_local ||= @site.deploys.find_by(type: 'DeployLocal')
end end
@ -60,7 +80,22 @@ class DeployJob < ApplicationJob
def deploy_others def deploy_others
@site.deploys.where.not(type: 'DeployLocal').find_each do |d| @site.deploys.where.not(type: 'DeployLocal').find_each do |d|
@deployed[d.type.underscore.to_sym] = d.deploy begin
status = d.deploy
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: seconds || 0,
size: d.size,
urls: d.respond_to?(:urls) ? d.urls : [d.url].compact
}
end end
end end

View file

@ -3,6 +3,8 @@
# Notifica excepciones a una instancia de Gitlab, como incidencias # Notifica excepciones a una instancia de Gitlab, como incidencias
# nuevas o como comentarios a las incidencias pre-existentes. # nuevas o como comentarios a las incidencias pre-existentes.
class GitlabNotifierJob < ApplicationJob class GitlabNotifierJob < ApplicationJob
class GitlabNotifierError < StandardError; end
include ExceptionNotifier::BacktraceCleaner include ExceptionNotifier::BacktraceCleaner
# Variables que vamos a acceder luego # Variables que vamos a acceder luego
@ -18,22 +20,28 @@ class GitlabNotifierJob < ApplicationJob
@issue_data = { count: 1 } @issue_data = { count: 1 }
# Necesitamos saber si el issue ya existía # Necesitamos saber si el issue ya existía
@cached = false @cached = false
@issue = {}
# Traemos los datos desde la caché si existen, sino generamos un # Traemos los datos desde la caché si existen, sino generamos un
# issue nuevo e inicializamos la caché # issue nuevo e inicializamos la caché
@issue_data = Rails.cache.fetch(cache_key) do @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 @cached = true
{ {
count: 1, count: 1,
issue: issue['iid'], issue: @issue['iid'],
user_agents: [user_agent].compact, user_agents: [user_agent].compact,
params: [request&.filtered_parameters].compact, params: [request&.filtered_parameters].compact,
urls: [url].compact urls: [url].compact
} }
end 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 # No seguimos actualizando si acabamos de generar el issue
return if cached return if cached
@ -104,6 +112,7 @@ class GitlabNotifierJob < ApplicationJob
# @return [String] # @return [String]
def description def description
@description ||= ''.dup.tap do |d| @description ||= ''.dup.tap do |d|
d << log_section
d << request_section d << request_section
d << javascript_section d << javascript_section
d << javascript_footer d << javascript_footer
@ -151,6 +160,19 @@ class GitlabNotifierJob < ApplicationJob
@client ||= GitlabApiClient.new @client ||= GitlabApiClient.new
end end
# @return [String]
def log_section
return '' unless options[:log]
<<~LOG
# Log
```
#{options[:log]}
```
LOG
end
# Muestra información de la petición # Muestra información de la petición
# #
# @return [String] # @return [String]

View file

@ -8,21 +8,66 @@
# TODO: Agregar firma GPG y header Autocrypt # TODO: Agregar firma GPG y header Autocrypt
# TODO: Cifrar con GPG si le usuarie nos dio su llave # TODO: Cifrar con GPG si le usuarie nos dio su llave
class DeployMailer < ApplicationMailer class DeployMailer < ApplicationMailer
include ActionView::Helpers::NumberHelper
include ActionView::Helpers::DateHelper
# rubocop:disable Metrics/AbcSize # rubocop:disable Metrics/AbcSize
def deployed(which_ones) def deployed(deploys = {})
@usuarie = Usuarie.find(params[:usuarie]) usuarie = Usuarie.find(params[:usuarie])
@site = @usuarie.sites.find(params[:site]) site = usuarie.sites.find(params[:site])
@deploys = which_ones hostname = site.hostname
@deploy_local = @site.deploys.find_by(type: 'DeployLocal') deploys ||= {}
# Informamos a cada quien en su idioma y damos una dirección de # Informamos a cada quien en su idioma y damos una dirección de
# respuesta porque a veces les usuaries nos escriben # respuesta porque a veces les usuaries nos escriben
I18n.with_locale(@usuarie.lang) do I18n.with_locale(usuarie.lang) do
mail(to: @usuarie.email, subject = t('.subject', site: site.name)
reply_to: "sutty@#{Site.domain}",
subject: I18n.t('deploy_mailer.deployed.subject', @hi = t('.hi')
site: @site.name)) @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
end end
# rubocop:enable Metrics/AbcSize # rubocop:enable Metrics/AbcSize
private
def t(key, **args)
I18n.t("deploy_mailer.deployed#{key}", **args)
end
end end

View file

@ -15,6 +15,10 @@ class Deploy < ApplicationRecord
raise NotImplementedError raise NotImplementedError
end end
def url
raise NotImplementedError
end
def limit def limit
raise NotImplementedError raise NotImplementedError
end end

View file

@ -18,6 +18,10 @@ class DeployAlternativeDomain < Deploy
end end
def destination def destination
File.join(Rails.root, '_deploy', hostname.gsub(/\.\z/, '')) @destination ||= File.join(Rails.root, '_deploy', hostname.gsub(/\.\z/, ''))
end
def url
"https://#{File.basename destination}"
end end
end end

View file

@ -13,6 +13,6 @@ class DeployHiddenService < DeployWww
end end
def url def url
'http://' + fqdn "http://#{fqdn}"
end end
end end

View file

@ -25,6 +25,10 @@ class DeployLocal < Deploy
1 1
end end
def url
site.url
end
# Obtener el tamaño de todos los archivos y directorios (los # Obtener el tamaño de todos los archivos y directorios (los
# directorios son archivos :) # directorios son archivos :)
def size def size

View file

@ -16,6 +16,10 @@ class DeployPrivate < DeployLocal
File.join(Rails.root, '_private', site.name) File.join(Rails.root, '_private', site.name)
end end
def url
"#{ENV['PANEL_URL']}/sites/private/#{site.name}"
end
# No usar recursos en compresión y habilitar los datos privados # No usar recursos en compresión y habilitar los datos privados
def env def env
@env ||= super.merge({ @env ||= super.merge({

View file

@ -27,6 +27,10 @@ class DeployWww < Deploy
"www.#{site.hostname}" "www.#{site.hostname}"
end end
def url
"https://www.#{site.hostname}/"
end
private private
def remove_destination! def remove_destination!

View file

@ -49,6 +49,10 @@ class DeployZip < Deploy
"#{site.hostname}.zip" "#{site.hostname}.zip"
end end
def url
"#{site.url}#{file}"
end
def path def path
File.join(destination, file) File.join(destination, file)
end end

View file

@ -1,17 +1,21 @@
%h1= t('.hi') %h1= @hi
= sanitize_markdown t('.explanation', fqdn: @deploy_local.site.hostname), = sanitize_markdown @explanation, tags: %w[p a strong em]
tags: %w[p a strong em]
%table %table
%thead %thead
%tr %tr
%th= t('.th.type') - @headers.each do |header|
%th= t('.th.status') %th= header
%tbody %tbody
- @deploys.each do |deploy, value| - @table.each do |row|
%tr - row[:urls].each do |url|
%td= t(".#{deploy}.title") %tr
%td= value ? t(".#{deploy}.success") : t(".#{deploy}.error") %td= row[:title]
%td= row[:status]
%td= link_to_if url.present?, url, url
%td
%time{ datetime: row[:seconds][:machine] }= row[:seconds][:human]
%td= row[:size]
= sanitize_markdown t('.help'), tags: %w[p a strong em] = sanitize_markdown @help, tags: %w[p a strong em]

View file

@ -1,12 +1,7 @@
= '# ' + t('.hi') = "# #{@hi}"
\ \
= t('.explanation', fqdn: @deploy_local.site.hostname) = @explanation
\ \
= Terminal::Table.new do |table| = @terminal_table
- table << [t('.th.type'), t('.th.status')]
- table.add_separator
- @deploys.each do |deploy, value|
- table << [t(".#{deploy}.title"),
value ? t(".#{deploy}.success") : t(".#{deploy}.error")]
\ \
= t('.help') = @help

View file

@ -87,6 +87,9 @@ en:
th: th:
type: Type type: Type
status: Status status: Status
seconds: Duration
size: Space used
url: Address
deploy_local: deploy_local:
title: Build the site title: Build the site
success: Success! success: Success!

View file

@ -87,6 +87,9 @@ es:
th: th:
type: Tipo type: Tipo
status: Estado status: Estado
seconds: Duración
size: Espacio ocupado
url: Dirección
deploy_local: deploy_local:
title: Generar el sitio title: Generar el sitio
success: ¡Éxito! success: ¡Éxito!