feat: initialize golang project template with docker and ci/cd
Some checks failed
CI / Lint (push) Failing after 45s
CI / Test (push) Failing after 10s
CI / Build (push) Has been skipped
CI / Docker Build (push) Has been skipped

This commit is contained in:
2026-01-12 10:47:04 +01:00
parent 12473662e8
commit 6ef83e18f8
11 changed files with 372 additions and 1 deletions

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
.git
.github
bin/
build/
coverage.out
README.md
Makefile
var/
tmp/

62
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
name: CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: false
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Test
run: go test -v -race -cover ./...
build:
name: Build
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Build
run: go build -v ./cmd/app
docker-build:
name: Docker Build
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build
uses: docker/build-push-action@v5
with:
context: .
push: false
tags: app:latest
cache-from: type=gha
cache-to: type=gha,mode=max

57
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: Release
on:
push:
tags:
- '*'
permissions:
contents: write
packages: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITEA_TOKEN: ${{ secrets.ACCESS_TOKEN_GITEA }}
docker-release:
runs-on: ubuntu-latest
needs: goreleaser
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: git.dcentral.systems
username: master
password: ${{ secrets.ACCESS_TOKEN_GITEA }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: git.dcentral.systems/templates/golang
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

2
.gitignore vendored
View File

@@ -25,3 +25,5 @@ go.work.sum
# env file
.env
build/

21
.golangci.yml Normal file
View File

@@ -0,0 +1,21 @@
# Options for analysis running.
version: 2
run:
timeout: 5m
linters:
enable:
- errcheck
- govet
- ineffassign
- staticcheck
- unused
- misspell
- unconvert
- unparam
linters-settings:
govet:
check-shadowing: true
gofmt:
simplify: true

45
AGENTS.md Normal file
View File

@@ -0,0 +1,45 @@
# Development Guidelines
This document outlines the best practices for Go development and Git workflow to be followed by the Gemini agent for this project.
## Go Development Guidelines
### Code Quality and Style
- **Formatting:** All Go code MUST be formatted with `gofmt` before committing.
- **Linting:** Use `golangci-lint` to enforce code quality and style.
- **Simplicity:** Write simple, clear, and concise code. Avoid unnecessary complexity.
- **Error Handling:** Handle all errors explicitly. Never ignore an error. Check for errors and return them from functions.
- **Naming:** Use meaningful and descriptive names for variables, functions, and packages. Follow Go's naming conventions (e.g., `camelCase` for private, `PascalCase` for public).
- **Comments:** Write comments to explain the *why* behind complex or non-obvious code, not the *what*. Document all public functions and packages.
- **Testing:**
- Write unit tests for all new code. Aim for high test coverage.
- Use table-driven tests for testing multiple scenarios.
- Mocks and interfaces should be used to isolate dependencies for testing.
- **Dependencies:** Use Go modules (`go mod`) to manage project dependencies. Keep the `go.mod` and `go.sum` files up-to-date.
### Best Practices
- **Concurrency:** When using goroutines, ensure proper synchronization to avoid race conditions. Use channels for communication between goroutines.
- **Interfaces:** Use interfaces to define behavior and decouple components.
- **Packages:** Structure your code into logical packages. Avoid circular dependencies.
- **Security:** Be mindful of security best practices. Sanitize inputs, avoid SQL injection, and handle credentials securely.
## Git Workflow Best Practices
### Branching
- **Main Branch:** The `main` branch is for production-ready code only. Direct commits to `main` are NOT allowed.
- **Feature Branches:** Create a new branch for every new feature or bug fix.
- Branch names should be descriptive and follow the pattern `feature/<short-description>` or `fix/<short-description>` (e.g., `feature/user-auth`, `fix/login-bug`).
- **Pull Requests (PRs):** All changes must be submitted through a Pull Request to the `main` branch.
### Committing
- **Atomic Commits:** Each commit should represent a single, logical change. Do not bundle unrelated changes into one commit.
- **Commit Messages:** Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. This helps in automating changelogs and versioning.
- **Format:** `<type>[optional scope]: <description>`
- **Example:** `feat: add user login endpoint`
- **Common types:** `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`.
### Pull Request (PR) Process
1. **Create a PR:** When your feature or fix is complete, create a PR against the `main` branch.
2. **CI Checks:** Ensure all automated checks (build, tests, linting) pass.
3. **Code Review:** The PR will be reviewed. Address any feedback by pushing new commits to your branch.
4. **Merge:** Once the PR is approved and all checks pass, it will be merged into `main`.

29
Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
# Build stage
FROM golang:1.23-alpine AS builder
WORKDIR /app
# Copy go.mod and go.sum first to leverage Docker cache
# We need to check if go.sum exists, but COPY fails if it doesn't.
# Since we just ran go mod init, go.sum might not exist yet if no deps.
# SAFE PATTERN: COPY go.mod and optional go.sum
COPY go.mod go.sum* ./
RUN go mod download
# Copy the rest of the source code
COPY . .
# Build the application
# -ldflags="-w -s" strips debug information for smaller binary
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /go/bin/app ./cmd/app
# Final stage
# Use distroless static image for security and minimal footprint
FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /
COPY --from=builder /go/bin/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]

24
Makefile Normal file
View File

@@ -0,0 +1,24 @@
.PHONY: build run test lint clean docker-build
APP_NAME := app
BUILD_DIR := build
CMD_PATH := ./cmd/app
build:
@mkdir -p $(BUILD_DIR)
go build -o $(BUILD_DIR)/$(APP_NAME) $(CMD_PATH)
run: build
$(BUILD_DIR)/$(APP_NAME)
test:
go test -v -race -cover ./...
lint:
golangci-lint run
clean:
rm -rf $(BUILD_DIR)
docker-build:
docker build -t $(APP_NAME):latest .

View File

@@ -1,2 +1,70 @@
# golang
# Golang Project Template
A production-ready Go project template with Docker builds, CI/CD pipelines, and best practices.
## Features
- **Standard Layout**: Follows Go project layout standards (`cmd`, `internal`).
- **Graceful Shutdown**: `main.go` implements signal handling and context cancellation.
- **Structured Logging**: Uses `log/slog`.
- **Docker**: Multi-stage `Dockerfile` using `distroless` for secure, small images.
- **CI/CD**: GitHub Actions for linting, testing, building, and releasing (with GoReleaser).
- **Tooling**: `Makefile` for common tasks and `golangci-lint` configuration.
## Prerequisites
- [Go](https://go.dev/) 1.23+
- [Docker](https://www.docker.com/)
- [Make](https://www.gnu.org/software/make/)
## Getting Started
### Build and Run
```bash
# Build binary
make build
# Run application
make run
```
### Testing
```bash
make test
```
### Linting
```bash
make lint
```
## Docker
Build the Docker image:
```bash
make docker-build
```
Run the container:
```bash
docker run --rm -p 8080:8080 app:latest
```
## CI/CD
The project includes GitHub Actions workflows:
- **CI (`ci.yml`)**: Runs on `main` and PRs. Validates formatting, linting, tests, and builds.
- **Release (`release.yml`)**: Runs on tags (`v*`). Creates a GitHub Release and pushes the Docker image to GHCR.
## Project Structure
- `cmd/app`: Main application entry point.
- `internal`: Private application code.
- `build`: Build artifacts.
- `.github`: CI/CD workflows.

51
cmd/app/main.go Normal file
View File

@@ -0,0 +1,51 @@
package main
import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
slog.SetDefault(logger)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Handle OS signals
go func() {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
slog.Info("Received shutdown signal")
cancel()
}()
if err := run(ctx); err != nil {
slog.Error("Application error", "error", err)
os.Exit(1)
}
}
func run(ctx context.Context) error {
slog.Info("Starting application...")
// Simulate long running process or server start
// e.g. server.ListenAndServe()
<-ctx.Done()
slog.Info("Shutting down application...")
// Cleanup with timeout
_, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shutdownCancel()
// Pretend to cleanup
time.Sleep(100 * time.Millisecond)
return nil
}

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module github.com/placeholder/golang-template
go 1.25.4