The codebase that powers boop.cat
boop.cat
1// Copyright 2025 boop.cat
2// Licensed under the Apache License, Version 2.0
3// See LICENSE file for details.
4
5package db
6
7import (
8 "database/sql"
9 "time"
10)
11
12type Deployment struct {
13 ID string
14 UserID string
15 SiteID string
16 CreatedAt string
17 Status string
18 URL sql.NullString
19 CommitSha sql.NullString
20 CommitMessage sql.NullString
21 CommitAuthor sql.NullString
22 CommitAvatar sql.NullString
23 LogsPath sql.NullString
24}
25
26type DeploymentResponse struct {
27 ID string `json:"id"`
28 Status string `json:"status"`
29 URL *string `json:"url"`
30 CreatedAt string `json:"createdAt"`
31 CommitSha *string `json:"commitSha"`
32 CommitMessage *string `json:"commitMessage"`
33 CommitAuthor *string `json:"commitAuthor"`
34 CommitAvatar *string `json:"commitAvatar"`
35}
36
37func (d *Deployment) ToResponse() DeploymentResponse {
38 resp := DeploymentResponse{
39 ID: d.ID,
40 Status: d.Status,
41 CreatedAt: d.CreatedAt,
42 }
43 if d.URL.Valid {
44 resp.URL = &d.URL.String
45 }
46 if d.CommitSha.Valid {
47 resp.CommitSha = &d.CommitSha.String
48 }
49 if d.CommitMessage.Valid {
50 resp.CommitMessage = &d.CommitMessage.String
51 }
52 if d.CommitAuthor.Valid {
53 resp.CommitAuthor = &d.CommitAuthor.String
54 }
55 if d.CommitAvatar.Valid {
56 resp.CommitAvatar = &d.CommitAvatar.String
57 }
58 return resp
59}
60
61func CreateDeployment(db *sql.DB, id, userID, siteID, status string, commitSha, commitMessage, commitAuthor, commitAvatar *string) error {
62 _, err := db.Exec(`
63 INSERT INTO deployments (id, userId, siteId, createdAt, status, commitSha, commitMessage, commitAuthor, commitAvatar)
64 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
65 `, id, userID, siteID, time.Now().UTC().Format(time.RFC3339), status, commitSha, commitMessage, commitAuthor, commitAvatar)
66 return err
67}
68
69func UpdateDeploymentStatus(db *sql.DB, id, status, urlStr string) error {
70 var urlVal sql.NullString
71 if urlStr != "" {
72 urlVal = sql.NullString{String: urlStr, Valid: true}
73 }
74 _, err := db.Exec(`UPDATE deployments SET status = ?, url = ? WHERE id = ?`, status, urlVal, id)
75 return err
76}
77
78func UpdateDeploymentLogs(db *sql.DB, id, logsPath string) error {
79 _, err := db.Exec(`UPDATE deployments SET logsPath = ? WHERE id = ?`, logsPath, id)
80 return err
81}
82
83func StopOtherDeployments(db *sql.DB, siteID, currentDeployID string) error {
84 _, err := db.Exec(`
85 UPDATE deployments
86 SET status = 'stopped'
87 WHERE siteId = ? AND id != ? AND status = 'running'
88 `, siteID, currentDeployID)
89 return err
90}
91
92func GetDeploymentByID(db *sql.DB, id string) (*Deployment, error) {
93 var d Deployment
94 err := db.QueryRow(`
95 SELECT id, userId, siteId, createdAt, status, url, commitSha, commitMessage, commitAuthor, commitAvatar, logsPath
96 FROM deployments WHERE id = ?
97 `, id).Scan(&d.ID, &d.UserID, &d.SiteID, &d.CreatedAt, &d.Status,
98 &d.URL, &d.CommitSha, &d.CommitMessage, &d.CommitAuthor, &d.CommitAvatar, &d.LogsPath)
99 if err != nil {
100 return nil, err
101 }
102 return &d, nil
103}
104
105func ListDeployments(db *sql.DB, userID, siteID string) ([]Deployment, error) {
106 rows, err := db.Query(`
107 SELECT id, userId, siteId, createdAt, status, url, commitSha, commitMessage, commitAuthor, commitAvatar, logsPath
108 FROM deployments WHERE userId = ? AND siteId = ?
109 ORDER BY createdAt DESC
110 `, userID, siteID)
111 if err != nil {
112 return nil, err
113 }
114 defer rows.Close()
115
116 var deps []Deployment
117 for rows.Next() {
118 var d Deployment
119 if err := rows.Scan(&d.ID, &d.UserID, &d.SiteID, &d.CreatedAt, &d.Status,
120 &d.URL, &d.CommitSha, &d.CommitMessage, &d.CommitAuthor, &d.CommitAvatar, &d.LogsPath); err != nil {
121 return nil, err
122 }
123 deps = append(deps, d)
124 }
125 return deps, rows.Err()
126}