1 Commits

Author SHA1 Message Date
clawbot
3b42620749 feat: split Dockerfile into dedicated lint stage
All checks were successful
check / check (push) Successful in 6s
Use pre-built golangci/golangci-lint:v2.1.6 image for fast lint feedback
instead of installing golangci-lint from source on every build.

- Lint stage: runs fmt-check and lint using pre-built image
- Build stage: runs tests and compiles binaries
- COPY --from=lint forces BuildKit to execute the lint stage
- All images pinned by sha256 digest
- Runtime stage unchanged
2026-03-02 00:03:04 -08:00
6 changed files with 15 additions and 17 deletions

View File

@@ -1,5 +1,5 @@
# Lint stage — fast feedback on formatting and lint issues # Lint stage — fast feedback on formatting and lint issues
# golangci/golangci-lint:v2.1.6, 2026-03-02 # golangci/golangci-lint:v2.1.6
FROM golangci/golangci-lint@sha256:568ee1c1c53493575fa9494e280e579ac9ca865787bafe4df3023ae59ecf299b AS lint FROM golangci/golangci-lint@sha256:568ee1c1c53493575fa9494e280e579ac9ca865787bafe4df3023ae59ecf299b AS lint
WORKDIR /src WORKDIR /src
COPY go.mod go.sum ./ COPY go.mod go.sum ./
@@ -8,13 +8,13 @@ COPY . .
RUN make fmt-check RUN make fmt-check
RUN make lint RUN make lint
# Build stage # Build stage — tests and compilation
# golang:1.24-alpine, 2026-02-26 # golang:1.24-alpine, 2026-02-26
FROM golang@sha256:8bee1901f1e530bfb4a7850aa7a479d17ae3a18beb6e09064ed54cfd245b7191 AS builder FROM golang@sha256:8bee1901f1e530bfb4a7850aa7a479d17ae3a18beb6e09064ed54cfd245b7191 AS builder
WORKDIR /src WORKDIR /src
RUN apk add --no-cache git build-base make RUN apk add --no-cache git build-base make
# Force BuildKit to run the lint stage before proceeding # Force BuildKit to run the lint stage by creating a stage dependency
COPY --from=lint /src/go.sum /dev/null COPY --from=lint /src/go.sum /dev/null
COPY go.mod go.sum ./ COPY go.mod go.sum ./
@@ -29,13 +29,10 @@ ARG VERSION=dev
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w -X main.Version=${VERSION}" -o /chatd ./cmd/chatd/ RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w -X main.Version=${VERSION}" -o /chatd ./cmd/chatd/
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /chat-cli ./cmd/chat-cli/ RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /chat-cli ./cmd/chat-cli/
# Runtime stage
# alpine:3.21, 2026-02-26 # alpine:3.21, 2026-02-26
FROM alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 FROM alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
RUN apk add --no-cache ca-certificates \ RUN apk add --no-cache ca-certificates \
&& addgroup -S chat && adduser -S chat -G chat \ && addgroup -S chat && adduser -S chat -G chat
&& mkdir -p /var/lib/neoirc \
&& chown chat:chat /var/lib/neoirc
COPY --from=builder /chatd /usr/local/bin/chatd COPY --from=builder /chatd /usr/local/bin/chatd
USER chat USER chat

View File

@@ -37,7 +37,7 @@ debug: build
DEBUG=1 GOTRACEBACK=all ./bin/$(BINARY) DEBUG=1 GOTRACEBACK=all ./bin/$(BINARY)
clean: clean:
rm -rf bin/ chatd rm -rf bin/ chatd data.db
docker: docker:
docker build -t chat . docker build -t chat .

View File

@@ -1645,7 +1645,7 @@ directory is also loaded automatically via
| Variable | Type | Default | Description | | Variable | Type | Default | Description |
|--------------------|---------|--------------------------------------|-------------| |--------------------|---------|--------------------------------------|-------------|
| `PORT` | int | `8080` | HTTP listen port | | `PORT` | int | `8080` | HTTP listen port |
| `DBURL` | string | `file:///var/lib/neoirc/state.db?_journal_mode=WAL` | SQLite connection string. For file-based: `file:///path/to/db.db?_journal_mode=WAL`. For in-memory (testing): `file::memory:?cache=shared`. | | `DBURL` | string | `file:./data.db?_journal_mode=WAL` | SQLite connection string. For file-based: `file:./path.db?_journal_mode=WAL`. For in-memory (testing): `file::memory:?cache=shared`. |
| `DEBUG` | bool | `false` | Enable debug logging (verbose request/response logging) | | `DEBUG` | bool | `false` | Enable debug logging (verbose request/response logging) |
| `MAX_HISTORY` | int | `10000` | Maximum messages retained per channel before rotation (planned) | | `MAX_HISTORY` | int | `10000` | Maximum messages retained per channel before rotation (planned) |
| `SESSION_IDLE_TIMEOUT` | string | `24h` | Session idle timeout as a Go duration string (e.g. `24h`, `30m`). Sessions with no activity for this long are expired and the nick is released. | | `SESSION_IDLE_TIMEOUT` | string | `24h` | Session idle timeout as a Go duration string (e.g. `24h`, `30m`). Sessions with no activity for this long are expired and the nick is released. |
@@ -1667,7 +1667,7 @@ PORT=8080
SERVER_NAME=My Chat Server SERVER_NAME=My Chat Server
MOTD=Welcome! Be excellent to each other. MOTD=Welcome! Be excellent to each other.
DEBUG=false DEBUG=false
DBURL=file:///var/lib/neoirc/state.db?_journal_mode=WAL DBURL=file:./data.db?_journal_mode=WAL
SESSION_IDLE_TIMEOUT=24h SESSION_IDLE_TIMEOUT=24h
``` ```
@@ -1685,7 +1685,8 @@ docker build -t chat .
# Run # Run
docker run -p 8080:8080 \ docker run -p 8080:8080 \
-v chat-data:/var/lib/neoirc \ -v chat-data:/data \
-e DBURL="file:/data/chat.db?_journal_mode=WAL" \
-e SERVER_NAME="My Server" \ -e SERVER_NAME="My Server" \
-e MOTD="Welcome!" \ -e MOTD="Welcome!" \
chat chat
@@ -1721,7 +1722,7 @@ make build
# Run # Run
./bin/chatd ./bin/chatd
# Listens on :8080, writes to /var/lib/neoirc/state.db # Listens on :8080, creates ./data.db
``` ```
### Reverse Proxy (Production) ### Reverse Proxy (Production)
@@ -1762,8 +1763,8 @@ seconds to accommodate long-poll connections.
string). This allows concurrent reads during writes. string). This allows concurrent reads during writes.
- **Single writer**: SQLite allows only one writer at a time. For high-traffic - **Single writer**: SQLite allows only one writer at a time. For high-traffic
servers, Postgres support is planned. servers, Postgres support is planned.
- **Backup**: The database is a single file. Back it up with `sqlite3 /var/lib/neoirc/state.db ".backup backup.db"` or just copy the file (safe with WAL mode). - **Backup**: The database is a single file. Back it up with `sqlite3 data.db ".backup backup.db"` or just copy the file (safe with WAL mode).
- **Location**: By default, `state.db` is created in `/var/lib/neoirc/`. - **Location**: By default, `data.db` is created in the working directory.
Use the `DBURL` env var to place it elsewhere. Use the `DBURL` env var to place it elsewhere.
--- ---

View File

@@ -15,7 +15,7 @@ import (
var ( var (
// Appname is the application name, set at build time. // Appname is the application name, set at build time.
Appname = "neoirc" //nolint:gochecknoglobals Appname = "chat" //nolint:gochecknoglobals
// Version is the application version, set at build time. // Version is the application version, set at build time.
Version string //nolint:gochecknoglobals Version string //nolint:gochecknoglobals

View File

@@ -56,7 +56,7 @@ func New(
viper.SetDefault("DEBUG", "false") viper.SetDefault("DEBUG", "false")
viper.SetDefault("MAINTENANCE_MODE", "false") viper.SetDefault("MAINTENANCE_MODE", "false")
viper.SetDefault("PORT", "8080") viper.SetDefault("PORT", "8080")
viper.SetDefault("DBURL", "file:///var/lib/neoirc/state.db?_journal_mode=WAL") viper.SetDefault("DBURL", "file:./data.db?_journal_mode=WAL")
viper.SetDefault("SENTRY_DSN", "") viper.SetDefault("SENTRY_DSN", "")
viper.SetDefault("METRICS_USERNAME", "") viper.SetDefault("METRICS_USERNAME", "")
viper.SetDefault("METRICS_PASSWORD", "") viper.SetDefault("METRICS_PASSWORD", "")

View File

@@ -87,7 +87,7 @@ func (database *Database) GetDB() *sql.DB {
func (database *Database) connect(ctx context.Context) error { func (database *Database) connect(ctx context.Context) error {
dbURL := database.params.Config.DBURL dbURL := database.params.Config.DBURL
if dbURL == "" { if dbURL == "" {
dbURL = "file:///var/lib/neoirc/state.db?_journal_mode=WAL&_busy_timeout=5000" dbURL = "file:./data.db?_journal_mode=WAL&_busy_timeout=5000"
} }
database.log.Info( database.log.Info(