Add commit URL to Slack notifications with link and backtick formatting
- Add commit_url column to webhook_events and deployments tables - Extract commit URL from webhook payload (from commit object or repo URL) - Format Slack messages with backticks for branch and commit SHA - Link commit SHA to the actual commit URL on the git server - Keep plain text format for ntfy notifications
This commit is contained in:
parent
4cd12d717c
commit
c4362c3143
3
internal/database/migrations/004_add_commit_url.sql
Normal file
3
internal/database/migrations/004_add_commit_url.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- Add commit_url column to webhook_events and deployments tables
|
||||||
|
ALTER TABLE webhook_events ADD COLUMN commit_url TEXT;
|
||||||
|
ALTER TABLE deployments ADD COLUMN commit_url TEXT;
|
||||||
@ -37,6 +37,7 @@ type Deployment struct {
|
|||||||
AppID string
|
AppID string
|
||||||
WebhookEventID sql.NullInt64
|
WebhookEventID sql.NullInt64
|
||||||
CommitSHA sql.NullString
|
CommitSHA sql.NullString
|
||||||
|
CommitURL sql.NullString
|
||||||
ImageID sql.NullString
|
ImageID sql.NullString
|
||||||
ContainerID sql.NullString
|
ContainerID sql.NullString
|
||||||
Status DeploymentStatus
|
Status DeploymentStatus
|
||||||
@ -65,7 +66,7 @@ func (d *Deployment) Save(ctx context.Context) error {
|
|||||||
// Reload refreshes the deployment from the database.
|
// Reload refreshes the deployment from the database.
|
||||||
func (d *Deployment) Reload(ctx context.Context) error {
|
func (d *Deployment) Reload(ctx context.Context) error {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, app_id, webhook_event_id, commit_sha, image_id,
|
SELECT id, app_id, webhook_event_id, commit_sha, commit_url, image_id,
|
||||||
container_id, status, logs, started_at, finished_at
|
container_id, status, logs, started_at, finished_at
|
||||||
FROM deployments WHERE id = ?`
|
FROM deployments WHERE id = ?`
|
||||||
|
|
||||||
@ -156,12 +157,12 @@ func (d *Deployment) FinishedAtFormatted() string {
|
|||||||
func (d *Deployment) insert(ctx context.Context) error {
|
func (d *Deployment) insert(ctx context.Context) error {
|
||||||
query := `
|
query := `
|
||||||
INSERT INTO deployments (
|
INSERT INTO deployments (
|
||||||
app_id, webhook_event_id, commit_sha, image_id,
|
app_id, webhook_event_id, commit_sha, commit_url, image_id,
|
||||||
container_id, status, logs
|
container_id, status, logs
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?)`
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
||||||
|
|
||||||
result, err := d.db.Exec(ctx, query,
|
result, err := d.db.Exec(ctx, query,
|
||||||
d.AppID, d.WebhookEventID, d.CommitSHA, d.ImageID,
|
d.AppID, d.WebhookEventID, d.CommitSHA, d.CommitURL, d.ImageID,
|
||||||
d.ContainerID, d.Status, d.Logs,
|
d.ContainerID, d.Status, d.Logs,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -193,7 +194,7 @@ func (d *Deployment) update(ctx context.Context) error {
|
|||||||
|
|
||||||
func (d *Deployment) scan(row *sql.Row) error {
|
func (d *Deployment) scan(row *sql.Row) error {
|
||||||
return row.Scan(
|
return row.Scan(
|
||||||
&d.ID, &d.AppID, &d.WebhookEventID, &d.CommitSHA, &d.ImageID,
|
&d.ID, &d.AppID, &d.WebhookEventID, &d.CommitSHA, &d.CommitURL, &d.ImageID,
|
||||||
&d.ContainerID, &d.Status, &d.Logs, &d.StartedAt, &d.FinishedAt,
|
&d.ContainerID, &d.Status, &d.Logs, &d.StartedAt, &d.FinishedAt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -210,7 +211,7 @@ func FindDeployment(
|
|||||||
deploy.ID = deployID
|
deploy.ID = deployID
|
||||||
|
|
||||||
row := deployDB.QueryRow(ctx, `
|
row := deployDB.QueryRow(ctx, `
|
||||||
SELECT id, app_id, webhook_event_id, commit_sha, image_id,
|
SELECT id, app_id, webhook_event_id, commit_sha, commit_url, image_id,
|
||||||
container_id, status, logs, started_at, finished_at
|
container_id, status, logs, started_at, finished_at
|
||||||
FROM deployments WHERE id = ?`,
|
FROM deployments WHERE id = ?`,
|
||||||
deployID,
|
deployID,
|
||||||
@ -236,7 +237,7 @@ func FindDeploymentsByAppID(
|
|||||||
limit int,
|
limit int,
|
||||||
) ([]*Deployment, error) {
|
) ([]*Deployment, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, app_id, webhook_event_id, commit_sha, image_id,
|
SELECT id, app_id, webhook_event_id, commit_sha, commit_url, image_id,
|
||||||
container_id, status, logs, started_at, finished_at
|
container_id, status, logs, started_at, finished_at
|
||||||
FROM deployments WHERE app_id = ?
|
FROM deployments WHERE app_id = ?
|
||||||
ORDER BY started_at DESC, id DESC LIMIT ?`
|
ORDER BY started_at DESC, id DESC LIMIT ?`
|
||||||
@ -255,7 +256,7 @@ func FindDeploymentsByAppID(
|
|||||||
|
|
||||||
scanErr := rows.Scan(
|
scanErr := rows.Scan(
|
||||||
&deploy.ID, &deploy.AppID, &deploy.WebhookEventID,
|
&deploy.ID, &deploy.AppID, &deploy.WebhookEventID,
|
||||||
&deploy.CommitSHA, &deploy.ImageID, &deploy.ContainerID,
|
&deploy.CommitSHA, &deploy.CommitURL, &deploy.ImageID, &deploy.ContainerID,
|
||||||
&deploy.Status, &deploy.Logs, &deploy.StartedAt, &deploy.FinishedAt,
|
&deploy.Status, &deploy.Logs, &deploy.StartedAt, &deploy.FinishedAt,
|
||||||
)
|
)
|
||||||
if scanErr != nil {
|
if scanErr != nil {
|
||||||
@ -284,7 +285,7 @@ func LatestDeploymentForApp(
|
|||||||
deploy := NewDeployment(deployDB)
|
deploy := NewDeployment(deployDB)
|
||||||
|
|
||||||
row := deployDB.QueryRow(ctx, `
|
row := deployDB.QueryRow(ctx, `
|
||||||
SELECT id, app_id, webhook_event_id, commit_sha, image_id,
|
SELECT id, app_id, webhook_event_id, commit_sha, commit_url, image_id,
|
||||||
container_id, status, logs, started_at, finished_at
|
container_id, status, logs, started_at, finished_at
|
||||||
FROM deployments WHERE app_id = ?
|
FROM deployments WHERE app_id = ?
|
||||||
ORDER BY started_at DESC, id DESC LIMIT 1`,
|
ORDER BY started_at DESC, id DESC LIMIT 1`,
|
||||||
|
|||||||
@ -19,6 +19,7 @@ type WebhookEvent struct {
|
|||||||
EventType string
|
EventType string
|
||||||
Branch string
|
Branch string
|
||||||
CommitSHA sql.NullString
|
CommitSHA sql.NullString
|
||||||
|
CommitURL sql.NullString
|
||||||
Payload sql.NullString
|
Payload sql.NullString
|
||||||
Matched bool
|
Matched bool
|
||||||
Processed bool
|
Processed bool
|
||||||
@ -42,8 +43,8 @@ func (w *WebhookEvent) Save(ctx context.Context) error {
|
|||||||
// Reload refreshes the webhook event from the database.
|
// Reload refreshes the webhook event from the database.
|
||||||
func (w *WebhookEvent) Reload(ctx context.Context) error {
|
func (w *WebhookEvent) Reload(ctx context.Context) error {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, app_id, event_type, branch, commit_sha, payload,
|
SELECT id, app_id, event_type, branch, commit_sha, commit_url,
|
||||||
matched, processed, created_at
|
payload, matched, processed, created_at
|
||||||
FROM webhook_events WHERE id = ?`
|
FROM webhook_events WHERE id = ?`
|
||||||
|
|
||||||
row := w.db.QueryRow(ctx, query, w.ID)
|
row := w.db.QueryRow(ctx, query, w.ID)
|
||||||
@ -54,11 +55,11 @@ func (w *WebhookEvent) Reload(ctx context.Context) error {
|
|||||||
func (w *WebhookEvent) insert(ctx context.Context) error {
|
func (w *WebhookEvent) insert(ctx context.Context) error {
|
||||||
query := `
|
query := `
|
||||||
INSERT INTO webhook_events (
|
INSERT INTO webhook_events (
|
||||||
app_id, event_type, branch, commit_sha, payload, matched, processed
|
app_id, event_type, branch, commit_sha, commit_url, payload, matched, processed
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?)`
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
||||||
|
|
||||||
result, err := w.db.Exec(ctx, query,
|
result, err := w.db.Exec(ctx, query,
|
||||||
w.AppID, w.EventType, w.Branch, w.CommitSHA,
|
w.AppID, w.EventType, w.Branch, w.CommitSHA, w.CommitURL,
|
||||||
w.Payload, w.Matched, w.Processed,
|
w.Payload, w.Matched, w.Processed,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -86,7 +87,7 @@ func (w *WebhookEvent) update(ctx context.Context) error {
|
|||||||
func (w *WebhookEvent) scan(row *sql.Row) error {
|
func (w *WebhookEvent) scan(row *sql.Row) error {
|
||||||
return row.Scan(
|
return row.Scan(
|
||||||
&w.ID, &w.AppID, &w.EventType, &w.Branch, &w.CommitSHA,
|
&w.ID, &w.AppID, &w.EventType, &w.Branch, &w.CommitSHA,
|
||||||
&w.Payload, &w.Matched, &w.Processed, &w.CreatedAt,
|
&w.CommitURL, &w.Payload, &w.Matched, &w.Processed, &w.CreatedAt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,8 +103,8 @@ func FindWebhookEvent(
|
|||||||
event.ID = id
|
event.ID = id
|
||||||
|
|
||||||
row := db.QueryRow(ctx, `
|
row := db.QueryRow(ctx, `
|
||||||
SELECT id, app_id, event_type, branch, commit_sha, payload,
|
SELECT id, app_id, event_type, branch, commit_sha, commit_url,
|
||||||
matched, processed, created_at
|
payload, matched, processed, created_at
|
||||||
FROM webhook_events WHERE id = ?`,
|
FROM webhook_events WHERE id = ?`,
|
||||||
id,
|
id,
|
||||||
)
|
)
|
||||||
@ -128,8 +129,8 @@ func FindWebhookEventsByAppID(
|
|||||||
limit int,
|
limit int,
|
||||||
) ([]*WebhookEvent, error) {
|
) ([]*WebhookEvent, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, app_id, event_type, branch, commit_sha, payload,
|
SELECT id, app_id, event_type, branch, commit_sha, commit_url,
|
||||||
matched, processed, created_at
|
payload, matched, processed, created_at
|
||||||
FROM webhook_events WHERE app_id = ? ORDER BY created_at DESC LIMIT ?`
|
FROM webhook_events WHERE app_id = ? ORDER BY created_at DESC LIMIT ?`
|
||||||
|
|
||||||
rows, err := db.Query(ctx, query, appID, limit)
|
rows, err := db.Query(ctx, query, appID, limit)
|
||||||
@ -146,7 +147,7 @@ func FindWebhookEventsByAppID(
|
|||||||
|
|
||||||
scanErr := rows.Scan(
|
scanErr := rows.Scan(
|
||||||
&event.ID, &event.AppID, &event.EventType, &event.Branch,
|
&event.ID, &event.AppID, &event.EventType, &event.Branch,
|
||||||
&event.CommitSHA, &event.Payload, &event.Matched,
|
&event.CommitSHA, &event.CommitURL, &event.Payload, &event.Matched,
|
||||||
&event.Processed, &event.CreatedAt,
|
&event.Processed, &event.CreatedAt,
|
||||||
)
|
)
|
||||||
if scanErr != nil {
|
if scanErr != nil {
|
||||||
@ -165,8 +166,8 @@ func FindUnprocessedWebhookEvents(
|
|||||||
db *database.Database,
|
db *database.Database,
|
||||||
) ([]*WebhookEvent, error) {
|
) ([]*WebhookEvent, error) {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, app_id, event_type, branch, commit_sha, payload,
|
SELECT id, app_id, event_type, branch, commit_sha, commit_url,
|
||||||
matched, processed, created_at
|
payload, matched, processed, created_at
|
||||||
FROM webhook_events
|
FROM webhook_events
|
||||||
WHERE matched = 1 AND processed = 0 ORDER BY created_at ASC`
|
WHERE matched = 1 AND processed = 0 ORDER BY created_at ASC`
|
||||||
|
|
||||||
@ -184,7 +185,7 @@ func FindUnprocessedWebhookEvents(
|
|||||||
|
|
||||||
scanErr := rows.Scan(
|
scanErr := rows.Scan(
|
||||||
&event.ID, &event.AppID, &event.EventType, &event.Branch,
|
&event.ID, &event.AppID, &event.EventType, &event.Branch,
|
||||||
&event.CommitSHA, &event.Payload, &event.Matched,
|
&event.CommitSHA, &event.CommitURL, &event.Payload, &event.Matched,
|
||||||
&event.Processed, &event.CreatedAt,
|
&event.Processed, &event.CreatedAt,
|
||||||
)
|
)
|
||||||
if scanErr != nil {
|
if scanErr != nil {
|
||||||
|
|||||||
@ -439,9 +439,15 @@ func (svc *Service) createDeploymentRecord(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set commit SHA from webhook event
|
// Set commit SHA and URL from webhook event
|
||||||
if webhookEvent != nil && webhookEvent.CommitSHA.Valid {
|
if webhookEvent != nil {
|
||||||
deployment.CommitSHA = webhookEvent.CommitSHA
|
if webhookEvent.CommitSHA.Valid {
|
||||||
|
deployment.CommitSHA = webhookEvent.CommitSHA
|
||||||
|
}
|
||||||
|
|
||||||
|
if webhookEvent.CommitURL.Valid {
|
||||||
|
deployment.CommitURL = webhookEvent.CommitURL
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deployment.Status = models.DeploymentStatusBuilding
|
deployment.Status = models.DeploymentStatusBuilding
|
||||||
|
|||||||
@ -4,6 +4,7 @@ package notify
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -73,14 +74,24 @@ func (svc *Service) NotifyBuildStart(
|
|||||||
deployment *models.Deployment,
|
deployment *models.Deployment,
|
||||||
) {
|
) {
|
||||||
title := "Build started: " + app.Name
|
title := "Build started: " + app.Name
|
||||||
message := "Building from branch " + app.Branch
|
|
||||||
|
// Plain text message for ntfy
|
||||||
|
ntfyMessage := "Building from branch " + app.Branch
|
||||||
|
|
||||||
if deployment.CommitSHA.Valid {
|
if deployment.CommitSHA.Valid {
|
||||||
shortSHA := deployment.CommitSHA.String[:minInt(shortCommitLength, len(deployment.CommitSHA.String))]
|
shortSHA := truncateSHA(deployment.CommitSHA.String)
|
||||||
message += " at " + shortSHA
|
ntfyMessage += " at " + shortSHA
|
||||||
}
|
}
|
||||||
|
|
||||||
svc.sendNotifications(ctx, app, title, message, "info")
|
// Slack message with formatting
|
||||||
|
slackMessage := "Building from branch `" + app.Branch + "`"
|
||||||
|
|
||||||
|
if deployment.CommitSHA.Valid {
|
||||||
|
shortSHA := truncateSHA(deployment.CommitSHA.String)
|
||||||
|
slackMessage += " at " + formatCommitLink(shortSHA, deployment.CommitURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.sendNotifications(ctx, app, title, ntfyMessage, slackMessage, "info")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyBuildSuccess sends a build success notification.
|
// NotifyBuildSuccess sends a build success notification.
|
||||||
@ -93,7 +104,7 @@ func (svc *Service) NotifyBuildSuccess(
|
|||||||
title := "Build success: " + app.Name
|
title := "Build success: " + app.Name
|
||||||
message := "Image built successfully in " + formatDuration(duration)
|
message := "Image built successfully in " + formatDuration(duration)
|
||||||
|
|
||||||
svc.sendNotifications(ctx, app, title, message, "success")
|
svc.sendNotifications(ctx, app, title, message, message, "success")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyBuildFailed sends a build failed notification.
|
// NotifyBuildFailed sends a build failed notification.
|
||||||
@ -107,7 +118,7 @@ func (svc *Service) NotifyBuildFailed(
|
|||||||
title := "Build failed: " + app.Name
|
title := "Build failed: " + app.Name
|
||||||
message := "Build failed after " + formatDuration(duration) + ": " + buildErr.Error()
|
message := "Build failed after " + formatDuration(duration) + ": " + buildErr.Error()
|
||||||
|
|
||||||
svc.sendNotifications(ctx, app, title, message, "error")
|
svc.sendNotifications(ctx, app, title, message, message, "error")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyDeploySuccess sends a deploy success notification.
|
// NotifyDeploySuccess sends a deploy success notification.
|
||||||
@ -118,14 +129,24 @@ func (svc *Service) NotifyDeploySuccess(
|
|||||||
) {
|
) {
|
||||||
duration := time.Since(deployment.StartedAt)
|
duration := time.Since(deployment.StartedAt)
|
||||||
title := "Deploy success: " + app.Name
|
title := "Deploy success: " + app.Name
|
||||||
message := "Successfully deployed in " + formatDuration(duration)
|
|
||||||
|
// Plain text message for ntfy
|
||||||
|
ntfyMessage := "Successfully deployed in " + formatDuration(duration)
|
||||||
|
|
||||||
if deployment.CommitSHA.Valid {
|
if deployment.CommitSHA.Valid {
|
||||||
shortSHA := deployment.CommitSHA.String[:minInt(shortCommitLength, len(deployment.CommitSHA.String))]
|
shortSHA := truncateSHA(deployment.CommitSHA.String)
|
||||||
message += " (commit " + shortSHA + ")"
|
ntfyMessage += " (commit " + shortSHA + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
svc.sendNotifications(ctx, app, title, message, "success")
|
// Slack message with formatting
|
||||||
|
slackMessage := "Successfully deployed in " + formatDuration(duration)
|
||||||
|
|
||||||
|
if deployment.CommitSHA.Valid {
|
||||||
|
shortSHA := truncateSHA(deployment.CommitSHA.String)
|
||||||
|
slackMessage += " (commit " + formatCommitLink(shortSHA, deployment.CommitURL) + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.sendNotifications(ctx, app, title, ntfyMessage, slackMessage, "success")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyDeployFailed sends a deploy failed notification.
|
// NotifyDeployFailed sends a deploy failed notification.
|
||||||
@ -139,7 +160,7 @@ func (svc *Service) NotifyDeployFailed(
|
|||||||
title := "Deploy failed: " + app.Name
|
title := "Deploy failed: " + app.Name
|
||||||
message := "Deployment failed after " + formatDuration(duration) + ": " + deployErr.Error()
|
message := "Deployment failed after " + formatDuration(duration) + ": " + deployErr.Error()
|
||||||
|
|
||||||
svc.sendNotifications(ctx, app, title, message, "error")
|
svc.sendNotifications(ctx, app, title, message, message, "error")
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatDuration formats a duration for display.
|
// formatDuration formats a duration for display.
|
||||||
@ -154,19 +175,28 @@ func formatDuration(d time.Duration) string {
|
|||||||
return fmt.Sprintf("%dm %ds", minutes, seconds)
|
return fmt.Sprintf("%dm %ds", minutes, seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
// minInt returns the smaller of two integers.
|
// truncateSHA truncates a commit SHA to shortCommitLength characters.
|
||||||
func minInt(a, b int) int {
|
func truncateSHA(sha string) string {
|
||||||
if a < b {
|
if len(sha) > shortCommitLength {
|
||||||
return a
|
return sha[:shortCommitLength]
|
||||||
}
|
}
|
||||||
|
|
||||||
return b
|
return sha
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatCommitLink formats a commit SHA as a Slack link if URL is available.
|
||||||
|
func formatCommitLink(shortSHA string, commitURL sql.NullString) string {
|
||||||
|
if commitURL.Valid && commitURL.String != "" {
|
||||||
|
return "<" + commitURL.String + "|`" + shortSHA + "`>"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "`" + shortSHA + "`"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *Service) sendNotifications(
|
func (svc *Service) sendNotifications(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
app *models.App,
|
app *models.App,
|
||||||
title, message, priority string,
|
title, ntfyMessage, slackMessage, priority string,
|
||||||
) {
|
) {
|
||||||
// Send to ntfy if configured
|
// Send to ntfy if configured
|
||||||
if app.NtfyTopic.Valid && app.NtfyTopic.String != "" {
|
if app.NtfyTopic.Valid && app.NtfyTopic.String != "" {
|
||||||
@ -178,7 +208,7 @@ func (svc *Service) sendNotifications(
|
|||||||
// even if the parent context is cancelled.
|
// even if the parent context is cancelled.
|
||||||
notifyCtx := context.WithoutCancel(ctx)
|
notifyCtx := context.WithoutCancel(ctx)
|
||||||
|
|
||||||
ntfyErr := svc.sendNtfy(notifyCtx, ntfyTopic, title, message, priority)
|
ntfyErr := svc.sendNtfy(notifyCtx, ntfyTopic, title, ntfyMessage, priority)
|
||||||
if ntfyErr != nil {
|
if ntfyErr != nil {
|
||||||
svc.log.Error(
|
svc.log.Error(
|
||||||
"failed to send ntfy notification",
|
"failed to send ntfy notification",
|
||||||
@ -199,7 +229,7 @@ func (svc *Service) sendNotifications(
|
|||||||
// even if the parent context is cancelled.
|
// even if the parent context is cancelled.
|
||||||
notifyCtx := context.WithoutCancel(ctx)
|
notifyCtx := context.WithoutCancel(ctx)
|
||||||
|
|
||||||
slackErr := svc.sendSlack(notifyCtx, slackWebhook, title, message, priority)
|
slackErr := svc.sendSlack(notifyCtx, slackWebhook, title, slackMessage, priority)
|
||||||
if slackErr != nil {
|
if slackErr != nil {
|
||||||
svc.log.Error(
|
svc.log.Error(
|
||||||
"failed to send slack notification",
|
"failed to send slack notification",
|
||||||
|
|||||||
@ -50,10 +50,12 @@ type GiteaPushPayload struct {
|
|||||||
Ref string `json:"ref"`
|
Ref string `json:"ref"`
|
||||||
Before string `json:"before"`
|
Before string `json:"before"`
|
||||||
After string `json:"after"`
|
After string `json:"after"`
|
||||||
|
CompareURL string `json:"compare_url"`
|
||||||
Repository struct {
|
Repository struct {
|
||||||
FullName string `json:"full_name"`
|
FullName string `json:"full_name"`
|
||||||
CloneURL string `json:"clone_url"`
|
CloneURL string `json:"clone_url"`
|
||||||
SSHURL string `json:"ssh_url"`
|
SSHURL string `json:"ssh_url"`
|
||||||
|
HTMLURL string `json:"html_url"`
|
||||||
} `json:"repository"`
|
} `json:"repository"`
|
||||||
Pusher struct {
|
Pusher struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@ -61,6 +63,7 @@ type GiteaPushPayload struct {
|
|||||||
} `json:"pusher"`
|
} `json:"pusher"`
|
||||||
Commits []struct {
|
Commits []struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
URL string `json:"url"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Author struct {
|
Author struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -90,6 +93,7 @@ func (svc *Service) HandleWebhook(
|
|||||||
// Extract branch from ref
|
// Extract branch from ref
|
||||||
branch := extractBranch(pushPayload.Ref)
|
branch := extractBranch(pushPayload.Ref)
|
||||||
commitSHA := pushPayload.After
|
commitSHA := pushPayload.After
|
||||||
|
commitURL := extractCommitURL(pushPayload)
|
||||||
|
|
||||||
// Check if branch matches
|
// Check if branch matches
|
||||||
matched := branch == app.Branch
|
matched := branch == app.Branch
|
||||||
@ -100,6 +104,7 @@ func (svc *Service) HandleWebhook(
|
|||||||
event.EventType = eventType
|
event.EventType = eventType
|
||||||
event.Branch = branch
|
event.Branch = branch
|
||||||
event.CommitSHA = sql.NullString{String: commitSHA, Valid: commitSHA != ""}
|
event.CommitSHA = sql.NullString{String: commitSHA, Valid: commitSHA != ""}
|
||||||
|
event.CommitURL = sql.NullString{String: commitURL, Valid: commitURL != ""}
|
||||||
event.Payload = sql.NullString{String: string(payload), Valid: true}
|
event.Payload = sql.NullString{String: string(payload), Valid: true}
|
||||||
event.Matched = matched
|
event.Matched = matched
|
||||||
event.Processed = false
|
event.Processed = false
|
||||||
@ -160,3 +165,21 @@ func extractBranch(ref string) string {
|
|||||||
|
|
||||||
return ref
|
return ref
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractCommitURL extracts the commit URL from the webhook payload.
|
||||||
|
// Prefers the URL from the head commit, falls back to constructing from repo URL.
|
||||||
|
func extractCommitURL(payload GiteaPushPayload) string {
|
||||||
|
// Try to find the URL from the head commit (matching After SHA)
|
||||||
|
for _, commit := range payload.Commits {
|
||||||
|
if commit.ID == payload.After && commit.URL != "" {
|
||||||
|
return commit.URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to constructing URL from repo HTML URL
|
||||||
|
if payload.Repository.HTMLURL != "" && payload.After != "" {
|
||||||
|
return payload.Repository.HTMLURL + "/commit/" + payload.After
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user