Clean up build tooling and Dockerfile
- Dockerfile cross-compiles Go for the target platform (amd64/arm64 without emulation), uses templ pinned in go.mod, runs as uid 1000 on alpine and lets FRONTEND_IMAGE pin the frontend version - justfile: tools via go tool, `test` (unit) and `test-integration` (uses the active docker context), no hardcoded paths, no tailwind or frontend recipes - Removed app.yaml, init.sh, tailwind.config.js and the tracked .idea folder
This commit is contained in:
1 parent
7b144ae419
commit
59dfff38bc
13 files changed
+58
-304
No files matched your search
+3
-9
@@ -14,18 +14,12 @@ compose.yaml
|
||||
*.pprof
|
||||
main
|
||||
conf.yaml
|
||||
output.css
|
||||
tailwindcss
|
||||
.env
|
||||
|
||||
# Node.js (frontend build artifacts)
|
||||
node_modules
|
||||
package.json
|
||||
package-lock.json
|
||||
|
||||
# Test files
|
||||
# Test files and fixtures
|
||||
*_test.go
|
||||
integration_test.go
|
||||
internal/testutil
|
||||
*_dump.sql
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
@@ -3,13 +3,8 @@ tmp
|
||||
.idea
|
||||
*templ.go
|
||||
conf.yaml
|
||||
output.css
|
||||
compose.yaml
|
||||
tailwindcss
|
||||
.env
|
||||
node_modules
|
||||
package.json
|
||||
package-lock.json
|
||||
cpu.pprof
|
||||
main
|
||||
|
||||
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
Generated
-16
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="Go" enabled="true">
|
||||
<buildTags>
|
||||
<option name="customFlags">
|
||||
<array>
|
||||
<option value="prod" />
|
||||
</array>
|
||||
</option>
|
||||
</buildTags>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
-5
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
Generated
-36
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="music_prod@192.168.86.100" uuid="e63caf71-2b1a-400d-9cc4-4b87b1f9b807">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://192.168.86.100:5432/music_prod</jdbc-url>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="music_test@192.168.86.100" uuid="d063e147-d7f0-48db-9f04-57a108261ef1">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://192.168.86.100:5432/music_test</jdbc-url>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="music_test@ssh.sanplex.xyz" uuid="a9cf3eb8-abc2-479b-9f27-12b4cbbfc321">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://ssh.sanplex.xyz:9432/music_test</jdbc-url>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="music_prod@ssh.sanplex.xyz" uuid="20917ace-4e9a-4273-bdb7-13ebc774cbba">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://ssh.sanplex.xyz:9432/music_prod</jdbc-url>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="music_test2@localhost" uuid="a423ab0a-55b0-42e1-8070-25d8ef34bfac">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://localhost:5432/music_test2</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/MusicServer.iml" filepath="$PROJECT_DIR$/.idea/MusicServer.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
+28
-25
@@ -1,36 +1,39 @@
|
||||
# Stage 1: Build backend
|
||||
FROM golang:1.25-alpine as build_go
|
||||
RUN apk add --no-cache curl
|
||||
# The frontend is built and published separately; override to pin a version.
|
||||
ARG FRONTEND_IMAGE=gitea.sanplex.xyz/sansan/musicfrontend:latest
|
||||
|
||||
# Stage 1: Build the backend on the build machine and cross-compile for the target platform,
|
||||
# so multi-platform builds need no emulation.
|
||||
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS build
|
||||
ARG TARGETOS TARGETARCH
|
||||
WORKDIR /app
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY cmd/ ./cmd/
|
||||
COPY internal/ ./internal/
|
||||
RUN find . -name "*_test.go" -delete && \
|
||||
find . -name "integration_test.go" -delete
|
||||
RUN go install github.com/a-h/templ/cmd/templ@latest
|
||||
RUN templ generate
|
||||
RUN go build -o main cmd/main.go
|
||||
RUN go tool templ generate
|
||||
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \
|
||||
go build -trimpath -ldflags="-s -w" -tags timetzdata -o main ./cmd
|
||||
|
||||
# Stage 2: Final image
|
||||
FROM golang:1.25-alpine
|
||||
# Stage 2: Frontend static files (the same for every platform)
|
||||
FROM --platform=$BUILDPLATFORM ${FRONTEND_IMAGE} AS frontend
|
||||
# Empty API_HOSTNAME makes the frontend use relative paths
|
||||
RUN echo "window.__RUNTIME_CONFIG__ = { API_HOSTNAME: '' };" > /usr/share/nginx/html/config.js
|
||||
|
||||
# Stage 3: Final image. No RUN steps here, so no emulation is needed for other architectures.
|
||||
FROM alpine:3.22
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/main .
|
||||
COPY --from=frontend /usr/share/nginx/html /frontend
|
||||
COPY ./songs/ ./songs/
|
||||
|
||||
# The music volume must be readable by uid 1000, and writable for the .id file cleanup during sync.
|
||||
USER 1000:1000
|
||||
EXPOSE 8080
|
||||
VOLUME /sorted
|
||||
VOLUME /characters
|
||||
|
||||
COPY --from=build_go /app/main .
|
||||
COPY --from=gitea.sanplex.xyz/sansan/musicfrontend:latest /usr/share/nginx/html /frontend
|
||||
# Generate config.js with empty API_HOSTNAME (relative paths)
|
||||
RUN echo "window.__RUNTIME_CONFIG__ = { API_HOSTNAME: '' };" > /frontend/config.js
|
||||
COPY ./songs/ ./songs/
|
||||
# Required: DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_NAME, MUSIC_PATH, CHARACTERS_PATH
|
||||
ENV PORT=8080
|
||||
|
||||
ENV PORT 8080
|
||||
ENV DB_HOST ""
|
||||
ENV DB_PORT ""
|
||||
ENV DB_USERNAME ""
|
||||
ENV DB_PASSWORD ""
|
||||
ENV DB_NAME ""
|
||||
ENV MUSIC_PATH ""
|
||||
ENV CHARACTERS_PATH ""
|
||||
|
||||
CMD ./main
|
||||
CMD ["./main"]
|
||||
@@ -1,8 +0,0 @@
|
||||
application: musicserver
|
||||
version: 2.2.0
|
||||
runtime: go115
|
||||
api_version: go1
|
||||
|
||||
handlers:
|
||||
- url: /.*
|
||||
script: _go_app
|
||||
@@ -1,17 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
#envsubst < ./frontend/src/arne.js
|
||||
|
||||
sed -i 's^$HOSTNAME^'"$HOSTNAME"'^g' ./frontend/src/arne.js
|
||||
|
||||
cat ./frontend/src/arne.js
|
||||
|
||||
cd ./frontend/
|
||||
|
||||
npm install
|
||||
|
||||
npm run build
|
||||
|
||||
cd ..
|
||||
|
||||
./MusicServer
|
||||
@@ -1,104 +1,50 @@
|
||||
set dotenv-load
|
||||
|
||||
# Build the application
|
||||
# Build and run the unit tests
|
||||
all: build test
|
||||
|
||||
templ-install:
|
||||
@if ! command -v templ > /dev/null; then \
|
||||
read -p "Go's 'templ' is not installed on your machine. Do you want to install it? [Y/n] " choice; \
|
||||
if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \
|
||||
go install github.com/a-h/templ/cmd/templ@latest; \
|
||||
if [ ! -x "$$(command -v templ)" ]; then \
|
||||
echo "templ installation failed. Exiting..."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
else \
|
||||
echo "You chose not to install templ. Exiting..."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
templ-build: templ-install
|
||||
# Generate templ components (version pinned in go.mod)
|
||||
templ-build:
|
||||
@echo "Building templ..."
|
||||
@templ generate
|
||||
|
||||
tailwind-macos:
|
||||
@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-macos-arm64 -o tailwindcss; fi
|
||||
@chmod +x tailwindcss
|
||||
|
||||
tailwind-linux:
|
||||
@if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss; fi
|
||||
@chmod +x tailwindcss
|
||||
|
||||
tailwind-build:
|
||||
@echo "Building tailwind..."
|
||||
@./tailwindcss -i cmd/web/assets/css/input.css -o cmd/web/assets/css/output.css
|
||||
@go tool templ generate
|
||||
|
||||
sqlc-generate:
|
||||
@echo "Generating sqlc schema..."
|
||||
@echo "Generating sqlc code..."
|
||||
@sqlc generate
|
||||
|
||||
migrate-create name:
|
||||
@migrate create -ext sql -dir internal/db/migrations -seq {{name}}
|
||||
|
||||
swag-install:
|
||||
@if ! command -v swag > /dev/null; then \
|
||||
read -p "Swag is not installed on your machine. Do you want to install it? [Y/n] " choice; \
|
||||
if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \
|
||||
go install github.com/swaggo/swag/cmd/swag@latest; \
|
||||
if [ ! -x "$$(command -v swag)" ]; then \
|
||||
echo "swag installation failed. Exiting..."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
else \
|
||||
echo "You chose not to install swag. Exiting..."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
swag-generate: swag-install
|
||||
# Generate OpenAPI docs (version pinned in go.mod)
|
||||
swag-generate:
|
||||
@echo "Generating OpenAPI docs..."
|
||||
@swag init -g internal/server/routes.go -o cmd/docs
|
||||
@go tool swag init -g internal/server/routes.go -o cmd/docs --parseInternal
|
||||
|
||||
frontend-install:
|
||||
@if ! command -v npm > /dev/null; then \
|
||||
echo "npm is not installed on your machine. Please install Node.js first."; \
|
||||
exit 1; \
|
||||
fi
|
||||
@cd cmd/frontend && npm install
|
||||
|
||||
frontend-build: frontend-install
|
||||
@echo "Building frontend..."
|
||||
@cd cmd/frontend && npm run build
|
||||
|
||||
[no-cd]
|
||||
build: sqlc-generate templ-build swag-generate
|
||||
@echo "Building..."
|
||||
@go build -o main cmd/main.go
|
||||
@echo "Building..."
|
||||
@go build -o main cmd/main.go
|
||||
|
||||
run:
|
||||
@templ generate
|
||||
run: templ-build
|
||||
@go run cmd/main.go
|
||||
|
||||
build-run: build
|
||||
@go run cmd/main.go
|
||||
@./main
|
||||
|
||||
test: build
|
||||
@echo "Starting test database container..."
|
||||
@docker compose -f compose.test.yaml up -d
|
||||
@sleep 10
|
||||
@echo "Running integration tests..."
|
||||
@just test-integration
|
||||
@echo "Stopping test database container..."
|
||||
@just test-integration-down
|
||||
# Unit tests: no database or Docker needed
|
||||
test:
|
||||
@go test -race ./...
|
||||
|
||||
# Integration tests against PostgreSQL in Docker (testcontainers), using the active docker context.
|
||||
# Pass a pattern to run a subset, e.g. `just test-integration TestSQLDumps`
|
||||
test-integration pattern=".":
|
||||
@DOCKER_HOST="${DOCKER_HOST:-$(docker context inspect --format '{{{{.Endpoints.docker.Host}}')}" \
|
||||
go test -tags integration -race -timeout 15m -run '{{pattern}}' ./...
|
||||
|
||||
# Clean the binary
|
||||
clean:
|
||||
@echo "Cleaning..."
|
||||
@rm -f main
|
||||
|
||||
docker-build:
|
||||
@echo "Building Docker image with docker..."
|
||||
@docker build -t music-server .
|
||||
|
||||
docker-run:
|
||||
@@ -107,82 +53,13 @@ docker-run:
|
||||
docker-down:
|
||||
@docker compose down
|
||||
|
||||
# Run integration tests with docker
|
||||
# Starts a test PostgreSQL container, runs tests, then cleans up
|
||||
test-integration:
|
||||
@echo "Cleaning old test database..."
|
||||
@docker compose -f compose.test.yaml down -v
|
||||
@echo "Starting fresh test database container..."
|
||||
@docker compose -f compose.test.yaml up -d
|
||||
@sleep 10
|
||||
@echo "Running integration tests..."
|
||||
@DOCKER_HOST=unix:///Users/sebastian/.docker/run/docker.sock TESTCONTAINERS_RYUK_CONTAINER_NETWORK=testcontainers-test-net DB_HOST=localhost DB_PORT=5433 DB_USERNAME=testuser DB_PASSWORD=testpass DB_NAME=music_server_test MUSIC_PATH=/Users/sebastian/projects/MusicServer/testMusic CHARACTERS_PATH=/Users/sebastian/projects/MusicServer/testCharacters PORT=8081 LOG_LEVEL=debug LOG_JSON=false go test -v -timeout 30m -p 1 -parallel 1 ./internal/...
|
||||
|
||||
# Alternative: Run integration tests using testcontainers with docker provider
|
||||
test-integration-tc:
|
||||
@echo "Creating test network (if it doesn't exist)..."
|
||||
@docker network inspect testcontainers-test-net > /dev/null 2>&1 || docker network create testcontainers-test-net
|
||||
@echo "Running integration tests with testcontainers (docker provider)..."
|
||||
@DOCKER_HOST=unix:///Users/sebastian/.docker/run/docker.sock TESTCONTAINERS_PROVIDER=docker TESTCONTAINERS_RYUK_CONTAINER_NETWORK=testcontainers-test-net go test -v -timeout 30m .
|
||||
|
||||
# Run SQL dump migration tests
|
||||
# Tests that the application can start with each SQL dump and migrations work correctly
|
||||
test-sql-dump:
|
||||
@echo "Creating test network (if it doesn't exist)..."
|
||||
@docker network inspect testcontainers-test-net > /dev/null 2>&1 || docker network create testcontainers-test-net
|
||||
@echo "Running SQL dump migration tests..."
|
||||
@DOCKER_HOST=unix:///Users/sebastian/.docker/run/docker.sock TESTCONTAINERS_PROVIDER=docker TESTCONTAINERS_RYUK_CONTAINER_NETWORK=testcontainers-test-net go test -v -timeout 15m -run "TestMusic.*Dump" ./internal/server/
|
||||
|
||||
# Run individual SQL dump tests
|
||||
test-sql-dump-ref:
|
||||
@echo "Creating test network (if it doesn't exist)..."
|
||||
@docker network inspect testcontainers-test-net > /dev/null 2>&1 || docker network create testcontainers-test-net
|
||||
@echo "Running SQL dump migration test for ref dump..."
|
||||
@DOCKER_HOST=unix:///Users/sebastian/.docker/run/docker.sock TESTCONTAINERS_PROVIDER=docker TESTCONTAINERS_RYUK_CONTAINER_NETWORK=testcontainers-test-net go test -v -timeout 5m -run "TestMusicRefDump" ./internal/server/
|
||||
|
||||
test-sql-dump-test:
|
||||
@echo "Creating test network (if it doesn't exist)..."
|
||||
@docker network inspect testcontainers-test-net > /dev/null 2>&1 || docker network create testcontainers-test-net
|
||||
@echo "Running SQL dump migration test for test dump..."
|
||||
@DOCKER_HOST=unix:///Users/sebastian/.docker/run/docker.sock TESTCONTAINERS_PROVIDER=docker TESTCONTAINERS_RYUK_CONTAINER_NETWORK=testcontainers-test-net go test -v -timeout 5m -run "TestMusicTestDump" ./internal/server/
|
||||
|
||||
test-sql-dump-prod:
|
||||
@echo "Creating test network (if it doesn't exist)..."
|
||||
@docker network inspect testcontainers-test-net > /dev/null 2>&1 || docker network create testcontainers-test-net
|
||||
@echo "Running SQL dump migration test for prod dump..."
|
||||
@DOCKER_HOST=unix:///Users/sebastian/.docker/run/docker.sock TESTCONTAINERS_PROVIDER=docker TESTCONTAINERS_RYUK_CONTAINER_NETWORK=testcontainers-test-net go test -v -timeout 5m -run "TestMusicProdDump" ./internal/server/
|
||||
|
||||
# Stop and remove test database container
|
||||
test-integration-down:
|
||||
@echo "Stopping test database container..."
|
||||
@docker compose -f compose.test.yaml down -v
|
||||
|
||||
# Build and run with Docker Compose
|
||||
build-run-docker:
|
||||
@echo "Building and running with Docker Compose..."
|
||||
@docker compose up --build
|
||||
|
||||
# Shutdown containers
|
||||
stop-docker:
|
||||
@echo "Stopping containers..."
|
||||
@docker compose down
|
||||
|
||||
watch-templ:
|
||||
templ generate --watch --proxy="http://localhost:8080" --cmd="go run ."
|
||||
@go tool templ generate --watch --proxy="http://localhost:8080" --cmd="go run ./cmd"
|
||||
|
||||
# Live Reload
|
||||
# Live reload
|
||||
watch:
|
||||
@if command -v air > /dev/null; then \
|
||||
air; \
|
||||
echo "Watching...";\
|
||||
else \
|
||||
read -p "Go's 'air' is not installed on your machine. Do you want to install it? [Y/n] " choice; \
|
||||
if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \
|
||||
go install github.com/air-verse/air@latest; \
|
||||
air; \
|
||||
echo "Watching...";\
|
||||
else \
|
||||
echo "You chose not to install air. Exiting..."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
@if ! command -v air > /dev/null; then \
|
||||
echo "air is not installed. Install it with: go install github.com/air-verse/air@latest"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@air
|
||||
@@ -1,11 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./cmd/web/**/*.html", "./cmd/web/**/*.templ",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user