feat/200acbbe17dab7c1 #1

Merged
kamelion merged 2 commits from feat/200acbbe17dab7c1 into main 2026-08-17 16:05:54 +05:00
3 changed files with 60 additions and 19 deletions

View File

@@ -52,7 +52,9 @@ func main() {
}
}
log.Print("ratatoskr: запущен")
// Строка с номером версии при старте: семантическая версия (app.Version)
// + build-идентификатор (main.version, вшитый ldflag'ом) для диагностики.
log.Printf("ratatoskr: запущен (version %s, build %s)", app.Version, version)
if err := a.Run(context.Background()); err != nil {
log.Fatalf("app run: %v", err)
}

View File

@@ -30,6 +30,27 @@ import (
// создателем токена read:package (kamelion). Не требует конфигурации.
const packageOwner = "kamelion"
// Version — семантический номер версии приложения в формате major.minor.patch
// (например "0.1.0"). Меняется вручную при выпуске новых изменений; НЕ должен
// вшиваться ldflag'ом или генерироваться автоматически.
//
// Правила ручного инкремента (когда и какую часть номера увеличивать):
// - patch (0.1.0 → 0.1.1): исправление багов и мелкие правки, новая
// функциональность не добавляется (обратно-совместимые изменения).
// - minor (0.1.0 → 0.2.0): появляется новая (обратно-совместимая)
// функциональность; patch при этом сбрасывается в 0.
// - major (0.1.0 → 1.0.0): несовместимые изменения API/поведения или крупные
// релизы; minor и patch сбрасываются в 0.
//
// Пока продукт не стабилен, major держим на 0 → версии идут 0.x.y
// (минорные правки с повышением minor, исправления — с повышением patch).
//
// ВАЖНО: это СЕМАНТИЧЕСКАЯ версия приложения (для людей и диагностики), её
// не следует путать с build-идентификатором `main.version` (commit-<sha7>),
// который вшивается ldflag'ом и используется автообновлением. Здесь номер
// поднимается вручную перед каждым релизом/публикацией новой сборки.
const Version = "0.1.0"
// App — собранный конвейер.
type App struct {
Config *config.Config
@@ -391,8 +412,9 @@ func (a *App) handleBinaryCommand(ctx context.Context, uid chat.UserID, text str
}
}
// helpText текст команды /help.
const helpText = "⚡ **Ratatoskr** — помогу продумать задачу и запущу агента.\n\n" +
// helpTextFor — полный текст команды /help с номером версии приложения.
func helpTextFor(version string) string {
return "⚡ **Ratatoskr** — помогу продумать задачу и запущу агента.\n\n" +
"**Команды:**\n" +
"`/start` — новая задача\n" +
"`/cancel` — отменить текущую\n" +
@@ -403,11 +425,13 @@ const helpText = "⚡ **Ratatoskr** — помогу продумать зада
"`/status` — статус бинаря и обновления\n" +
"`/update` — применить обновление\n" +
"`/help` — эта справка\n\n" +
"Версия: " + version + "\n\n" +
"Просто опишите задачу — я помогу её продумать."
}
// handleHelpCmd отвечает списком команд.
// handleHelpCmd отвечает списком команд и номером версии приложения.
func (a *App) handleHelpCmd(ctx context.Context, uid chat.UserID) {
a.send(ctx, uid, helpText)
a.send(ctx, uid, helpTextFor(Version))
}
// handleStatusCmd отвечает текущей версией и результатом последней проверки.

View File

@@ -4,6 +4,7 @@ import (
"context"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
)
@@ -216,17 +217,31 @@ func TestHelp_IsBinaryCommand(t *testing.T) {
}
}
// TestHelpText_ContainsCommands проверяет, что справка упоминает все команды.
// TestHelpText_ContainsCommands проверяет, что справка упоминает все команды
// и номер версии приложения.
func TestHelpText_ContainsCommands(t *testing.T) {
text := helpTextFor(Version)
for _, cmd := range []string{
"/start", "/cancel", "/skip", "/retry", "/status", "/continue",
"/update", "/help",
} {
if !strings.Contains(helpText, cmd) {
if !strings.Contains(text, cmd) {
t.Errorf("helpText не упоминает команду %s", cmd)
}
}
if !strings.Contains(helpText, "Ratatoskr") {
if !strings.Contains(text, "Ratatoskr") {
t.Errorf("helpText не содержит имени бота")
}
if !strings.Contains(text, Version) {
t.Errorf("helpText не содержит номера версии приложения %s", Version)
}
}
// TestVersion_Semver проверяет, что константа версии приложения объявлена
// в формате major.minor.patch (например 0.1.0).
func TestVersion_Semver(t *testing.T) {
re := regexp.MustCompile(`^\d+\.\d+\.\d+$`)
if !re.MatchString(Version) {
t.Errorf("Version = %q, ожидался формат major.minor.patch", Version)
}
}