#!/usr/bin/env bash # init_go_project # --------------- # Pipeline que inicializa un repositorio Go completo con estructura profesional: # cmd/app, internal/config, internal/service, pkg/version, scripts/, Makefile, # .gitignore, README y git init. # # USO: # bash init_go_project.sh [module_path] # # ARGUMENTOS: # module_path Path del módulo Go (opcional; default: github.com//) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" init_go_project() { local module_path="${1:-}" local project_name project_name="$(basename "$(pwd)")" if [[ -z "$module_path" ]]; then module_path="github.com/$(whoami)/${project_name}" fi echo "=== Inicializar Proyecto Go Completo ===" echo " Proyecto: ${project_name}" echo " Módulo: ${module_path}" echo " Dir: $(pwd)" echo "" # Verificar dependencias if ! command -v go &>/dev/null; then echo "init_go_project: Go no está instalado" >&2 return 1 fi if ! command -v git &>/dev/null; then echo "init_go_project: git no está instalado" >&2 return 1 fi echo "Go: $(go version)" echo "git: $(git --version)" echo "" # Crear estructura de carpetas echo "Creando estructura de carpetas..." mkdir -p cmd/app internal/config internal/service pkg/version scripts bin echo "Estructura base creada" echo "" # go mod init echo "Inicializando módulo Go..." if ! go mod init "$module_path"; then echo "init_go_project: falló go mod init" >&2 return 1 fi echo "go.mod creado" echo "" # Crear archivos fuente echo "Creando archivos fuente..." cat > cmd/app/main.go << GOEOF package main import ( "fmt" "${module_path}/internal/config" "${module_path}/internal/service" "${module_path}/pkg/version" ) func main() { cfg := config.Load() msg := service.BuildStartupMessage(cfg.AppName, version.Current()) fmt.Println(msg) } GOEOF cat > internal/config/config.go << 'CFGEOF' package config import "os" type AppConfig struct { AppName string } func Load() AppConfig { appName := os.Getenv("APP_NAME") if appName == "" { appName = "Go Project" } return AppConfig{AppName: appName} } CFGEOF cat > internal/service/message.go << 'SVCEOF' package service import "fmt" func BuildStartupMessage(appName, appVersion string) string { return fmt.Sprintf("%s iniciado correctamente (version %s)", appName, appVersion) } SVCEOF cat > internal/service/message_test.go << 'TESTEOF' package service import "testing" func TestBuildStartupMessage(t *testing.T) { result := BuildStartupMessage("MyApp", "0.1.0") want := "MyApp iniciado correctamente (version 0.1.0)" if result != want { t.Fatalf("resultado inesperado:\nwant: %s\ngot: %s", want, result) } } TESTEOF cat > pkg/version/version.go << 'VEREOF' package version var value = "0.1.0" func Current() string { return value } VEREOF echo "Archivos fuente creados" echo "" # Makefile echo "Creando Makefile..." cat > Makefile << 'MAKEEOF' APP_NAME=app CMD_PATH=./cmd/app BIN_DIR=./bin .PHONY: run build build-all test fmt tidy clean run: go run $(CMD_PATH) build: mkdir -p $(BIN_DIR) go build -o $(BIN_DIR)/$(APP_NAME) $(CMD_PATH) build-all: bash ./scripts/build-all.sh test: go test ./... fmt: gofmt -w ./cmd ./internal ./pkg tidy: go mod tidy clean: rm -rf $(BIN_DIR) MAKEEOF echo "Makefile creado" echo "" # .gitignore cat > .gitignore << 'IGNEOF' bin/ *.exe *.exe~ *.dll *.so *.dylib *.test *.out coverage.out .idea/ .vscode/ *.swp *.swo *~ .DS_Store Thumbs.db IGNEOF # README cat > README.md << READEOF # ${project_name} Repositorio Go inicializado con estructura completa. ## Uso rápido \`\`\`bash ./scripts/run.sh ./scripts/test.sh ./scripts/build.sh \`\`\` ## Make \`\`\`bash make run make test make build make build-all \`\`\` READEOF # Scripts echo "Creando scripts..." cat > scripts/run.sh << 'RUNEOF' #!/bin/bash set -euo pipefail go run ./cmd/app RUNEOF cat > scripts/test.sh << 'TESTSHEOF' #!/bin/bash set -euo pipefail go test ./... TESTSHEOF cat > scripts/build.sh << 'BUILDSHEOF' #!/bin/bash set -euo pipefail mkdir -p ./bin go build -o ./bin/app ./cmd/app echo "Binario: ./bin/app" BUILDSHEOF cat > scripts/build-all.sh << 'BUILDALLEOF' #!/bin/bash set -euo pipefail mkdir -p ./bin GOOS=linux GOARCH=amd64 go build -o ./bin/app-linux-amd64 ./cmd/app GOOS=darwin GOARCH=amd64 go build -o ./bin/app-darwin-amd64 ./cmd/app GOOS=windows GOARCH=amd64 go build -o ./bin/app-windows-amd64.exe ./cmd/app echo "Builds en ./bin" BUILDALLEOF cat > scripts/lint.sh << 'LINTEOF' #!/bin/bash set -euo pipefail unformatted="$(gofmt -l ./cmd ./internal ./pkg)" if [ -n "$unformatted" ]; then echo "Archivos sin formato:" >&2 echo "$unformatted" >&2 echo "Ejecuta: make fmt" >&2 exit 1 fi echo "Formato OK" LINTEOF chmod +x scripts/*.sh echo "Scripts creados" echo "" # go mod tidy echo "Ajustando dependencias (go mod tidy)..." go mod tidy echo "Dependencias ajustadas" echo "" # git init echo "Inicializando repositorio git..." git init >/dev/null 2>&1 git add . echo "Repositorio git inicializado" echo "" echo "=== Proyecto Go creado exitosamente ===" echo "" echo "Estructura:" echo " cmd/app/main.go" echo " internal/config/config.go" echo " internal/service/message.go + message_test.go" echo " pkg/version/version.go" echo " scripts/ (run, test, build, build-all, lint)" echo " Makefile, go.mod, .gitignore, README.md" echo "" echo "Proximos pasos:" echo " 1. ./scripts/run.sh" echo " 2. ./scripts/test.sh" echo " 3. ./scripts/build-all.sh" } init_go_project "$@"