mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
feat: notifications: report failed workspace builds (#14571)
This commit is contained in:
@ -3879,6 +3879,23 @@ func (q *sqlQuerier) GetNotificationMessagesByStatus(ctx context.Context, arg Ge
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getNotificationReportGeneratorLogByTemplate = `-- name: GetNotificationReportGeneratorLogByTemplate :one
|
||||
SELECT
|
||||
notification_template_id, last_generated_at
|
||||
FROM
|
||||
notification_report_generator_logs
|
||||
WHERE
|
||||
notification_template_id = $1::uuid
|
||||
`
|
||||
|
||||
// Fetch the notification report generator log indicating recent activity.
|
||||
func (q *sqlQuerier) GetNotificationReportGeneratorLogByTemplate(ctx context.Context, templateID uuid.UUID) (NotificationReportGeneratorLog, error) {
|
||||
row := q.db.QueryRowContext(ctx, getNotificationReportGeneratorLogByTemplate, templateID)
|
||||
var i NotificationReportGeneratorLog
|
||||
err := row.Scan(&i.NotificationTemplateID, &i.LastGeneratedAt)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getNotificationTemplateByID = `-- name: GetNotificationTemplateByID :one
|
||||
SELECT id, name, title_template, body_template, actions, "group", method, kind
|
||||
FROM notification_templates
|
||||
@ -4028,6 +4045,23 @@ func (q *sqlQuerier) UpdateUserNotificationPreferences(ctx context.Context, arg
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
const upsertNotificationReportGeneratorLog = `-- name: UpsertNotificationReportGeneratorLog :exec
|
||||
INSERT INTO notification_report_generator_logs (notification_template_id, last_generated_at) VALUES ($1, $2)
|
||||
ON CONFLICT (notification_template_id) DO UPDATE set last_generated_at = EXCLUDED.last_generated_at
|
||||
WHERE notification_report_generator_logs.notification_template_id = EXCLUDED.notification_template_id
|
||||
`
|
||||
|
||||
type UpsertNotificationReportGeneratorLogParams struct {
|
||||
NotificationTemplateID uuid.UUID `db:"notification_template_id" json:"notification_template_id"`
|
||||
LastGeneratedAt time.Time `db:"last_generated_at" json:"last_generated_at"`
|
||||
}
|
||||
|
||||
// Insert or update notification report generator logs with recent activity.
|
||||
func (q *sqlQuerier) UpsertNotificationReportGeneratorLog(ctx context.Context, arg UpsertNotificationReportGeneratorLogParams) error {
|
||||
_, err := q.db.ExecContext(ctx, upsertNotificationReportGeneratorLog, arg.NotificationTemplateID, arg.LastGeneratedAt)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteOAuth2ProviderAppByID = `-- name: DeleteOAuth2ProviderAppByID :exec
|
||||
DELETE FROM oauth2_provider_apps WHERE id = $1
|
||||
`
|
||||
@ -12896,6 +12930,83 @@ func (q *sqlQuerier) GetActiveWorkspaceBuildsByTemplateID(ctx context.Context, t
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getFailedWorkspaceBuildsByTemplateID = `-- name: GetFailedWorkspaceBuildsByTemplateID :many
|
||||
SELECT
|
||||
tv.name AS template_version_name,
|
||||
u.username AS workspace_owner_username,
|
||||
w.name AS workspace_name,
|
||||
wb.build_number AS workspace_build_number
|
||||
FROM
|
||||
workspace_build_with_user AS wb
|
||||
JOIN
|
||||
workspaces AS w
|
||||
ON
|
||||
wb.workspace_id = w.id
|
||||
JOIN
|
||||
users AS u
|
||||
ON
|
||||
w.owner_id = u.id
|
||||
JOIN
|
||||
provisioner_jobs AS pj
|
||||
ON
|
||||
wb.job_id = pj.id
|
||||
JOIN
|
||||
templates AS t
|
||||
ON
|
||||
w.template_id = t.id
|
||||
JOIN
|
||||
template_versions AS tv
|
||||
ON
|
||||
wb.template_version_id = tv.id
|
||||
WHERE
|
||||
w.template_id = $1
|
||||
AND wb.created_at >= $2
|
||||
AND pj.completed_at IS NOT NULL
|
||||
AND pj.job_status = 'failed'
|
||||
ORDER BY
|
||||
tv.name ASC, wb.build_number DESC
|
||||
`
|
||||
|
||||
type GetFailedWorkspaceBuildsByTemplateIDParams struct {
|
||||
TemplateID uuid.UUID `db:"template_id" json:"template_id"`
|
||||
Since time.Time `db:"since" json:"since"`
|
||||
}
|
||||
|
||||
type GetFailedWorkspaceBuildsByTemplateIDRow struct {
|
||||
TemplateVersionName string `db:"template_version_name" json:"template_version_name"`
|
||||
WorkspaceOwnerUsername string `db:"workspace_owner_username" json:"workspace_owner_username"`
|
||||
WorkspaceName string `db:"workspace_name" json:"workspace_name"`
|
||||
WorkspaceBuildNumber int32 `db:"workspace_build_number" json:"workspace_build_number"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetFailedWorkspaceBuildsByTemplateID(ctx context.Context, arg GetFailedWorkspaceBuildsByTemplateIDParams) ([]GetFailedWorkspaceBuildsByTemplateIDRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getFailedWorkspaceBuildsByTemplateID, arg.TemplateID, arg.Since)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetFailedWorkspaceBuildsByTemplateIDRow
|
||||
for rows.Next() {
|
||||
var i GetFailedWorkspaceBuildsByTemplateIDRow
|
||||
if err := rows.Scan(
|
||||
&i.TemplateVersionName,
|
||||
&i.WorkspaceOwnerUsername,
|
||||
&i.WorkspaceName,
|
||||
&i.WorkspaceBuildNumber,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getLatestWorkspaceBuildByWorkspaceID = `-- name: GetLatestWorkspaceBuildByWorkspaceID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, initiator_by_avatar_url, initiator_by_username
|
||||
@ -13154,6 +13265,73 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx context.Co
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceBuildStatsByTemplates = `-- name: GetWorkspaceBuildStatsByTemplates :many
|
||||
SELECT
|
||||
w.template_id,
|
||||
t.name AS template_name,
|
||||
t.display_name AS template_display_name,
|
||||
t.organization_id AS template_organization_id,
|
||||
COUNT(*) AS total_builds,
|
||||
COUNT(CASE WHEN pj.job_status = 'failed' THEN 1 END) AS failed_builds
|
||||
FROM
|
||||
workspace_build_with_user AS wb
|
||||
JOIN
|
||||
workspaces AS w ON
|
||||
wb.workspace_id = w.id
|
||||
JOIN
|
||||
provisioner_jobs AS pj ON
|
||||
wb.job_id = pj.id
|
||||
JOIN
|
||||
templates AS t ON
|
||||
w.template_id = t.id
|
||||
WHERE
|
||||
wb.created_at >= $1
|
||||
AND pj.completed_at IS NOT NULL
|
||||
GROUP BY
|
||||
w.template_id, template_name, template_display_name, template_organization_id
|
||||
ORDER BY
|
||||
template_name ASC
|
||||
`
|
||||
|
||||
type GetWorkspaceBuildStatsByTemplatesRow struct {
|
||||
TemplateID uuid.UUID `db:"template_id" json:"template_id"`
|
||||
TemplateName string `db:"template_name" json:"template_name"`
|
||||
TemplateDisplayName string `db:"template_display_name" json:"template_display_name"`
|
||||
TemplateOrganizationID uuid.UUID `db:"template_organization_id" json:"template_organization_id"`
|
||||
TotalBuilds int64 `db:"total_builds" json:"total_builds"`
|
||||
FailedBuilds int64 `db:"failed_builds" json:"failed_builds"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceBuildStatsByTemplates(ctx context.Context, since time.Time) ([]GetWorkspaceBuildStatsByTemplatesRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getWorkspaceBuildStatsByTemplates, since)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetWorkspaceBuildStatsByTemplatesRow
|
||||
for rows.Next() {
|
||||
var i GetWorkspaceBuildStatsByTemplatesRow
|
||||
if err := rows.Scan(
|
||||
&i.TemplateID,
|
||||
&i.TemplateName,
|
||||
&i.TemplateDisplayName,
|
||||
&i.TemplateOrganizationID,
|
||||
&i.TotalBuilds,
|
||||
&i.FailedBuilds,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getWorkspaceBuildsByWorkspaceID = `-- name: GetWorkspaceBuildsByWorkspaceID :many
|
||||
SELECT
|
||||
id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, initiator_by_avatar_url, initiator_by_username
|
||||
|
Reference in New Issue
Block a user