From 5552258f2050e5482719efdfaf3d740118082a72 Mon Sep 17 00:00:00 2001 From: schreifuchs Date: Wed, 27 Aug 2025 21:29:52 +0200 Subject: [PATCH] chore(): docker-compose --- Dockerfile | 22 +++++++++++++++++ README.md | 38 +++++++++++++---------------- docker-compose.yml | 22 +++++++++++++++++ go.mod | 1 + go.sum | 2 ++ internal/api/httpinvoce/resource.go | 2 +- internal/config/config.go | 30 ++++++++++++++--------- internal/email/resource.go | 12 ++++----- main.go | 22 ----------------- 9 files changed, 89 insertions(+), 62 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml delete mode 100644 main.go diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ba89470 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM golang:1.24 as build + +WORKDIR /app + +# Copy module files and download dependencies +COPY go.mod go.sum ./ +RUN go mod download + +# Copy the rest of the application source and build +COPY . . +RUN CGO_ENABLED=0 GOOS=linux go build -o /invoiceapi cmd/invoiceapi/main.go + +EXPOSE 8080 + +FROM alpine:3 +# the test program: +COPY --from=build /invoiceapi /invoiceapi +# the tls certificates: +# NB: this pulls directly from the upstream image, which already has ca-certificates: + +CMD [ "/invoiceapi" ] + diff --git a/README.md b/README.md index eddf9e2..e4b67ea 100644 --- a/README.md +++ b/README.md @@ -2,28 +2,24 @@ docker run --rm -p 3030:3000 gotenberg/gotenberg:8 ## Configuration -This application is configured using a `config.json` file in the root of the project. You can use the `config.json.example` file as a starting point. +This application can be configured using a `config.json` file in the root of the project, or by using environment variables. Values set in environment variables will override the values from the `config.json` file. -```json -{ - "email": { - "smtp": { - "host": "smtp.example.com", - "port": 587, - "username": "user", - "password": "password" - }, - "from": "from@example.com" - }, - "pdf": { - "hostname": "http://localhost:3030" - }, - "gitea": { - "url": "https://gitea.example.com", - "token": "your-gitea-token" - } -} -``` +You can use the `config.example.json` file as a starting point for your `config.json`. + +### Environment Variables + +The following environment variables can be used for configuration: + +| Variable | Description | +| --------------------- | --------------------------------------------- | +| `PDF_HOSTNAME` | The hostname of the PDF generator (Gotenberg) | +| `GITEA_URL` | The URL of your Gitea instance | +| `GITEA_TOKEN` | Your Gitea API token | +| `EMAIL_FROM` | The "From" address for sending emails | +| `EMAIL_SMTP_HOST` | The SMTP server host | +| `EMAIL_SMTP_PORT` | The SMTP server port | +| `EMAIL_SMTP_USER` | The username for SMTP authentication | +| `EMAIL_SMTP_PASSWORD` | The password for SMTP authentication | ## API Endpoints diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..fd0fe94 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +services: + invoiceapi: + build: + context: . + dockerfile: Dockerfile + ports: + - "8080:8080" + depends_on: + - gotenberg + environment: + - PDF_HOSTNAME=http://gotenberg:3000 + volumes: + - ./config.json:/config.json + develop: + watch: + - action: rebuild + path: . + ignore: + - .git + gotenberg: + image: gotenberg/gotenberg:8 + restart: unless-stopped diff --git a/go.mod b/go.mod index 5755f58..38a47c7 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.24.5 require ( code.gitea.io/sdk/gitea v0.21.0 + github.com/caarlos0/env/v10 v10.0.0 github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a github.com/jedib0t/go-pretty/v6 v6.6.8 github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible diff --git a/go.sum b/go.sum index d254de0..3928b23 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4= code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA= github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs= github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM= +github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA= +github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= diff --git a/internal/api/httpinvoce/resource.go b/internal/api/httpinvoce/resource.go index 952de50..875b87a 100644 --- a/internal/api/httpinvoce/resource.go +++ b/internal/api/httpinvoce/resource.go @@ -22,7 +22,7 @@ func New(log *slog.Logger, invoice invoicer, mail mailer) *Service { } type invoicer interface { - Generate(creditor, deptor model.Entity, mindur time.Duration, rate float64, repos []invoice.Repo) (document io.ReadCloser, report report.Report, err error) + Generate(creditor, deptor model.Entity, mindur time.Duration, rate float64, repos []invoice.Repo) (document io.ReadCloser, report *report.Report, err error) } type mailer interface { diff --git a/internal/config/config.go b/internal/config/config.go index 18ae786..f0359f0 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,37 +5,43 @@ import ( "os" "git.schreifuchs.ch/lou-taylor/accounting/internal/email" + "github.com/caarlos0/env/v10" ) // PDF holds the configuration for the PDF generator. type PDF struct { - Hostname string `json:"hostname"` + Hostname string `json:"hostname" env:"HOSTNAME"` } // Gitea holds the configuration for the Gitea client. type Gitea struct { - URL string `json:"url"` - Token string `json:"token"` + URL string `json:"url" env:"URL"` + Token string `json:"token" env:"TOKEN"` } // Config holds the configuration for the entire application. type Config struct { - Email email.Config `json:"email"` - PDF PDF `json:"pdf"` - Gitea Gitea `json:"gitea"` + Email email.Config `json:"email" envPrefix:"EMAIL_"` + PDF PDF `json:"pdf" envPrefix:"PDF_"` + Gitea Gitea `json:"gitea" envPrefix:"GITEA_"` } -// Load loads the configuration from a JSON file. +// Load loads the configuration from a JSON file and environment variables. func Load(path string) (*Config, error) { + cfg := &Config{} + file, err := os.Open(path) - if err != nil { + if err == nil { + defer file.Close() + decoder := json.NewDecoder(file) + if err := decoder.Decode(cfg); err != nil { + return nil, err + } + } else if !os.IsNotExist(err) { return nil, err } - defer file.Close() - cfg := &Config{} - decoder := json.NewDecoder(file) - if err := decoder.Decode(cfg); err != nil { + if err := env.Parse(cfg); err != nil { return nil, err } diff --git a/internal/email/resource.go b/internal/email/resource.go index 87a5f27..fcacff9 100644 --- a/internal/email/resource.go +++ b/internal/email/resource.go @@ -8,15 +8,15 @@ import ( ) type Config struct { - SMTP SMTPConfig - From string + SMTP SMTPConfig `envPrefix:"SMTP_"` + From string `env:"FROM"` } type SMTPConfig struct { - Host string - Port string - User string - Password string + Host string `env:"HOST"` + Port string `env:"PORT"` + User string `env:"USER"` + Password string `env:"PASSWORD"` } type Service struct { diff --git a/main.go b/main.go deleted file mode 100644 index 69d6657..0000000 --- a/main.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "git.schreifuchs.ch/lou-taylor/accounting/internal/api" -) - -func main() { - // var cfg invoice.Config - // file, err := os.Open("config.json") - // if err != nil { - // panic(err) - // } - // defer file.Close() - // decoder := json.NewDecoder(file) - // err = decoder.Decode(&cfg) - // if err != nil { - // panic(err) - // } - // - // invoice.Generate(cfg) - api.Start(":8080") -}