Merge pull request 'ci: add Gitea Actions workflow with gofmt and test jobs' (#10) from feat/ci-workflow into main

Reviewed-on: #10
Reviewed-by: codex <39+codex@noreply.localhost>
This commit was merged in pull request #10.
This commit is contained in:
2026-04-27 22:47:50 +07:00
8 changed files with 66 additions and 37 deletions
+29
View File
@@ -0,0 +1,29 @@
name: CI
on:
pull_request:
jobs:
fmt:
runs-on: linux
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: |
out=$(gofmt -l .)
if [ -n "$out" ]; then
echo "Files not formatted:"
echo "$out"
exit 1
fi
test:
runs-on: linux
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go test ./...
+6 -6
View File
@@ -9,10 +9,10 @@ import (
"strings" "strings"
"time" "time"
"gorm.io/gorm"
"thuanle.me/claw-email-bridge/internal/config" "thuanle.me/claw-email-bridge/internal/config"
"thuanle.me/claw-email-bridge/internal/database" "thuanle.me/claw-email-bridge/internal/database"
"thuanle.me/claw-email-bridge/internal/logging" "thuanle.me/claw-email-bridge/internal/logging"
"gorm.io/gorm"
) )
// Retry backoff schedule: 1s, 5s, 15s. // Retry backoff schedule: 1s, 5s, 15s.
@@ -20,11 +20,11 @@ var retryBackoffs = []time.Duration{1 * time.Second, 5 * time.Second, 15 * time.
// openClawRequest is the payload sent to OpenClaw API. // openClawRequest is the payload sent to OpenClaw API.
type openClawRequest struct { type openClawRequest struct {
Input string `json:"input"` Input string `json:"input"`
SessionID string `json:"session_id"` SessionID string `json:"session_id"`
History []historyEntry `json:"history,omitempty"` History []historyEntry `json:"history,omitempty"`
CallbackURL string `json:"callback_url"` CallbackURL string `json:"callback_url"`
Metadata map[string]string `json:"metadata"` Metadata map[string]string `json:"metadata"`
} }
type historyEntry struct { type historyEntry struct {
+3 -3
View File
@@ -130,9 +130,9 @@ func TestDispatch_UsesCallbackBaseURL(t *testing.T) {
defer mockServer.Close() defer mockServer.Close()
cfg := &config.Config{ cfg := &config.Config{
OpenClawURL: mockServer.URL, OpenClawURL: mockServer.URL,
ListenAddr: ":9999", ListenAddr: ":9999",
CallbackBaseURL: "https://bridge.example.com/", CallbackBaseURL: "https://bridge.example.com/",
} }
task := &database.Task{ task := &database.Task{
+1 -1
View File
@@ -5,9 +5,9 @@ import (
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm"
"thuanle.me/claw-email-bridge/internal/database" "thuanle.me/claw-email-bridge/internal/database"
"thuanle.me/claw-email-bridge/internal/logging" "thuanle.me/claw-email-bridge/internal/logging"
"gorm.io/gorm"
) )
// CallbackRequest is the payload received from OpenClaw. // CallbackRequest is the payload received from OpenClaw.
+11 -11
View File
@@ -102,17 +102,17 @@ func defaultCallbackBaseURL(listenAddr string) string {
// validate checks that all required configuration values are present. // validate checks that all required configuration values are present.
func (c *Config) validate() error { func (c *Config) validate() error {
required := map[string]string{ required := map[string]string{
"IMAP_HOST": c.IMAPHost, "IMAP_HOST": c.IMAPHost,
"IMAP_PORT": c.IMAPPort, "IMAP_PORT": c.IMAPPort,
"IMAP_USER": c.IMAPUser, "IMAP_USER": c.IMAPUser,
"IMAP_PASS": c.IMAPPass, "IMAP_PASS": c.IMAPPass,
"SMTP_HOST": c.SMTPHost, "SMTP_HOST": c.SMTPHost,
"SMTP_PORT": c.SMTPPort, "SMTP_PORT": c.SMTPPort,
"SMTP_USER": c.SMTPUser, "SMTP_USER": c.SMTPUser,
"SMTP_PASS": c.SMTPPass, "SMTP_PASS": c.SMTPPass,
"OPENCLAW_URL": c.OpenClawURL, "OPENCLAW_URL": c.OpenClawURL,
"BRIDGE_CALLBACK_TOKEN": c.BridgeCallbackToken, "BRIDGE_CALLBACK_TOKEN": c.BridgeCallbackToken,
"SYSTEM_EMAIL": c.SystemEmail, "SYSTEM_EMAIL": c.SystemEmail,
} }
var missing []string var missing []string
+14 -14
View File
@@ -6,28 +6,28 @@ import (
// Task status constants matching the requirement's state machine. // Task status constants matching the requirement's state machine.
const ( const (
StatusIgnored = "IGNORED" StatusIgnored = "IGNORED"
StatusReceived = "RECEIVED" StatusReceived = "RECEIVED"
StatusAIProcessing = "AI_PROCESSING" StatusAIProcessing = "AI_PROCESSING"
StatusCallbackDone = "CALLBACK_DONE" StatusCallbackDone = "CALLBACK_DONE"
StatusSMTPRetrying = "SMTP_RETRYING" StatusSMTPRetrying = "SMTP_RETRYING"
StatusCompleted = "COMPLETED" StatusCompleted = "COMPLETED"
StatusFailed = "FAILED" StatusFailed = "FAILED"
) )
// Task represents a single email processing unit tracked through the pipeline. // Task represents a single email processing unit tracked through the pipeline.
type Task struct { type Task struct {
ID uint `gorm:"primaryKey;autoIncrement"` ID uint `gorm:"primaryKey;autoIncrement"`
TaskUUID string `gorm:"uniqueIndex;not null"` TaskUUID string `gorm:"uniqueIndex;not null"`
ThreadID string `gorm:"index"` ThreadID string `gorm:"index"`
MessageID string `gorm:"index"` MessageID string `gorm:"index"`
Sender string Sender string
Subject string Subject string
BodyPlain string BodyPlain string
AIResponse string AIResponse string
Status string `gorm:"index;not null"` Status string `gorm:"index;not null"`
AttemptOpenClaw int `gorm:"default:0"` AttemptOpenClaw int `gorm:"default:0"`
AttemptSMTP int `gorm:"default:0"` AttemptSMTP int `gorm:"default:0"`
LastError *string LastError *string
NextRetryAt *time.Time NextRetryAt *time.Time
CreatedAt time.Time CreatedAt time.Time
+1 -1
View File
@@ -17,10 +17,10 @@ import (
"github.com/emersion/go-imap/v2/imapclient" "github.com/emersion/go-imap/v2/imapclient"
"github.com/google/uuid" "github.com/google/uuid"
"golang.org/x/net/proxy" "golang.org/x/net/proxy"
"gorm.io/gorm"
"thuanle.me/claw-email-bridge/internal/config" "thuanle.me/claw-email-bridge/internal/config"
"thuanle.me/claw-email-bridge/internal/database" "thuanle.me/claw-email-bridge/internal/database"
"thuanle.me/claw-email-bridge/internal/logging" "thuanle.me/claw-email-bridge/internal/logging"
"gorm.io/gorm"
) )
// IMAPWatcher monitors an IMAP mailbox via IDLE and processes new emails. // IMAPWatcher monitors an IMAP mailbox via IDLE and processes new emails.
+1 -1
View File
@@ -6,10 +6,10 @@ import (
"strings" "strings"
"time" "time"
"gorm.io/gorm"
"thuanle.me/claw-email-bridge/internal/config" "thuanle.me/claw-email-bridge/internal/config"
"thuanle.me/claw-email-bridge/internal/database" "thuanle.me/claw-email-bridge/internal/database"
"thuanle.me/claw-email-bridge/internal/logging" "thuanle.me/claw-email-bridge/internal/logging"
"gorm.io/gorm"
) )
// Retry backoff schedule: 1s, 5s, 15s. // Retry backoff schedule: 1s, 5s, 15s.