Skip to content

Commit 2edd10e

Browse files
committed
feat: add release workflow and enhance bot command handlers
1 parent c815b81 commit 2edd10e

File tree

5 files changed

+654
-65
lines changed

5 files changed

+654
-65
lines changed

.github/workflows/release.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build-and-release:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Set up Docker Buildx
20+
uses: docker/setup-buildx-action@v3
21+
22+
- name: Build Docker image and extract binary
23+
run: |
24+
docker build --platform linux/amd64 -t ash .
25+
docker run --rm -v $(pwd):/host ash cp /usr/local/bin/ash /host/ash-linux-amd64
26+
27+
- name: Create release
28+
run: |
29+
TAG_NAME=${GITHUB_REF#refs/tags/}
30+
gh release create "$TAG_NAME" ash-linux-amd64 --generate-notes
31+
env:
32+
GH_TOKEN: ${{ github.token }}

ash.go

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"os/signal"
1616
"path/filepath"
1717
"regexp"
18+
"sort"
1819
"strings"
1920
"sync"
2021
"syscall"
@@ -95,6 +96,7 @@ type Config struct {
9596
LinkstashURL string `json:"LINKSTASH_URL,omitempty"`
9697
SyncTimeoutMS int `json:"SYNC_TIMEOUT_MS"`
9798
Debug bool `json:"DEBUG"`
99+
DryRun bool `json:"DRY_RUN"`
98100
DeviceName string `json:"MATRIX_DEVICE_NAME"`
99101
OptOutTag string `json:"OPT_OUT_TAG"`
100102
}
@@ -114,6 +116,21 @@ func LoadConfig() (*Config, error) {
114116
return &cfg, nil
115117
}
116118

119+
// generateHelpMessage creates a help message listing available commands
120+
func generateHelpMessage(botCfg *BotConfig, allowedCommands []string) string {
121+
var cmds []string
122+
if len(allowedCommands) > 0 {
123+
cmds = make([]string, len(allowedCommands))
124+
copy(cmds, allowedCommands)
125+
} else {
126+
for cmd := range botCfg.Commands {
127+
cmds = append(cmds, cmd)
128+
}
129+
}
130+
sort.Strings(cmds)
131+
return "Available commands: " + strings.Join(cmds, ", ")
132+
}
133+
117134
func OpenMeta(ctx context.Context, path string) (*sql.DB, error) {
118135
return openWithSchema(ctx, path, "db/schema_meta.sql")
119136
}
@@ -433,32 +450,6 @@ func resolveURL(url string) string {
433450
return resp.Request.URL.String()
434451
}
435452

436-
// fetchRandomJoke fetches a random dad joke from icanhazdadjoke.com
437-
func fetchRandomJoke(ctx context.Context) (string, error) {
438-
req, err := http.NewRequestWithContext(ctx, "GET", "https://icanhazdadjoke.com/", nil)
439-
if err != nil {
440-
return "", err
441-
}
442-
req.Header.Set("Accept", "application/json")
443-
req.Header.Set("User-Agent", "ash-bot (https://github.com/polarhive/ash)")
444-
client := &http.Client{Timeout: 5 * time.Second}
445-
resp, err := client.Do(req)
446-
if err != nil {
447-
return "", err
448-
}
449-
defer resp.Body.Close()
450-
if resp.StatusCode != http.StatusOK {
451-
return "", fmt.Errorf("unexpected status: %d", resp.StatusCode)
452-
}
453-
var payload struct {
454-
Joke string `json:"joke"`
455-
}
456-
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
457-
return "", err
458-
}
459-
return payload.Joke, nil
460-
}
461-
462453
type LinkRow struct {
463454
MessageID string `json:"message_id"`
464455
URL string `json:"url"`
@@ -670,6 +661,10 @@ func run(ctx context.Context, metaDB *sql.DB, messagesDB *sql.DB, cfg *Config) e
670661
return
671662
}
672663
log.Info().Str("sender", string(ev.Sender)).Str("room", currentRoom.Comment).Msg(truncate(msgData.Msg.Body, 100))
664+
if cfg.DryRun {
665+
log.Info().Msg("dry run mode: skipping bot commands and hooks")
666+
return
667+
}
673668
if cfg.BotReplyLabel != "" && strings.Contains(msgData.Msg.Body, cfg.BotReplyLabel) {
674669
log.Debug().Str("label", cfg.BotReplyLabel).Msg("skipped bot processing due to bot reply label")
675670
return
@@ -692,38 +687,21 @@ func run(ctx context.Context, metaDB *sql.DB, messagesDB *sql.DB, cfg *Config) e
692687
body = "command not allowed in this room"
693688
} else {
694689
if botCfg != nil {
695-
if cmdCfg, ok := botCfg.Commands[cmd]; ok {
696-
resp, err := FetchBotCommand(evCtx, &cmdCfg, cfg.LinkstashURL)
690+
if cmd == "help" {
691+
body = generateHelpMessage(botCfg, currentRoom.AllowedCommands)
692+
} else if cmdCfg, ok := botCfg.Commands[cmd]; ok {
693+
resp, err := FetchBotCommand(evCtx, &cmdCfg, cfg.LinkstashURL, ev, client)
697694
if err != nil {
698-
log.Error().Err(err).Str("cmd", cmd).Msg("failed to fetch bot command")
699-
body = fmt.Sprintf("sorry, couldn't fetch %s right now", cmd)
695+
log.Error().Err(err).Str("cmd", cmd).Msg("failed to execute bot command")
696+
body = fmt.Sprintf("sorry, couldn't execute %s right now", cmd)
700697
} else {
701698
body = resp
702699
}
703-
} else if cmd == "joke" {
704-
joke, err := fetchRandomJoke(evCtx)
705-
if err != nil {
706-
log.Error().Err(err).Msg("failed to fetch joke")
707-
body = "sorry, couldn't fetch a joke right now"
708-
} else {
709-
body = joke
710-
}
711700
} else {
712-
body = "unknown command"
701+
body = "Unknown command. " + generateHelpMessage(botCfg, currentRoom.AllowedCommands)
713702
}
714703
} else {
715-
// No bot config loaded; fall back to built-in joke
716-
if cmd == "joke" {
717-
joke, err := fetchRandomJoke(evCtx)
718-
if err != nil {
719-
log.Error().Err(err).Msg("failed to fetch joke")
720-
body = "sorry, couldn't fetch a joke right now"
721-
} else {
722-
body = joke
723-
}
724-
} else {
725-
body = "unknown command"
726-
}
704+
body = "no bot configuration loaded"
727705
}
728706
}
729707
label := "> "

0 commit comments

Comments
 (0)