mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-09-07 22:20:56 +00:00
fix(deploynotify): read commit SHA from Coolify SOURCE_COMMIT runtime env
Baking SOURCE_COMMIT as a Docker build arg never worked: Coolify exposes it as a runtime env var, not a build arg, so gitSHA was always empty and the owner DM was skipped. Read SOURCE_COMMIT from the container env at startup (falling back to the ldflags-baked gitSHA for local builds), forward it via the compose environment, and drop the dead build-arg baking.
This commit is contained in:
+3
-2
@@ -23,8 +23,9 @@ ADMIN_IDS=
|
||||
# Only the twentyq module needs this. Leave blank to disable that command.
|
||||
GEMINI_API_KEY=
|
||||
|
||||
# SOURCE_COMMIT is injected as a build arg by Coolify (it sets it automatically)
|
||||
# for the deploynotify owner DM. Leave unset for local `docker compose up` —
|
||||
# SOURCE_COMMIT is injected into the container at runtime by Coolify (a
|
||||
# predefined env var holding the commit SHA); read at startup for the
|
||||
# deploynotify owner DM. Leave unset for local `docker compose up` —
|
||||
# deploynotify just stays silent.
|
||||
# SOURCE_COMMIT=
|
||||
|
||||
|
||||
+4
-8
@@ -6,15 +6,11 @@ RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
# SOURCE_COMMIT is baked into the binary so internal/deploynotify can DM the
|
||||
# owner once per new version (parity with the Makefile build). Coolify exposes
|
||||
# the commit SHA as the SOURCE_COMMIT build arg automatically — no manual
|
||||
# wiring needed. For a manual build, pass it with
|
||||
# --build-arg SOURCE_COMMIT=$(git rev-parse --short HEAD)
|
||||
# When unset, deploynotify treats the empty SHA as "stay silent".
|
||||
ARG SOURCE_COMMIT=""
|
||||
# The deploy-notify commit SHA comes from the SOURCE_COMMIT runtime env that
|
||||
# Coolify injects into the container (see docker-compose.yml), not from a build
|
||||
# arg — Coolify does not pass build args here. The binary is built plain.
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags="-s -w -X main.gitSHA=${SOURCE_COMMIT}" \
|
||||
-ldflags="-s -w" \
|
||||
-o /out/server \
|
||||
./cmd/server
|
||||
|
||||
|
||||
+17
-4
@@ -36,11 +36,22 @@ import (
|
||||
"github.com/tiennm99/miti99bot/internal/telegram"
|
||||
)
|
||||
|
||||
// gitSHA is populated at build time via `-ldflags "-X main.gitSHA=<sha>"`
|
||||
// (see Makefile). Empty value means the binary was built without that flag —
|
||||
// deploynotify treats it as a signal to stay silent.
|
||||
// gitSHA is the local-build fallback, populated via `-ldflags "-X
|
||||
// main.gitSHA=<sha>"` (see Makefile). On Coolify the commit comes from the
|
||||
// SOURCE_COMMIT runtime env instead (resolveCommitSHA prefers it). Empty from
|
||||
// both sources means deploynotify stays silent.
|
||||
var gitSHA string
|
||||
|
||||
// resolveCommitSHA returns the commit identifier for the deploy notification.
|
||||
// Coolify injects SOURCE_COMMIT into the container environment at runtime, so
|
||||
// prefer it; fall back to the ldflags-baked gitSHA for local builds.
|
||||
func resolveCommitSHA(envSourceCommit string) string {
|
||||
if s := strings.TrimSpace(envSourceCommit); s != "" {
|
||||
return s
|
||||
}
|
||||
return gitSHA
|
||||
}
|
||||
|
||||
// factories is the static module catalog. Adding a new module is a one-line
|
||||
// change here. Lives in main rather than the modules package to avoid an
|
||||
// import cycle (modules → util → modules).
|
||||
@@ -157,7 +168,7 @@ func main() {
|
||||
Bot: b,
|
||||
Store: deploynotify.NewStore(provider.Collection("deploynotify")),
|
||||
OwnerID: cfg.BotOwnerID,
|
||||
GitSHA: gitSHA,
|
||||
GitSHA: resolveCommitSHA(cfg.SourceCommit),
|
||||
})
|
||||
|
||||
handler := server.New()
|
||||
@@ -260,6 +271,7 @@ func buildProvider(ctx context.Context, cfg config) (storage.Provider, func(), e
|
||||
type config struct {
|
||||
Port string
|
||||
TelegramBotToken string
|
||||
SourceCommit string // Coolify-injected commit SHA (runtime env) for deploynotify
|
||||
GeminiAPIKey string
|
||||
GoldPriceAPIURL string
|
||||
GoldFXAPIURL string
|
||||
@@ -299,6 +311,7 @@ func loadConfig() config {
|
||||
return config{
|
||||
Port: port,
|
||||
TelegramBotToken: envMap["TELEGRAM_BOT_TOKEN"],
|
||||
SourceCommit: envMap["SOURCE_COMMIT"],
|
||||
GeminiAPIKey: envMap["GEMINI_API_KEY"],
|
||||
GoldPriceAPIURL: envMap["GOLD_PRICE_API_URL"],
|
||||
GoldFXAPIURL: envMap["GOLD_FX_API_URL"],
|
||||
|
||||
@@ -7,6 +7,28 @@ import (
|
||||
"github.com/tiennm99/miti99bot/internal/storage"
|
||||
)
|
||||
|
||||
func TestResolveCommitSHA(t *testing.T) {
|
||||
prev := gitSHA
|
||||
defer func() { gitSHA = prev }()
|
||||
|
||||
// Coolify runtime env wins over the baked fallback.
|
||||
gitSHA = "baked"
|
||||
if got := resolveCommitSHA(" runtime-sha "); got != "runtime-sha" {
|
||||
t.Errorf("env present: got %q, want trimmed runtime-sha", got)
|
||||
}
|
||||
|
||||
// Empty env falls back to the ldflags-baked value.
|
||||
if got := resolveCommitSHA(""); got != "baked" {
|
||||
t.Errorf("env empty: got %q, want baked fallback", got)
|
||||
}
|
||||
|
||||
// Neither source set → empty (deploynotify stays silent).
|
||||
gitSHA = ""
|
||||
if got := resolveCommitSHA(" "); got != "" {
|
||||
t.Errorf("both empty: got %q, want empty", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFactoriesIncludesGoldAndCoin(t *testing.T) {
|
||||
catalog := factories()
|
||||
if catalog["gold"] == nil {
|
||||
|
||||
+4
-4
@@ -2,10 +2,6 @@ services:
|
||||
bot:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
# Coolify sets SOURCE_COMMIT automatically; passed so deploynotify DMs
|
||||
# the owner on each new version. Optional — empty SHA just stays silent.
|
||||
SOURCE_COMMIT: ${SOURCE_COMMIT:-}
|
||||
# Or pin a prebuilt image instead of building:
|
||||
# image: ghcr.io/tiennm99/miti99bot:latest
|
||||
restart: unless-stopped
|
||||
@@ -20,6 +16,10 @@ services:
|
||||
ADMIN_IDS: ${ADMIN_IDS} # CSV of admin Telegram user ids
|
||||
# --- Optional ---
|
||||
GEMINI_API_KEY: ${GEMINI_API_KEY} # only the twentyq module needs it
|
||||
# Coolify injects SOURCE_COMMIT (commit SHA) at deploy time; passed to the
|
||||
# container so deploynotify DMs the owner once per new version. Empty (e.g.
|
||||
# local `docker compose up` without it) just stays silent.
|
||||
SOURCE_COMMIT: ${SOURCE_COMMIT:-}
|
||||
# Storage auto-selects mongodb because MONGO_URL is set — no KV_PROVIDER.
|
||||
# The in-process cron scheduler runs by default — no CRON_MODE.
|
||||
# PORT defaults to 8080 (internal health server) — omit unless overriding.
|
||||
|
||||
@@ -88,10 +88,11 @@ SSM/AWS lookup that fails with no AWS creds and bricks startup), `KV_PROVIDER`,
|
||||
bot token; a second poller gets HTTP 409, and a second in-process scheduler
|
||||
double-fires crons. Prefer **stop-first redeploys** so two containers never
|
||||
overlap near a cron time.
|
||||
5. **Build arg for deploynotify:** Coolify sets `SOURCE_COMMIT` automatically
|
||||
and the compose build forwards it, so the owner gets the "new version" DM
|
||||
with no manual wiring. Without it, `deploynotify` stays silent (no crash) —
|
||||
but you lose that notification.
|
||||
5. **deploynotify commit SHA:** Coolify injects `SOURCE_COMMIT` (a predefined
|
||||
runtime env var) into the container, and the compose `environment` forwards
|
||||
it, so the bot reads it at startup and DMs the owner the "new version"
|
||||
notice — no manual wiring. Without it, `deploynotify` stays silent (no
|
||||
crash) — but you lose that notification.
|
||||
6. **Health check:** use Coolify's HTTP monitor against `GET /` (returns
|
||||
`text/plain` `miti99bot ok`). Do **not** use a compose `healthcheck` — the
|
||||
distroless image has no shell/curl and `cmd/server` has no `-healthcheck`
|
||||
|
||||
Reference in New Issue
Block a user