From 8fcafcdffd7ad4f4e2f588d3b8664b919b579adf Mon Sep 17 00:00:00 2001 From: Hermes Date: Sun, 16 Aug 2026 12:33:17 +0500 Subject: [PATCH] =?UTF-8?q?feat(update):=20=D0=B2=D0=BB=D0=B0=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D1=86=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=B0=20?= =?UTF-8?q?=D0=B2=D1=88=D0=B8=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2?= =?UTF-8?q?=20=D0=B1=D0=B8=D0=BD=D0=B0=D1=80=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - -X main.updateOwner (из vars.TC_GITEA_OWNER / Make UPDATE_OWNER), фоллбэк на update.owner в конфиге. - update.owner больше не обязателен: гейты в startAutoCheck и handleUpdateCmd требуют только update.base_url. - Обновлены main, app.New (сигнатура), CI, Makefile, тесты. --- .gitea/workflows/ci.yaml | 2 +- Makefile | 3 ++- cmd/ratatoskr/main.go | 7 ++++++- internal/app/app.go | 19 +++++++++++++------ internal/app/app_test.go | 28 ++++++++++++++++++---------- 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 9c87e9e..b556ae1 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -58,7 +58,7 @@ jobs: fi VERSION="commit-$(echo '${{ gitea.sha }}' | cut -c1-7)" GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \ - go build -ldflags="-s -w -X main.version=${VERSION} -X main.updateToken=${{ secrets.TC_UPDATE_TOKEN }}" -o "${FILENAME}" ./cmd/ratatoskr/ + go build -ldflags="-s -w -X main.version=${VERSION} -X main.updateToken=${{ secrets.TC_UPDATE_TOKEN }} -X main.updateOwner=${{ vars.TC_GITEA_OWNER }}" -o "${FILENAME}" ./cmd/ratatoskr/ echo "FILENAME=${FILENAME}" >> "${GITEA_ENV}" echo "VERSION=${VERSION}" >> "${GITEA_ENV}" diff --git a/Makefile b/Makefile index 7fa6f99..70dbdbb 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,8 @@ GO ?= go GOPATH := $(shell $(GO) env GOPATH) GIT_SHA := $(shell git rev-parse --short HEAD 2>/dev/null || echo dev) UPDATE_TOKEN ?= "" -GOFLAGS ?= -ldflags="-s -w -X main.version=commit-$(GIT_SHA) -X main.updateToken=$(UPDATE_TOKEN)" +UPDATE_OWNER ?= "" +GOFLAGS ?= -ldflags="-s -w -X main.version=commit-$(GIT_SHA) -X main.updateToken=$(UPDATE_TOKEN) -X main.updateOwner=$(UPDATE_OWNER)" all: test build diff --git a/cmd/ratatoskr/main.go b/cmd/ratatoskr/main.go index 79e289b..815d2ed 100644 --- a/cmd/ratatoskr/main.go +++ b/cmd/ratatoskr/main.go @@ -24,6 +24,11 @@ var version = "dev" // Без ldflags — пустой; тогда используется update.token из конфига (если задан). var updateToken = "" +// updateOwner — владелец Gitea-пакета (обычно git-юзер), вшивается при сборке: +// go build -ldflags "-X main.updateOwner=kamelion" +// Без ldflags — пустой; тогда используется update.owner из конфига (если задан). +var updateOwner = "" + func main() { cfg := flag.String("config", "", "путь к config.yaml (по умолчанию — CWD/config.yaml)") versionFlag := flag.Bool("version", false, "показать версию и выйти") @@ -34,7 +39,7 @@ func main() { return } - a, err := app.New(*cfg, version, updateToken) + a, err := app.New(*cfg, version, updateToken, updateOwner) if err != nil { log.Fatalf("app init: %v", err) } diff --git a/internal/app/app.go b/internal/app/app.go index 52e5b86..2439825 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -41,7 +41,9 @@ type App struct { // version — вшитая версия бинаря (ldflag -X main.version). // updateToken — вшитый токен read:package для авто-обновления // (ldflag -X main.updateToken); имеет приоритет над update.token из конфига. -func New(configPath, version, updateToken string) (*App, error) { +// updateOwner — вшитый владелец Gitea-пакета (ldflag -X main.updateOwner); +// имеет приоритет над update.owner из конфига. +func New(configPath, version, updateToken, updateOwner string) (*App, error) { cfg, err := config.Load(configPath) if err != nil { return nil, fmt.Errorf("%w: %v", ErrConfig, err) @@ -122,9 +124,14 @@ func New(configPath, version, updateToken string) (*App, error) { if udToken == "" { udToken = cfg.Update.Token } + // Владелец пакета: вшитый updateOwner приоритетнее update.owner из конфига. + udOwner := updateOwner + if udOwner == "" { + udOwner = cfg.Update.Owner + } ud := &update.Updater{ BaseURL: cfg.Update.BaseURL, - Owner: cfg.Update.Owner, + Owner: udOwner, Package: cfg.Update.Package, Token: udToken, CurrentVersion: version, @@ -293,8 +300,8 @@ func (a *App) startAutoCheck(ctx context.Context) { if !a.Config.Update.Enabled { return } - if a.Updater == nil || a.Updater.BaseURL == "" || a.Updater.Owner == "" { - log.Print("app: update авто-проверка выключена (не заполнен git.base_url / update.owner)") + if a.Updater == nil || a.Updater.BaseURL == "" { + log.Print("app: update авто-проверка выключена (не заполнен update.base_url)") return } interval := a.Config.Update.CheckInterval.Duration() @@ -376,8 +383,8 @@ func (a *App) version() string { // handleUpdateCmd — команда /update: Check → Download → Verify → Swap/Restart. // При активной задаче в чате — требует подтверждения, чтобы не прерывать работу. func (a *App) handleUpdateCmd(ctx context.Context, uid chat.UserID) { - if a.Updater == nil || a.Updater.BaseURL == "" || a.Updater.Owner == "" { - a.send(ctx, uid, "Обновление не настроено (нужен update.base_url и update.owner в config).") + if a.Updater == nil || a.Updater.BaseURL == "" { + a.send(ctx, uid, "Обновление не настроено (нужен update.base_url в config).") return } if !a.Config.Update.Enabled { diff --git a/internal/app/app_test.go b/internal/app/app_test.go index d33ec49..c612309 100644 --- a/internal/app/app_test.go +++ b/internal/app/app_test.go @@ -20,7 +20,7 @@ func TestNew(t *testing.T) { t.Setenv("RATATOSKR_DB", dbPath) // Загружаем без config-файла (дефолты + env) - a, err := New("", "dev", "") + a, err := New("", "dev", "", "") if err != nil { t.Fatalf("New() err = %v", err) } @@ -50,7 +50,7 @@ func TestNew_MissingToken(t *testing.T) { t.Setenv("TG_CHAT_ID", "12345") t.Setenv("RATATOSKR_DB", dbPath) - _, err := New("", "dev", "") + _, err := New("", "dev", "", "") if err == nil { t.Fatal("expected error for missing token") } @@ -65,7 +65,7 @@ func TestNew_BadDB(t *testing.T) { t.Setenv("TG_CHAT_ID", "12345") t.Setenv("RATATOSKR_DB", dbPath) - _, err := New("", "dev", "") + _, err := New("", "dev", "", "") if err == nil { t.Fatal("expected error for invalid db path") } @@ -82,7 +82,7 @@ func TestNew_RunCtxCancel(t *testing.T) { t.Setenv("TG_CHAT_ID", "12345") t.Setenv("RATATOSKR_DB", dbPath) - a, err := New("", "dev", "") + a, err := New("", "dev", "", "") if err != nil { t.Fatalf("New() err = %v", err) } @@ -109,7 +109,8 @@ func TestMain(t *testing.T) { } // TestNew_UpdateWiring проверяет: 1) update.base_url берётся из update-блока -// (не git.base_url); 2) приоритет токена: вшитый updateToken > update.token. +// (не git.base_url); 2) приоритет токена: вшитый updateToken > update.token; +// 3) приоритет владельца: вшитый updateOwner > update.owner. func TestNew_UpdateWiring(t *testing.T) { tmp := t.TempDir() dbPath := filepath.Join(tmp, "test.db") @@ -126,7 +127,7 @@ func TestNew_UpdateWiring(t *testing.T) { " enabled: true", " base_url: \"https://hub.example.com\"", " token: \"cfg-update-token\"", - " owner: \"kamelion\"", + " owner: \"cfg-owner\"", "paths:", " db: \"" + dbPath + "\"", "", // пустая строка в конце @@ -136,7 +137,7 @@ func TestNew_UpdateWiring(t *testing.T) { } // 1) base_url из update-блока, а НЕ git - a, err := New(configPath, "dev", "") + a, err := New(configPath, "dev", "", "") if err != nil { t.Fatalf("New() err = %v", err) } @@ -146,17 +147,24 @@ func TestNew_UpdateWiring(t *testing.T) { if want := "https://hub.example.com"; a.Updater.BaseURL != want { t.Errorf("BaseURL = %q, want %q (должен быть update.base_url, не git.base_url)", a.Updater.BaseURL, want) } - // без вшитого токена берём update.token из конфига + // без вшитого токена и владельца берём их из конфига if a.Updater.Token != "cfg-update-token" { t.Errorf("Token = %q, want cfg-update-token (при пустом вшитом)", a.Updater.Token) } + if a.Updater.Owner != "cfg-owner" { + t.Errorf("Owner = %q, want cfg-owner (при пустом вшитом)", a.Updater.Owner) + } - // 2) вшитый updateToken перекрывает оба источника - a2, err := New(configPath, "dev", "embedded-update-token") + // 2) вшитый updateToken перекрывает конфиг + a2, err := New(configPath, "dev", "embedded-update-token", "embedded-owner") if err != nil { t.Fatalf("New() err = %v", err) } if a2.Updater.Token != "embedded-update-token" { t.Errorf("Token = %q, want embedded-update-token (вшитый приоритетнее)", a2.Updater.Token) } + // 3) вшитый updateOwner перекрывает конфиг + if a2.Updater.Owner != "embedded-owner" { + t.Errorf("Owner = %q, want embedded-owner (вшитый приоритетнее)", a2.Updater.Owner) + } } \ No newline at end of file