457 lines
9.0 KiB
Markdown
457 lines
9.0 KiB
Markdown
---
|
|
name: golang-development:scaffold
|
|
description: Scaffold new Go projects with modern structure, Go modules, testing setup, CI/CD pipelines, and best practices
|
|
---
|
|
|
|
# Golang Development Scaffold Command
|
|
|
|
Create a new Go project with a production-ready structure, modern tooling, and best practices built-in.
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
/golang-development:scaffold <project-name> [options]
|
|
```
|
|
|
|
## Arguments
|
|
|
|
- `$1` - Project name (required, will be used for module name)
|
|
- `$2` - Project type: `service`, `cli`, `library`, or `microservice` (optional, defaults to `service`)
|
|
- `$3` - Additional options as JSON (optional)
|
|
|
|
## Examples
|
|
|
|
```bash
|
|
# Create a basic HTTP service
|
|
/golang-development:scaffold my-api service
|
|
|
|
# Create a CLI application
|
|
/golang-development:scaffold my-tool cli
|
|
|
|
# Create a library
|
|
/golang-development:scaffold my-lib library
|
|
|
|
# Create a microservice with full features
|
|
/golang-development:scaffold user-service microservice '{"with_grpc": true, "with_db": true}'
|
|
```
|
|
|
|
## Project Structures
|
|
|
|
### Service (HTTP API)
|
|
```
|
|
my-api/
|
|
├── cmd/
|
|
│ └── server/
|
|
│ └── main.go
|
|
├── internal/
|
|
│ ├── handler/
|
|
│ │ └── health.go
|
|
│ ├── middleware/
|
|
│ │ └── logging.go
|
|
│ └── service/
|
|
│ └── user.go
|
|
├── pkg/
|
|
│ └── response/
|
|
│ └── response.go
|
|
├── api/
|
|
│ └── openapi.yaml
|
|
├── scripts/
|
|
│ └── build.sh
|
|
├── deployments/
|
|
│ ├── Dockerfile
|
|
│ └── k8s/
|
|
├── go.mod
|
|
├── go.sum
|
|
├── .gitignore
|
|
├── .golangci.yml
|
|
├── Makefile
|
|
└── README.md
|
|
```
|
|
|
|
### CLI Application
|
|
```
|
|
my-tool/
|
|
├── cmd/
|
|
│ └── my-tool/
|
|
│ └── main.go
|
|
├── internal/
|
|
│ ├── command/
|
|
│ │ ├── root.go
|
|
│ │ └── serve.go
|
|
│ └── config/
|
|
│ └── config.go
|
|
├── go.mod
|
|
├── go.sum
|
|
├── .gitignore
|
|
├── .golangci.yml
|
|
├── Makefile
|
|
└── README.md
|
|
```
|
|
|
|
### Library
|
|
```
|
|
my-lib/
|
|
├── example_test.go
|
|
├── lib.go
|
|
├── lib_test.go
|
|
├── go.mod
|
|
├── go.sum
|
|
├── .gitignore
|
|
├── .golangci.yml
|
|
├── LICENSE
|
|
└── README.md
|
|
```
|
|
|
|
### Microservice (Full Features)
|
|
```
|
|
user-service/
|
|
├── cmd/
|
|
│ └── server/
|
|
│ └── main.go
|
|
├── internal/
|
|
│ ├── domain/
|
|
│ │ └── user.go
|
|
│ ├── handler/
|
|
│ │ ├── http/
|
|
│ │ └── grpc/
|
|
│ ├── repository/
|
|
│ │ └── postgres/
|
|
│ ├── service/
|
|
│ │ └── user_service.go
|
|
│ └── infrastructure/
|
|
│ ├── database/
|
|
│ ├── cache/
|
|
│ └── messaging/
|
|
├── api/
|
|
│ ├── http/
|
|
│ │ └── openapi.yaml
|
|
│ └── grpc/
|
|
│ └── user.proto
|
|
├── pkg/
|
|
│ ├── logger/
|
|
│ ├── metrics/
|
|
│ └── tracing/
|
|
├── migrations/
|
|
│ └── 001_create_users.sql
|
|
├── deployments/
|
|
│ ├── Dockerfile
|
|
│ ├── docker-compose.yml
|
|
│ └── k8s/
|
|
├── scripts/
|
|
├── go.mod
|
|
├── go.sum
|
|
├── .gitignore
|
|
├── .golangci.yml
|
|
├── Makefile
|
|
└── README.md
|
|
```
|
|
|
|
## Generated Files
|
|
|
|
### main.go (Service)
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"{{.ModuleName}}/internal/handler"
|
|
"{{.ModuleName}}/internal/middleware"
|
|
)
|
|
|
|
func main() {
|
|
// Setup router
|
|
mux := http.NewServeMux()
|
|
|
|
// Middleware
|
|
handler := middleware.Logging(
|
|
middleware.Recovery(mux),
|
|
)
|
|
|
|
// Routes
|
|
mux.HandleFunc("/health", handler.Health)
|
|
mux.HandleFunc("/ready", handler.Ready)
|
|
|
|
// Server configuration
|
|
port := os.Getenv("PORT")
|
|
if port == "" {
|
|
port = "8080"
|
|
}
|
|
|
|
server := &http.Server{
|
|
Addr: fmt.Sprintf(":%s", port),
|
|
Handler: handler,
|
|
ReadTimeout: 15 * time.Second,
|
|
WriteTimeout: 15 * time.Second,
|
|
IdleTimeout: 60 * time.Second,
|
|
}
|
|
|
|
// Start server
|
|
go func() {
|
|
log.Printf("Server starting on port %s", port)
|
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Fatalf("Server error: %v", err)
|
|
}
|
|
}()
|
|
|
|
// Graceful shutdown
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
<-quit
|
|
|
|
log.Println("Shutting down server...")
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
if err := server.Shutdown(ctx); err != nil {
|
|
log.Fatalf("Server forced to shutdown: %v", err)
|
|
}
|
|
|
|
log.Println("Server exited")
|
|
}
|
|
```
|
|
|
|
### Makefile
|
|
```makefile
|
|
.PHONY: build test lint run clean
|
|
|
|
# Variables
|
|
APP_NAME := {{.ProjectName}}
|
|
VERSION := $(shell git describe --tags --always --dirty)
|
|
BUILD_TIME := $(shell date -u '+%Y-%m-%d_%H:%M:%S')
|
|
LDFLAGS := -ldflags "-X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME)"
|
|
|
|
# Build
|
|
build:
|
|
go build $(LDFLAGS) -o bin/$(APP_NAME) ./cmd/server
|
|
|
|
# Test
|
|
test:
|
|
go test -v -race -coverprofile=coverage.out ./...
|
|
|
|
# Coverage
|
|
coverage:
|
|
go tool cover -html=coverage.out
|
|
|
|
# Lint
|
|
lint:
|
|
golangci-lint run
|
|
|
|
# Run
|
|
run:
|
|
go run ./cmd/server
|
|
|
|
# Clean
|
|
clean:
|
|
rm -rf bin/
|
|
rm -f coverage.out
|
|
|
|
# Install tools
|
|
tools:
|
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
|
|
|
# Docker
|
|
docker-build:
|
|
docker build -t $(APP_NAME):$(VERSION) .
|
|
|
|
docker-run:
|
|
docker run -p 8080:8080 $(APP_NAME):$(VERSION)
|
|
```
|
|
|
|
### Dockerfile
|
|
```dockerfile
|
|
# Build stage
|
|
FROM golang:1.21-alpine AS builder
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy go mod files
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
# Copy source code
|
|
COPY . .
|
|
|
|
# Build
|
|
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/server
|
|
|
|
# Runtime stage
|
|
FROM alpine:latest
|
|
|
|
RUN apk --no-cache add ca-certificates
|
|
|
|
WORKDIR /root/
|
|
|
|
# Copy binary from builder
|
|
COPY --from=builder /app/main .
|
|
|
|
EXPOSE 8080
|
|
|
|
CMD ["./main"]
|
|
```
|
|
|
|
### .golangci.yml
|
|
```yaml
|
|
linters:
|
|
enable:
|
|
- errcheck
|
|
- gosimple
|
|
- govet
|
|
- ineffassign
|
|
- staticcheck
|
|
- unused
|
|
- gofmt
|
|
- goimports
|
|
- misspell
|
|
- gocritic
|
|
- gosec
|
|
- revive
|
|
|
|
linters-settings:
|
|
errcheck:
|
|
check-blank: true
|
|
govet:
|
|
check-shadowing: true
|
|
gofmt:
|
|
simplify: true
|
|
|
|
issues:
|
|
exclude-use-default: false
|
|
max-issues-per-linter: 0
|
|
max-same-issues: 0
|
|
```
|
|
|
|
### GitHub Actions CI (.github/workflows/ci.yml)
|
|
```yaml
|
|
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [ main ]
|
|
pull_request:
|
|
branches: [ main ]
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v4
|
|
with:
|
|
go-version: '1.21'
|
|
|
|
- name: Install dependencies
|
|
run: go mod download
|
|
|
|
- name: Run tests
|
|
run: go test -v -race -coverprofile=coverage.out ./...
|
|
|
|
- name: Upload coverage
|
|
uses: codecov/codecov-action@v3
|
|
with:
|
|
files: ./coverage.out
|
|
|
|
lint:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v4
|
|
with:
|
|
go-version: '1.21'
|
|
|
|
- name: golangci-lint
|
|
uses: golangci/golangci-lint-action@v3
|
|
with:
|
|
version: latest
|
|
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
needs: [test, lint]
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v4
|
|
with:
|
|
go-version: '1.21'
|
|
|
|
- name: Build
|
|
run: go build -v ./cmd/server
|
|
```
|
|
|
|
## Configuration Options
|
|
|
|
The command accepts a JSON configuration object:
|
|
|
|
```json
|
|
{
|
|
"with_grpc": true,
|
|
"with_db": true,
|
|
"with_redis": true,
|
|
"with_kafka": true,
|
|
"with_docker": true,
|
|
"with_k8s": true,
|
|
"with_ci": true,
|
|
"db_driver": "postgres",
|
|
"module_path": "github.com/user/project"
|
|
}
|
|
```
|
|
|
|
## Implementation Steps
|
|
|
|
1. Parse arguments and configuration
|
|
2. Create project directory structure
|
|
3. Initialize Go module
|
|
4. Generate main.go and core files
|
|
5. Create Makefile and build scripts
|
|
6. Add Dockerfile and Docker Compose
|
|
7. Generate CI/CD configuration
|
|
8. Create README with usage instructions
|
|
9. Initialize git repository
|
|
10. Run `go mod tidy`
|
|
|
|
## Features Included
|
|
|
|
- **Modern Project Structure**: Clean architecture with separation of concerns
|
|
- **HTTP Server**: Production-ready with graceful shutdown
|
|
- **Middleware**: Logging, recovery, CORS, authentication templates
|
|
- **Health Checks**: Health and readiness endpoints
|
|
- **Testing**: Test structure and examples
|
|
- **Linting**: golangci-lint configuration
|
|
- **CI/CD**: GitHub Actions workflow
|
|
- **Docker**: Multi-stage Dockerfile
|
|
- **Kubernetes**: Basic manifests (if requested)
|
|
- **Documentation**: Comprehensive README
|
|
|
|
## Post-Scaffold Steps
|
|
|
|
After scaffolding, the command will suggest:
|
|
|
|
```bash
|
|
cd {{.ProjectName}}
|
|
go mod tidy
|
|
make test
|
|
make run
|
|
```
|
|
|
|
## When to Use
|
|
|
|
Use this command to:
|
|
- Start new Go projects quickly
|
|
- Ensure consistent project structure
|
|
- Set up best practices from the start
|
|
- Include modern tooling and CI/CD
|
|
- Scaffold microservices or APIs
|
|
- Create CLI tools with proper structure
|