chore(build,ci,docs): switch to Makefile, consolidate CI, add caching + AGENTS (#47)

This commit is contained in:
Ruidy 2025-08-30 22:36:11 -04:00 committed by GitHub
parent 9c5123968a
commit fc0daf6a14
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 199 additions and 91 deletions

View file

@ -6,41 +6,62 @@ on:
- main
pull_request:
branches:
- main
- "**"
jobs:
build:
checks:
runs-on: ubuntu-latest
env:
GO111MODULE: on
NAME: rentease
PORT: 8000
DB_USER: ci
DB_NAME: villafleurie
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Checkout
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build dev image (cached)
uses: docker/build-push-action@v6
with:
go-version: 1.23
context: .
file: Dockerfile.dev
tags: ${{ env.NAME }}:dev
load: true
cache-from: type=gha,scope=dev
cache-to: type=gha,scope=dev,mode=max
- name: Install dependencies
- name: Start dev container (background)
run: |
go mod download
docker run -d \
--name ${NAME} \
-v "$GITHUB_WORKSPACE":/app \
-v /app/tmp \
${NAME}:dev sleep infinity
- name: Lint code
- name: Make format
run: make format
- name: Make lint
run: make lint
- name: Make test
run: make test
- name: Stop container
if: always()
run: |
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
golangci-lint run
docker logs ${NAME} || true
docker stop ${NAME} || true
- name: Run tests
run: |
go test ./...
# - name: Run Gosec Security Scanner
# uses: securego/gosec@master
# with:
# args: ./...
- name: Build Docker image
run: |
docker build -t rentease .
- name: Build production image (cached, push only)
if: github.event_name == 'push'
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
tags: ${{ env.NAME }}:latest
cache-from: type=gha,scope=prod
cache-to: type=gha,scope=prod,mode=max

52
AGENTS.md Normal file
View file

@ -0,0 +1,52 @@
# Repository Guidelines
## Project Structure & Module Organization
- `main.go`: Application entrypoint (HTTP server on `:8000`).
- `internal/`: Private app code (e.g., `server/`, `service/`, `repository/`, `driver/`,
`config/`, `view/`). Templ views live in `internal/view` and generate `*_templ.go`.
- `pkg/`: Reusable packages shared across app layers.
- `cmd/`: Optional binaries/entrypoints.
- `assets/`: Static assets and images.
- `docs/`: Project documentation.
- `scripts/`, `tmp/`: Dev tooling and build artifacts (Air uses `tmp/`).
## Build, Test, and Development Commands
- `make dev`: Start dev container with live reload (Air) on `http://localhost:8000`.
- `make run`: Build and run the Docker image with `PORT` and `DATABASE_URL`.
- `make test`: Run `go test ./...` inside the running dev container.
- `make format`: Run `templ generate`, `templ fmt`, and `go fmt`.
- `make lint`: Run `golangci-lint`.
- Local alternative: `air -c .air.toml`, `go test ./...`, `go run .`.
## Coding Style & Naming Conventions
- Go formatting: Use `go fmt` (tabs, standard import ordering). CI helpers:
`make format`.
- Linting: `golangci-lint run ./...` via `make lint` (fix issues before PR).
- Packages: lowercase, no underscores; files: lowercase with underscores; exported
identifiers: `PascalCase`; unexported: `camelCase`.
- Templ: keep `.templ` in `internal/view`; commit sources, not generated `*_templ.go`.
## Testing Guidelines
- Framework: standard `testing` with table-driven tests.
- Files: `*_test.go`; functions: `TestXxx`, benchmarks: `BenchmarkXxx`.
- Run: `make test` (in container) or `go test ./...` locally.
- Aim for meaningful coverage on new/changed code; include error paths.
## Commit & Pull Request Guidelines
- Messages: Prefer Conventional Commits (e.g., `feat(parser): ...`,
`fix(config): ...`). Short, imperative first line; scope optional.
- PRs: Provide clear description, link issues (e.g., `#45`), include screenshots
for UI, and note breaking changes/migrations.
- Keep diffs focused; run `make format` and `make lint` before opening.
## Security & Configuration Tips
- Environment: Use `.env`/`prod.env`; never commit secrets.
Example: `DATABASE_URL="host=... user=... database=..."`.
- Ports: default `8000`; configure via `PORT`.
- Dependencies: use `go mod tidy` and `make up-deps` when updating.

View file

@ -2,19 +2,24 @@
FROM golang:1.24-alpine AS builder
WORKDIR /app
RUN apk update && apk add --no-cache build-base
RUN apk add --no-cache build-base
# Install tooling early so it stays cached across source changes
RUN go install github.com/air-verse/air@latest \
&& go install github.com/a-h/templ/cmd/templ@latest
# Leverage module cache
COPY go.mod go.sum ./
RUN go mod download
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download
# Copy the rest of the sources
COPY . .
RUN go build -ldflags="-s -w" -o rentease main.go
# Install air and templ for live reload and templating in dev
RUN go install github.com/air-verse/air@latest \
&& go install github.com/a-h/templ/cmd/templ@latest \
&& rm -rf /go/pkg/mod /root/.cache/go-build
# Build once (helps verify builds and speeds CI with cache)
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
go build -ldflags="-s -w" -o rentease main.go
# ----------- Dev Stage -----------
FROM golang:1.24-alpine AS dev

43
Makefile Normal file
View file

@ -0,0 +1,43 @@
# Defaults (override via `make VAR=value`)
NAME ?= rentease
PORT ?= 8000
DB_USER ?= ruidy
DB_NAME ?= villafleurie
DOCKER_RUN_ENV = -e DATABASE_URL="host=docker.for.mac.host.internal user=$(DB_USER) database=$(DB_NAME)" -e PORT=$(PORT)
.PHONY: help build run dev test up-deps format lint stop
help: ## List available commands
@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " %-12s %s\n", $$1, $$2}'
build: format lint ## Build the production Docker image
docker build -t $(NAME):latest .
run: build ## Run the production container (port $(PORT))
docker run -p $(PORT):$(PORT) $(DOCKER_RUN_ENV) $(NAME)
dev: ## Build and run the dev container with live reload (Air)
docker build -t $(NAME):dev -f Dockerfile.dev .
docker run -p $(PORT):$(PORT) --rm \
-v `pwd`:/app -v /app/tmp \
--name $(NAME) \
$(DOCKER_RUN_ENV) $(NAME):dev
test: ## Run Go tests inside the running dev container
docker exec $(NAME) go test ./...
up-deps: ## Update Go dependencies on host
go get -u ./...
format: ## Generate templ files and format code (dev container must be running)
docker exec $(NAME) templ generate internal/view
docker exec $(NAME) templ fmt .
docker exec $(NAME) go fmt ./...
lint: ## Lint the code using golangci-lint (dev container must be running)
docker exec $(NAME) golangci-lint run ./...
stop: ## Stop the dev container
-@docker stop $(NAME) >/dev/null 2>&1 || true

View file

@ -79,6 +79,17 @@ use a cloud alternative such as Railway, fly.io, _etc._
make dev
```
### Development Commands
Use the included Makefile for common tasks:
- `make dev`: Run the dev container with live reload (Air) on `http://localhost:8000`.
- `make run`: Build and run the production image locally.
- `make test`: Run `go test ./...` inside the dev container.
- `make format`: Generate templ files and format code.
- `make lint`: Lint with `golangci-lint`.
- `make stop`: Stop the dev container.
6. **Access the application**:
Open your browser and go to `http://localhost:8000` to start using Rentease.

22
go.mod
View file

@ -3,9 +3,9 @@ module github.com/rjNemo/rentease
go 1.24.2
require (
github.com/a-h/templ v0.3.906
github.com/getsentry/sentry-go v0.34.0
github.com/getsentry/sentry-go/echo v0.34.0
github.com/a-h/templ v0.3.943
github.com/getsentry/sentry-go v0.35.1
github.com/getsentry/sentry-go/echo v0.35.1
github.com/gorilla/sessions v1.4.0
github.com/joho/godotenv v1.5.1
github.com/labstack/echo-contrib v0.17.4
@ -13,7 +13,7 @@ require (
github.com/labstack/gommon v0.4.2
github.com/rjNemo/underscore v0.7.0
gorm.io/driver/postgres v1.6.0
gorm.io/gorm v1.30.0
gorm.io/gorm v1.30.2
)
require (
@ -35,15 +35,15 @@ require (
github.com/jinzhu/now v1.1.5 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/openai/openai-go v1.8.1
github.com/openai/openai-go v1.12.0
github.com/sethvargo/go-envconfig v1.3.0
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/crypto v0.41.0 // indirect
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.12.0 // indirect
)

22
go.sum
View file

@ -2,13 +2,19 @@ github.com/a-h/templ v0.3.898 h1:g9oxL/dmM6tvwRe2egJS8hBDQTncokbMoOFk1oJMX7s=
github.com/a-h/templ v0.3.898/go.mod h1:oLBbZVQ6//Q6zpvSMPTuBK0F3qOtBdFBcGRspcT+VNQ=
github.com/a-h/templ v0.3.906 h1:ZUThc8Q9n04UATaCwaG60pB1AqbulLmYEAMnWV63svg=
github.com/a-h/templ v0.3.906/go.mod h1:FFAu4dI//ESmEN7PQkJ7E7QfnSEMdcnu7QrAY8Dn334=
github.com/a-h/templ v0.3.943 h1:o+mT/4yqhZ33F3ootBiHwaY4HM5EVaOJfIshvd5UNTY=
github.com/a-h/templ v0.3.943/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/getsentry/sentry-go v0.34.0 h1:1FCHBVp8TfSc8L10zqSwXUZNiOSF+10qw4czjarTiY4=
github.com/getsentry/sentry-go v0.34.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ=
github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/getsentry/sentry-go/echo v0.34.0 h1:qjEOup0MJ4qyNKEc/H1XUooIQndka0HOGDMFbLR3x8E=
github.com/getsentry/sentry-go/echo v0.34.0/go.mod h1:kCjZ3/HnI340yMESlyRRYoL/7stfCkuxakhFkrR2nxk=
github.com/getsentry/sentry-go/echo v0.35.1 h1:MIhSUyo7cpCdcw0/lIeAw5fukrDt3x9G7qbiyjbVllI=
github.com/getsentry/sentry-go/echo v0.35.1/go.mod h1:IjdEzgvwlP2/7A32tWk75UmSUsBqvKFdpkN6WhB1e6M=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
@ -49,6 +55,8 @@ github.com/openai/openai-go v1.6.0 h1:KGjDS5sDrO27vykzO50BYknuabzVxuFuwAB8Djrmex
github.com/openai/openai-go v1.6.0/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
github.com/openai/openai-go v1.8.1 h1:mGS5Y9dEeHvLnE3k9LF4vUV3pvYG2K/6MHI/fCr4Ou8=
github.com/openai/openai-go v1.8.1/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
github.com/openai/openai-go v1.12.0 h1:NBQCnXzqOTv5wsgNC36PrFEiskGfO5wccfCWDo9S1U0=
github.com/openai/openai-go v1.12.0/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -82,17 +90,29 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -103,3 +123,5 @@ gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
gorm.io/gorm v1.30.2 h1:f7bevlVoVe4Byu3pmbWPVHnPsLoWaMjEb7/clyr9Ivs=
gorm.io/gorm v1.30.2/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=

View file

@ -1,46 +0,0 @@
# Set default values
name := "rentease"
port := "8000"
db_user := "ruidy"
db_name := "villafleurie"
# List available recipes
default:
@just --list
# Build the binary
build: format lint
@docker build -t {{name}}:latest .
# Run the binary
run: build
@docker run -p {{port}}:{{port}} \
-e DATABASE_URL="host=docker.for.mac.host.internal user={{db_user}} database={{db_name}}" \
-e PORT={{port}} {{name}}
# Run the binary in dev mode
dev:
@docker build -t {{name}}:dev -f Dockerfile.dev .
@docker run -p {{port}}:{{port}} --rm \
-v `pwd`:/app -v /app/tmp \
--name {{name}} \
-e DATABASE_URL="host=docker.for.mac.host.internal user={{db_user}} database={{db_name}}" \
-e PORT={{port}} {{name}}:dev
# Run the tests
test:
@docker exec {{name}} go test ./...
# Update dependencies
up-deps:
@go get -u ./...
# Format the code
format:
@docker exec {{name}} templ generate internal/view
@docker exec {{name}} templ fmt .
@docker exec {{name}} go fmt ./...
# Lint the code
lint:
@docker exec {{name}} golangci-lint run ./...