From c1e628f3391da6607016d52ef555a28c05454339 Mon Sep 17 00:00:00 2001 From: Gabriel Radureau Date: Thu, 9 Apr 2026 00:26:15 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20docs:=20update=20comprehensive?= =?UTF-8?q?=20documentation=20and=20project=20infrastructure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation Updates: - Enhanced AGENTS.md with user authentication details - Updated README.md with authentication API documentation - Added CONTRIBUTING.md guidelines for BDD testing - Version management guide improvements - Local CI/CD testing documentation Project Infrastructure: - Updated .gitignore for new file patterns - Enhanced git hooks documentation - YAML linting configuration - Script improvements and organization - Configuration management updates API Enhancements: - Greet service integration with authentication - Server middleware for JWT validation - Telemetry improvements - Version management utilities Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- .githooks/README.md | 4 +- .gitignore | 3 + .yamllint.yaml | 2 +- AGENTS.md | 38 +- CONTRIBUTING.md | 16 +- README.md | 82 +++- VERSION | 2 +- documentation/AGENT_USAGE_GUIDE.md | 14 +- documentation/BDD_GUIDE.md | 10 +- documentation/local-ci-cd-testing.md | 2 +- documentation/version-management-guide.md | 6 +- pkg/config/config.go | 154 ++++++- pkg/greet/api_v1.go | 2 + pkg/greet/api_v2.go | 1 + pkg/greet/greet.go | 27 +- pkg/server/server.go | 129 +++++- pkg/telemetry/telemetry.go | 2 +- pkg/version/version.go | 6 +- scripts/LOCAL_CI_GUIDE.md | 215 ++++++++++ scripts/README.md | 10 +- scripts/build-with-version.sh | 10 +- scripts/build.sh | 4 +- scripts/cicd.sh | 4 +- scripts/cicd/README.md | 286 ------------- scripts/cicd/check-pipeline-status.sh | 71 ---- scripts/cicd/contributor-quickstart.sh | 78 ---- scripts/cicd/test-act-local.sh | 75 ---- scripts/cicd/test-cicd-docker.sh | 99 ----- scripts/cicd/test-cicd-local.sh | 82 ---- scripts/cicd/test-cicd-simple.sh | 61 --- scripts/cicd/validate-workflow.sh | 151 ------- scripts/run-bdd-tests.sh | 91 ++++- scripts/run-bdd-tests.sh.backup | 177 ++++++++ scripts/start-server.sh | 6 +- scripts/test-graceful-shutdown.sh | 6 +- scripts/test-local-ci-cd.sh | 473 ++++++++++++++-------- scripts/test-opentelemetry.sh | 10 +- scripts/validate-cicd-comprehensive.sh | 2 +- scripts/version-bump.sh | 6 +- 39 files changed, 1230 insertions(+), 1187 deletions(-) create mode 100644 scripts/LOCAL_CI_GUIDE.md delete mode 100644 scripts/cicd/README.md delete mode 100755 scripts/cicd/check-pipeline-status.sh delete mode 100755 scripts/cicd/contributor-quickstart.sh delete mode 100755 scripts/cicd/test-act-local.sh delete mode 100755 scripts/cicd/test-cicd-docker.sh delete mode 100755 scripts/cicd/test-cicd-local.sh delete mode 100755 scripts/cicd/test-cicd-simple.sh delete mode 100755 scripts/cicd/validate-workflow.sh create mode 100755 scripts/run-bdd-tests.sh.backup diff --git a/.githooks/README.md b/.githooks/README.md index 1fb3bb0..bd9e517 100644 --- a/.githooks/README.md +++ b/.githooks/README.md @@ -1,6 +1,6 @@ -# Git Hooks for DanceLessonsCoach +# Git Hooks for dance-lessons-coach -This directory contains Git hooks for the DanceLessonsCoach project. +This directory contains Git hooks for the dance-lessons-coach project. ## Available Hooks diff --git a/.gitignore b/.gitignore index c00512d..705ae24 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ pkg/server/docs/ # CI/CD runner configuration config/runner .runner +coverage.txt +trigger.txt +test_trigger.txt diff --git a/.yamllint.yaml b/.yamllint.yaml index e22ffae..e27d995 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -1,4 +1,4 @@ -# DanceLessonsCoach YAML Lint Configuration +# dance-lessons-coach YAML Lint Configuration # More practical limits for CI/CD workflow files extends: default diff --git a/AGENTS.md b/AGENTS.md index debf14d..827bf7e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,10 +1,10 @@ -# DanceLessonsCoach - AI Agent Documentation +# dance-lessons-coach - AI Agent Documentation -This file documents the AI agents, tools, and development workflow for the DanceLessonsCoach project. +This file documents the AI agents, tools, and development workflow for the dance-lessons-coach project. ## 🎯 Project Overview -**DanceLessonsCoach** is a Go-based web service with CLI capabilities, featuring: +**dance-lessons-coach** is a Go-based web service with CLI capabilities, featuring: - RESTful JSON API with Chi router - High-performance Zerolog logging - Interface-based architecture @@ -94,7 +94,7 @@ This file documents the AI agents, tools, and development workflow for the Dance ## πŸ—ΊοΈ Project Structure ``` -DanceLessonsCoach/ +dance-lessons-coach/ β”œβ”€β”€ adr/ # Architecture Decision Records β”‚ β”œβ”€β”€ README.md # ADR guidelines and index β”‚ β”œβ”€β”€ 0001-go-1.26.1-standard.md @@ -138,7 +138,7 @@ DanceLessonsCoach/ ### New Cobra CLI (Recommended) -DanceLessonsCoach now includes a modern CLI built with Cobra framework: +dance-lessons-coach now includes a modern CLI built with Cobra framework: ```bash # Show help and available commands @@ -156,7 +156,7 @@ DanceLessonsCoach now includes a modern CLI built with Cobra framework: **Available Commands:** - `version` - Print version information -- `server` - Start the DanceLessonsCoach server +- `server` - Start the dance-lessons-coach server - `greet [name]` - Greet someone by name - `help` - Built-in help system - `completion` - Generate shell completion scripts @@ -178,7 +178,7 @@ The server provides runtime version information: ./bin/server --version # Output: -DanceLessonsCoach Version Information: +dance-lessons-coach Version Information: Version: 1.0.0 Commit: abc1234 Built: 2026-04-05T10:00:00+0000 @@ -191,7 +191,7 @@ A convenient shell script is provided for managing the server lifecycle: ```bash # Navigate to project directory -cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach +cd /Users/gabrielradureau/Work/Vibe/dance-lessons-coach # Start the server ./scripts/start-server.sh start @@ -223,7 +223,7 @@ If you prefer manual control: ```bash # Navigate to project directory -cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach +cd /Users/gabrielradureau/Work/Vibe/dance-lessons-coach # Run server in background using control script ./scripts/start-server.sh start @@ -535,7 +535,7 @@ Enable OpenTelemetry in your `config.yaml`: telemetry: enabled: true otlp_endpoint: "localhost:4317" - service_name: "DanceLessonsCoach" + service_name: "dance-lessons-coach" insecure: true sampler: type: "parentbased_always_on" @@ -547,7 +547,7 @@ Or via environment variables: ```bash export DLC_TELEMETRY_ENABLED=true export DLC_TELEMETRY_OTLP_ENDPOINT="localhost:4317" -export DLC_TELEMETRY_SERVICE_NAME="DanceLessonsCoach" +export DLC_TELEMETRY_SERVICE_NAME="dance-lessons-coach" export DLC_TELEMETRY_INSECURE=true export DLC_TELEMETRY_SAMPLER_TYPE="parentbased_always_on" export DLC_TELEMETRY_SAMPLER_RATIO=1.0 @@ -579,7 +579,7 @@ curl http://localhost:8080/api/v1/greet/John ``` 4. **View traces in Jaeger UI:** -Open http://localhost:16686 and select the "DanceLessonsCoach" service. +Open http://localhost:16686 and select the "dance-lessons-coach" service. ### Sampler Types @@ -613,7 +613,7 @@ curl -s http://localhost:8080/api/health ### 2. Start Development Server ```bash -cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach +cd /Users/gabrielradureau/Work/Vibe/dance-lessons-coach ./scripts/start-server.sh start ``` @@ -927,7 +927,7 @@ defer cancel() ## πŸ“¦ Version Management -DanceLessonsCoach uses a comprehensive version management system based on Semantic Versioning 2.0.0. +dance-lessons-coach uses a comprehensive version management system based on Semantic Versioning 2.0.0. ### Version Information @@ -990,9 +990,9 @@ curl http://localhost:8080/api/version # Release build go build -o bin/server \ -ldflags="\ - -X 'DanceLessonsCoach/pkg/version.Version=1.0.0' \ - -X 'DanceLessonsCoach/pkg/version.Commit=$(git rev-parse --short HEAD)' \ - -X 'DanceLessonsCoach/pkg/version.Date=$(date +%Y-%m-%dT%H:%M:%S%z)' \ + -X 'dance-lessons-coach/pkg/version.Version=1.0.0' \ + -X 'dance-lessons-coach/pkg/version.Commit=$(git rev-parse --short HEAD)' \ + -X 'dance-lessons-coach/pkg/version.Date=$(date +%Y-%m-%dT%H:%M:%S%z)' \ " \ ./cmd/server ``` @@ -1034,7 +1034,7 @@ The `pkg/version` package provides runtime access to version information: package main import ( - "DanceLessonsCoach/pkg/version" + "dance-lessons-coach/pkg/version" "fmt" ) @@ -1267,7 +1267,7 @@ For issues or questions: 4. Consult Go and Chi documentation 5. Ask the AI agent for guidance -This documentation provides a complete guide to developing, testing, and maintaining the DanceLessonsCoach project using the established patterns and best practices. +This documentation provides a complete guide to developing, testing, and maintaining the dance-lessons-coach project using the established patterns and best practices. ## πŸ“‹ BDD Feature Structure All user stories and BDD features follow the structure defined in ADR-0019: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c15ed6..c20c78b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to DanceLessonsCoach +# Contributing to dance-lessons-coach -Thank you for your interest in contributing to DanceLessonsCoach! This guide will help you set up your development environment and understand our contribution process. +Thank you for your interest in contributing to dance-lessons-coach! This guide will help you set up your development environment and understand our contribution process. ## πŸ“‹ Table of Contents @@ -24,8 +24,8 @@ Thank you for your interest in contributing to DanceLessonsCoach! This guide wil ```bash # Clone the repository -git clone https://gitea.arcodange.lab/arcodange/DanceLessonsCoach.git -cd DanceLessonsCoach +git clone https://gitea.arcodange.lab/arcodange/dance-lessons-coach.git +cd dance-lessons-coach # Install dependencies go mod tidy @@ -260,7 +260,7 @@ Major architectural decisions are documented in the `adr/` directory. Please rev ## πŸ€– AI Agent Contributions -AI agents play a crucial role in maintaining and improving DanceLessonsCoach. This section provides guidance for AI agents on how to effectively contribute. +AI agents play a crucial role in maintaining and improving dance-lessons-coach. This section provides guidance for AI agents on how to effectively contribute. ### Key Files and Directories @@ -342,7 +342,7 @@ AI agents play a crucial role in maintaining and improving DanceLessonsCoach. Th ## πŸ“œ License -By contributing to DanceLessonsCoach, you agree that your contributions will be licensed under the MIT License. +By contributing to dance-lessons-coach, you agree that your contributions will be licensed under the MIT License. --- @@ -350,7 +350,7 @@ By contributing to DanceLessonsCoach, you agree that your contributions will be ======= ## πŸ€– AI Agent Contributions -AI agents play a crucial role in maintaining and improving DanceLessonsCoach. This section provides guidance for AI agents on how to effectively contribute. +AI agents play a crucial role in maintaining and improving dance-lessons-coach. This section provides guidance for AI agents on how to effectively contribute. ### Key Files and Directories @@ -432,7 +432,7 @@ AI agents play a crucial role in maintaining and improving DanceLessonsCoach. Th ## πŸ“œ License -By contributing to DanceLessonsCoach, you agree that your contributions will be licensed under the MIT License. +By contributing to dance-lessons-coach, you agree that your contributions will be licensed under the MIT License. --- diff --git a/README.md b/README.md index 69fc910..d94909f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ -# DanceLessonsCoach +# dance-lessons-coach -[![Build Status](https://gitea.arcodange.fr/api/badges/arcodange/DanceLessonsCoach/status)](https://gitea.arcodange.fr/arcodange/DanceLessonsCoach) -[![Go Report Card](https://goreportcard.com/badge/github.com/arcodange/DanceLessonsCoach)](https://goreportcard.com/report/github.com/arcodange/DanceLessonsCoach) -[![Version](https://img.shields.io/badge/version-1.4.0-blue.svg)](https://gitea.arcodange.fr/arcodange/DanceLessonsCoach/releases) +[![Build Status](https://gitea.arcodange.fr/api/badges/arcodange/dance-lessons-coach/status)](https://gitea.arcodange.fr/arcodange/dance-lessons-coach) +[![Go Report Card](https://goreportcard.com/badge/github.com/arcodange/dance-lessons-coach)](https://goreportcard.com/report/github.com/arcodange/dance-lessons-coach) +[![Version](https://img.shields.io/badge/version-1.4.0-blue.svg)](https://gitea.arcodange.fr/arcodange/dance-lessons-coach/releases) [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) +[![BDD Coverage](https://img.shields.io/badge/BDD_Coverage-55.9%-yellow?style=flat-square)](https://gitea.arcodange.lab/arcodange/dance-lessons-coach) +[![Unit Coverage](https://img.shields.io/badge/Unit_Coverage-8.4%-red?style=flat-square)](https://gitea.arcodange.lab/arcodange/dance-lessons-coach) A Go project demonstrating idiomatic package structure, CLI implementation, and JSON API with Chi router. ======= @@ -42,11 +44,69 @@ go run ./cmd/greet ## CI/CD Pipeline -DanceLessonsCoach includes a portable CI/CD pipeline using GitHub Actions syntax: +dance-lessons-coach features an optimized CI/CD pipeline using GitHub Actions with container/services architecture: -### Features -- βœ… **Multi-platform**: Works on Gitea, GitHub, and GitLab -- βœ… **Build & Test**: Automated Go builds and tests +### Key Features +- βœ… **Container-based execution**: All steps run in pre-built Docker cache images +- βœ… **Service-based PostgreSQL**: Automatic database service provisioning +- βœ… **Smart caching**: Dependency-aware cache invalidation +- βœ… **Multi-platform**: Compatible with Gitea, GitHub, and GitLab +- βœ… **Fast execution**: No Docker Compose overhead +- βœ… **Reliable testing**: Full database connectivity with proper environment setup + +### Architecture + +The pipeline uses GitHub Actions' native `container` and `services` directives instead of Docker Compose: + +```yaml +jobs: + ci-pipeline: + container: + image: gitea.arcodange.lab/arcodange/dance-lessons-coach-build-cache:${{ needs.build-cache.outputs.deps_hash }} + + services: + postgres: + image: postgres:15 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: dance_lessons_coach_bdd_test +``` + +### Benefits + +1. **Performance**: Direct container execution without compose overhead +2. **Reliability**: Service containers managed by GitHub Actions +3. **Simplicity**: Cleaner workflow definition +4. **Portability**: Works across CI platforms +5. **Caching**: Intelligent dependency-based cache rebuilding + +### Workflow Steps + +1. **Build Cache**: Creates Docker image with Go tools and dependencies +2. **CI Pipeline**: Runs tests, builds binaries, and generates documentation +3. **Database Tests**: Connects to PostgreSQL service container +4. **Coverage Reporting**: Updates coverage badges automatically +5. **Artifact Publishing**: Builds and pushes Docker images (main branch only) + +### Environment Configuration + +The pipeline automatically sets up database environment variables: + +```bash +echo "DLC_DATABASE_HOST=postgres" >> $GITHUB_ENV +echo "DLC_DATABASE_PORT=5432" >> $GITHUB_ENV +echo "DLC_DATABASE_USER=postgres" >> $GITHUB_ENV +echo "DLC_DATABASE_PASSWORD=postgres" >> $GITHUB_ENV +echo "DLC_DATABASE_NAME=dance_lessons_coach_bdd_test" >> $GITHUB_ENV +echo "DLC_DATABASE_SSL_MODE=disable" >> $GITHUB_ENV +``` + +### Status + +[![Build Status](https://gitea.arcodange.fr/api/badges/arcodange/dance-lessons-coach/status)](https://gitea.arcodange.fr/arcodange/dance-lessons-coach) + +======= - βœ… **Linting**: Code quality checks with `go fmt` and `go vet` - βœ… **Version Management**: Automatic version detection - βœ… **Portable**: Uses standard GitHub Actions workflow format @@ -184,7 +244,7 @@ go test ./pkg/greet/ ## CI/CD -DanceLessonsCoach includes a comprehensive CI/CD pipeline with multiple testing options: +dance-lessons-coach includes a comprehensive CI/CD pipeline with multiple testing options: ### Local Testing (No Gitea Required) ```bash @@ -215,7 +275,7 @@ DanceLessonsCoach includes a comprehensive CI/CD pipeline with multiple testing ## Project Structure ``` -DanceLessonsCoach/ +dance-lessons-coach/ β”œβ”€β”€ adr/ # Architecture Decision Records β”œβ”€β”€ cmd/ # Entry points (greet CLI, server) β”œβ”€β”€ pkg/ # Core packages (config, greet, server, telemetry) @@ -273,7 +333,7 @@ This project uses Architecture Decision Records (ADRs) to document key technical ## Gitea Integration -DanceLessonsCoach includes AI agent skills for Gitea integration to monitor CI/CD jobs and interact with pull requests. +dance-lessons-coach includes AI agent skills for Gitea integration to monitor CI/CD jobs and interact with pull requests. ### Gitea Client Skill Setup diff --git a/VERSION b/VERSION index 672e2ba..09e2510 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ -# DanceLessonsCoach Version +# dance-lessons-coach Version # Current Version (Semantic Versioning) MAJOR=1 diff --git a/documentation/AGENT_USAGE_GUIDE.md b/documentation/AGENT_USAGE_GUIDE.md index 0bac1e1..f5c2b0b 100644 --- a/documentation/AGENT_USAGE_GUIDE.md +++ b/documentation/AGENT_USAGE_GUIDE.md @@ -1,16 +1,16 @@ -# DanceLessonsCoach Agent Usage Guide +# dance-lessons-coach Agent Usage Guide ## πŸš€ Quick Start ### Launch Programmer Agent ```bash -cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach +cd /Users/gabrielradureau/Work/Vibe/dance-lessons-coach vibe start --agent dancelessonscoachprogrammer ``` ### Launch Product Owner Agent ```bash -cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach +cd /Users/gabrielradureau/Work/Vibe/dance-lessons-coach vibe start --agent dancelessonscoach-product-owner ``` @@ -141,7 +141,7 @@ skill changelog-manager add-entry \ ```toml # .mistral/dancelessonscoachprogrammer-agent.toml name: dancelessonscoachprogrammer -role: DanceLessonsCoachProgrammer +role: dance-lessons-coach-programmer goals: ["Follow BDD practices", "Use Gitmoji commits", "Respect ADR process"] ``` @@ -149,7 +149,7 @@ goals: ["Follow BDD practices", "Use Gitmoji commits", "Respect ADR process"] ```toml # .mistral/dancelessonscoach-product-owner-agent.toml name: dancelessonscoach-product-owner -role: DanceLessonsCoachProductOwner +role: dance-lessons-coach-product-owner goals: ["Facilitate stakeholder interviews", "Generate BDD tests", "Maintain documentation"] ``` @@ -210,7 +210,7 @@ vibe validate --agent dancelessonscoach-product-owner ```bash # List available skills ls /Users/gabrielradureau/Work/Vibe/.mistral/skills/ -ls /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach/.vibe/skills/ +ls /Users/gabrielradureau/Work/Vibe/dance-lessons-coach/.vibe/skills/ # Validate skill skill skill-creator validate .vibe/skills/product-owner-assistant @@ -222,7 +222,7 @@ skill skill-creator validate .mistral/skills/interview-facilitator ```bash # Check file permissions chmod +x /Users/gabrielradureau/Work/Vibe/.mistral/skills/*/scripts/* -chmod +x /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach/.vibe/skills/*/scripts/* +chmod +x /Users/gabrielradureau/Work/Vibe/dance-lessons-coach/.vibe/skills/*/scripts/* ``` ## πŸ“– Related Documentation diff --git a/documentation/BDD_GUIDE.md b/documentation/BDD_GUIDE.md index d9354d3..5535657 100644 --- a/documentation/BDD_GUIDE.md +++ b/documentation/BDD_GUIDE.md @@ -1,6 +1,6 @@ -# BDD Testing Guide for DanceLessonsCoach +# BDD Testing Guide for dance-lessons-coach -This guide explains how to work with BDD tests using Godog in the DanceLessonsCoach project. +This guide explains how to work with BDD tests using Godog in the dance-lessons-coach project. ## Installation @@ -33,7 +33,7 @@ The project already includes Godog as a dependency in `go.mod`. The BDD tests ar ```bash # From project root -cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach +cd /Users/gabrielradureau/Work/Vibe/dance-lessons-coach go test ./features/... -v ``` @@ -112,7 +112,7 @@ Create a corresponding step definition file in `pkg/bdd/steps/`: package steps import ( - "DanceLessonsCoach/pkg/bdd/testserver" + "dance-lessons-coach/pkg/bdd/testserver" "github.com/cucumber/godog" ) @@ -213,7 +213,7 @@ Add BDD tests to your CI pipeline: ## Modern Go Testing Practices -The DanceLessonsCoach project follows modern Go testing practices: +The dance-lessons-coach project follows modern Go testing practices: 1. **Standard library integration**: BDD tests use `go test` 2. **No global installation required**: Godog is a Go module dependency diff --git a/documentation/local-ci-cd-testing.md b/documentation/local-ci-cd-testing.md index ce3baf4..95b8963 100644 --- a/documentation/local-ci-cd-testing.md +++ b/documentation/local-ci-cd-testing.md @@ -69,7 +69,7 @@ This workflow can be triggered manually or on test/feature branches. ### 1. Run the Interactive Script ```bash -cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach +cd /Users/gabrielradureau/Work/Vibe/dance-lessons-coach ./scripts/test-local-ci-cd.sh ``` diff --git a/documentation/version-management-guide.md b/documentation/version-management-guide.md index b71576b..fb1504f 100644 --- a/documentation/version-management-guide.md +++ b/documentation/version-management-guide.md @@ -1,6 +1,6 @@ # Version Management Guide -This guide provides comprehensive instructions for managing versions in the DanceLessonsCoach project. +This guide provides comprehensive instructions for managing versions in the dance-lessons-coach project. ## πŸ“‹ Table of Contents @@ -13,7 +13,7 @@ This guide provides comprehensive instructions for managing versions in the Danc ## πŸ“– Semantic Versioning -DanceLessonsCoach follows [Semantic Versioning 2.0.0](https://semver.org/): +dance-lessons-coach follows [Semantic Versioning 2.0.0](https://semver.org/): ### Version Format: `MAJOR.MINOR.PATCH-PRERELEASE` @@ -360,6 +360,6 @@ git push origin v1.0.1 --- -**Maintained by:** DanceLessonsCoach Team +**Maintained by:** dance-lessons-coach Team **Last Updated:** 2026-04-05 **Version:** 1.0 \ No newline at end of file diff --git a/pkg/config/config.go b/pkg/config/config.go index aa02a88..5db803a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -13,6 +13,11 @@ import ( "dance-lessons-coach/pkg/version" ) +// NewZerologWriter creates a zerolog writer based on configuration +func NewZerologWriter() *os.File { + return os.Stderr +} + // Config represents the application configuration type Config struct { Server ServerConfig `mapstructure:"server"` @@ -20,6 +25,8 @@ type Config struct { Logging LoggingConfig `mapstructure:"logging"` Telemetry TelemetryConfig `mapstructure:"telemetry"` API APIConfig `mapstructure:"api"` + Auth AuthConfig `mapstructure:"auth"` + Database DatabaseConfig `mapstructure:"database"` } // ServerConfig holds server-related configuration @@ -42,11 +49,17 @@ type LoggingConfig struct { // TelemetryConfig holds OpenTelemetry-related configuration type TelemetryConfig struct { - Enabled bool `mapstructure:"enabled"` - OTLPEndpoint string `mapstructure:"otlp_endpoint"` - ServiceName string `mapstructure:"service_name"` - Insecure bool `mapstructure:"insecure"` - Sampler SamplerConfig `mapstructure:"sampler"` + Enabled bool `mapstructure:"enabled"` + OTLPEndpoint string `mapstructure:"otlp_endpoint"` + ServiceName string `mapstructure:"service_name"` + Insecure bool `mapstructure:"insecure"` + Sampler SamplerConfig `mapstructure:"sampler"` + Persistence PersistenceTelemetryConfig `mapstructure:"persistence"` +} + +// PersistenceTelemetryConfig holds persistence layer telemetry configuration +type PersistenceTelemetryConfig struct { + Enabled bool `mapstructure:"enabled"` } // APIConfig holds API version configuration @@ -54,6 +67,25 @@ type APIConfig struct { V2Enabled bool `mapstructure:"v2_enabled"` } +// AuthConfig holds authentication configuration +type AuthConfig struct { + JWTSecret string `mapstructure:"jwt_secret"` + AdminMasterPassword string `mapstructure:"admin_master_password"` +} + +// DatabaseConfig holds database configuration +type DatabaseConfig struct { + Host string `mapstructure:"host"` + Port int `mapstructure:"port"` + User string `mapstructure:"user"` + Password string `mapstructure:"password"` + Name string `mapstructure:"name"` + SSLMode string `mapstructure:"ssl_mode"` + MaxOpenConns int `mapstructure:"max_open_conns"` + MaxIdleConns int `mapstructure:"max_idle_conns"` + ConnMaxLifetime time.Duration `mapstructure:"conn_max_lifetime"` +} + // VersionInfo holds application version information type VersionInfo struct { Version string `mapstructure:"-"` // Set via ldflags @@ -65,7 +97,7 @@ type VersionInfo struct { // VersionCommand handles version display func (c *Config) VersionCommand() string { // This will be enhanced when we integrate with cobra - return fmt.Sprintf("DanceLessonsCoach %s (commit: %s, built: %s, go: %s)", + return fmt.Sprintf("dance-lessons-coach %s (commit: %s, built: %s, go: %s)", version.Version, version.Commit, version.Date, version.GoVersion) } @@ -96,14 +128,19 @@ func LoadConfig() (*Config, error) { // Telemetry defaults v.SetDefault("telemetry.enabled", false) v.SetDefault("telemetry.otlp_endpoint", "localhost:4317") - v.SetDefault("telemetry.service_name", "DanceLessonsCoach") + v.SetDefault("telemetry.service_name", "dance-lessons-coach") v.SetDefault("telemetry.insecure", true) v.SetDefault("telemetry.sampler.type", "parentbased_always_on") v.SetDefault("telemetry.sampler.ratio", 1.0) + v.SetDefault("telemetry.persistence.enabled", false) // API defaults v.SetDefault("api.v2_enabled", false) + // Auth defaults + v.SetDefault("auth.jwt_secret", "default-secret-key-please-change-in-production") + v.SetDefault("auth.admin_master_password", "admin123") + // Check for custom config file path via environment variable if configFile := os.Getenv("DLC_CONFIG_FILE"); configFile != "" { v.SetConfigFile(configFile) @@ -128,7 +165,7 @@ func LoadConfig() (*Config, error) { // Bind environment variables v.AutomaticEnv() - v.SetEnvPrefix("DLC") // DanceLessonsCoach prefix + v.SetEnvPrefix("DLC") // dance-lessons-coach prefix v.BindEnv("server.host", "DLC_SERVER_HOST") v.BindEnv("server.port", "DLC_SERVER_PORT") v.BindEnv("shutdown.timeout", "DLC_SHUTDOWN_TIMEOUT") @@ -141,12 +178,24 @@ func LoadConfig() (*Config, error) { v.BindEnv("telemetry.otlp_endpoint", "DLC_TELEMETRY_OTLP_ENDPOINT") v.BindEnv("telemetry.service_name", "DLC_TELEMETRY_SERVICE_NAME") v.BindEnv("telemetry.insecure", "DLC_TELEMETRY_INSECURE") + + // Auth environment variables + v.BindEnv("auth.jwt_secret", "DLC_AUTH_JWT_SECRET") + v.BindEnv("auth.admin_master_password", "DLC_AUTH_ADMIN_MASTER_PASSWORD") v.BindEnv("telemetry.sampler.type", "DLC_TELEMETRY_SAMPLER_TYPE") v.BindEnv("telemetry.sampler.ratio", "DLC_TELEMETRY_SAMPLER_RATIO") // API environment variables v.BindEnv("api.v2_enabled", "DLC_API_V2_ENABLED") + // Database environment variables + v.BindEnv("database.host", "DLC_DATABASE_HOST") + v.BindEnv("database.port", "DLC_DATABASE_PORT") + v.BindEnv("database.user", "DLC_DATABASE_USER") + v.BindEnv("database.password", "DLC_DATABASE_PASSWORD") + v.BindEnv("database.name", "DLC_DATABASE_NAME") + v.BindEnv("database.ssl_mode", "DLC_DATABASE_SSL_MODE") + // Unmarshal into Config struct var config Config if err := v.Unmarshal(&config); err != nil { @@ -200,6 +249,11 @@ func (c *Config) GetServiceName() string { return c.Telemetry.ServiceName } +// GetPersistenceTelemetryEnabled returns whether persistence layer telemetry is enabled +func (c *Config) GetPersistenceTelemetryEnabled() bool { + return c.Telemetry.Enabled && c.Telemetry.Persistence.Enabled +} + // GetTelemetryInsecure returns whether to use insecure connection func (c *Config) GetTelemetryInsecure() bool { return c.Telemetry.Insecure @@ -220,6 +274,21 @@ func (c *Config) GetV2Enabled() bool { return c.API.V2Enabled } +// GetJWTSecret returns the JWT secret +func (c *Config) GetJWTSecret() string { + return c.Auth.JWTSecret +} + +// GetAdminMasterPassword returns the admin master password +func (c *Config) GetAdminMasterPassword() string { + return c.Auth.AdminMasterPassword +} + +// GetLoggingJSON returns whether JSON logging is enabled +func (c *Config) GetLoggingJSON() bool { + return c.Logging.JSON +} + // GetLogLevel returns the logging level func (c *Config) GetLogLevel() string { return c.Logging.Level @@ -230,6 +299,75 @@ func (c *Config) GetLogOutput() string { return c.Logging.Output } +// GetDatabaseHost returns the database host +func (c *Config) GetDatabaseHost() string { + if c.Database.Host == "" { + return "localhost" + } + return c.Database.Host +} + +// GetDatabasePort returns the database port +func (c *Config) GetDatabasePort() int { + if c.Database.Port == 0 { + return 5432 + } + return c.Database.Port +} + +// GetDatabaseUser returns the database user +func (c *Config) GetDatabaseUser() string { + if c.Database.User == "" { + return "postgres" + } + return c.Database.User +} + +// GetDatabasePassword returns the database password +func (c *Config) GetDatabasePassword() string { + return c.Database.Password +} + +// GetDatabaseName returns the database name +func (c *Config) GetDatabaseName() string { + if c.Database.Name == "" { + return "dance_lessons_coach" + } + return c.Database.Name +} + +// GetDatabaseSSLMode returns the database SSL mode +func (c *Config) GetDatabaseSSLMode() string { + if c.Database.SSLMode == "" { + return "disable" + } + return c.Database.SSLMode +} + +// GetDatabaseMaxOpenConns returns the maximum number of open connections +func (c *Config) GetDatabaseMaxOpenConns() int { + if c.Database.MaxOpenConns == 0 { + return 25 + } + return c.Database.MaxOpenConns +} + +// GetDatabaseMaxIdleConns returns the maximum number of idle connections +func (c *Config) GetDatabaseMaxIdleConns() int { + if c.Database.MaxIdleConns == 0 { + return 5 + } + return c.Database.MaxIdleConns +} + +// GetDatabaseConnMaxLifetime returns the maximum lifetime of connections +func (c *Config) GetDatabaseConnMaxLifetime() time.Duration { + if c.Database.ConnMaxLifetime == 0 { + return time.Hour + } + return c.Database.ConnMaxLifetime +} + // SetupLogging configures zerolog based on the configuration func (c *Config) SetupLogging() { // Parse log level diff --git a/pkg/greet/api_v1.go b/pkg/greet/api_v1.go index 8ec441c..82f2e6b 100644 --- a/pkg/greet/api_v1.go +++ b/pkg/greet/api_v1.go @@ -88,6 +88,7 @@ func (h *apiV1GreetHandler) RegisterRoutes(router chi.Router) { // @Accept json // @Produce json // @Success 200 {object} GreetResponse "Successful response" +// @Security BearerAuth // @Router /v1/greet [get] func (h *apiV1GreetHandler) handleGreetQuery(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("name") @@ -104,6 +105,7 @@ func (h *apiV1GreetHandler) handleGreetQuery(w http.ResponseWriter, r *http.Requ // @Param name path string true "Name to greet" // @Success 200 {object} GreetResponse "Successful response" // @Failure 400 {object} ErrorResponse "Invalid name parameter" +// @Security BearerAuth // @Router /v1/greet/{name} [get] func (h *apiV1GreetHandler) handleGreetPath(w http.ResponseWriter, r *http.Request) { name := chi.URLParam(r, "name") diff --git a/pkg/greet/api_v2.go b/pkg/greet/api_v2.go index 105d470..76fbc7c 100644 --- a/pkg/greet/api_v2.go +++ b/pkg/greet/api_v2.go @@ -55,6 +55,7 @@ type greetResponse struct { // @Param request body GreetRequest true "Greeting request" // @Success 200 {object} GreetResponseV2 "Successful response" // @Failure 400 {object} ValidationError "Validation error" +// @Security BearerAuth // @Router /v2/greet [post] func (h *apiV2GreetHandler) handleGreetPost(w http.ResponseWriter, r *http.Request) { // Read request body diff --git a/pkg/greet/greet.go b/pkg/greet/greet.go index 2ca7ec4..54e6d0b 100644 --- a/pkg/greet/greet.go +++ b/pkg/greet/greet.go @@ -3,21 +3,46 @@ package greet import ( "context" + "dance-lessons-coach/pkg/user" + "github.com/rs/zerolog/log" ) +// Context key for storing authenticated user +type contextKey string + +const ( + // UserContextKey is the context key for storing authenticated user + UserContextKey contextKey = "authenticatedUser" +) + type Service struct{} func NewService() *Service { return &Service{} } +// GetAuthenticatedUserFromContext extracts the authenticated user from context +func GetAuthenticatedUserFromContext(ctx context.Context) (*user.User, bool) { + user, ok := ctx.Value(UserContextKey).(*user.User) + return user, ok +} + // Greet returns a greeting message for the given name. -// If name is empty, it defaults to "world". +// If name is empty, it checks for authenticated user and uses their username. +// If no authenticated user and no name, it defaults to "world". // Implements the Greeter interface. func (s *Service) Greet(ctx context.Context, name string) string { log.Trace().Ctx(ctx).Str("name", name).Msg("Greet function called") + // If no name provided, check for authenticated user + if name == "" { + if authenticatedUser, ok := GetAuthenticatedUserFromContext(ctx); ok { + name = authenticatedUser.Username + log.Trace().Ctx(ctx).Str("authenticated_user", name).Msg("Using authenticated username for greeting") + } + } + if name == "" { return "Hello world!" } diff --git a/pkg/server/server.go b/pkg/server/server.go index b462678..aa125e3 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -20,8 +20,11 @@ import ( "dance-lessons-coach/pkg/config" "dance-lessons-coach/pkg/greet" "dance-lessons-coach/pkg/telemetry" + "dance-lessons-coach/pkg/user" + userapi "dance-lessons-coach/pkg/user/api" "dance-lessons-coach/pkg/validation" "dance-lessons-coach/pkg/version" + "encoding/json" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -37,6 +40,8 @@ type Server struct { config *config.Config tracerProvider *sdktrace.TracerProvider validator *validation.Validator + userRepo user.UserRepository + userService user.UserService } func NewServer(cfg *config.Config, readyCtx context.Context) *Server { @@ -48,17 +53,46 @@ func NewServer(cfg *config.Config, readyCtx context.Context) *Server { log.Trace().Msg("Validator created successfully") } + // Initialize user repository and services + userRepo, userService, err := initializeUserServices(cfg) + if err != nil { + log.Warn().Err(err).Msg("Failed to initialize user services, user functionality will be disabled") + } + s := &Server{ - router: chi.NewRouter(), - readyCtx: readyCtx, - withOTEL: cfg.GetTelemetryEnabled(), - config: cfg, - validator: validator, + router: chi.NewRouter(), + readyCtx: readyCtx, + withOTEL: cfg.GetTelemetryEnabled(), + config: cfg, + validator: validator, + userRepo: userRepo, + userService: userService, } s.setupRoutes() return s } +// initializeUserServices initializes the user repository and unified user service +func initializeUserServices(cfg *config.Config) (user.UserRepository, user.UserService, error) { + // Create user repository using PostgreSQL + repo, err := user.NewPostgresRepository(cfg) + if err != nil { + return nil, nil, fmt.Errorf("failed to create PostgreSQL user repository: %w", err) + } + + // Create JWT config + jwtConfig := user.JWTConfig{ + Secret: cfg.GetJWTSecret(), + ExpirationTime: time.Hour * 24, // 24 hours + Issuer: "dance-lessons-coach", + } + + // Create unified user service + userService := user.NewUserService(repo, jwtConfig, cfg.GetAdminMasterPassword()) + + return repo, userService, nil +} + func (s *Server) setupRoutes() { // Use Zerolog middleware instead of Chi's default logger s.router.Use(middleware.RequestLogger(&middleware.DefaultLogFormatter{ @@ -109,9 +143,31 @@ func (s *Server) setupRoutes() { func (s *Server) registerApiV1Routes(r chi.Router) { greetService := greet.NewService() greetHandler := greet.NewApiV1GreetHandler(greetService) + + // Create auth middleware if available + var authMiddleware *AuthMiddleware + if s.userService != nil { + authMiddleware = NewAuthMiddleware(s.userService) + } + r.Route("/greet", func(r chi.Router) { + // Add optional authentication middleware + if authMiddleware != nil { + r.Use(authMiddleware.Middleware) + } greetHandler.RegisterRoutes(r) }) + + // Register user authentication routes + if s.userService != nil && s.userRepo != nil { + // Use unified user service - much simpler! + if s.userService != nil { + handler := userapi.NewAuthHandler(s.userService, s.userService, s.validator) + r.Route("/auth", func(r chi.Router) { + handler.RegisterRoutes(r) + }) + } + } } func (s *Server) registerApiV2Routes(r chi.Router) { @@ -155,24 +211,75 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { // handleReadiness godoc // // @Summary Readiness check -// @Description Check if the service is ready to accept traffic +// @Description Check if the service is ready to accept traffic including detailed connection status // @Tags System/Health // @Accept json // @Produce json -// @Success 200 {object} map[string]bool "Service is ready" -// @Failure 503 {object} map[string]bool "Service is not ready" +// @Success 200 {object} object "Service is ready with connection details" +// @Failure 503 {object} object "Service is not ready with failure details" // @Router /ready [get] func (s *Server) handleReadiness(w http.ResponseWriter, r *http.Request) { log.Trace().Msg("Readiness check requested") + // Check if server is shutting down select { case <-s.readyCtx.Done(): log.Trace().Msg("Readiness check: not ready (shutting down)") + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusServiceUnavailable) - w.Write([]byte(`{"ready":false}`)) + json.NewEncoder(w).Encode(map[string]interface{}{ + "ready": false, + "reason": "server_shutting_down", + "connections": map[string]interface{}{ + "database": "not_checked", + }, + }) + return default: - log.Trace().Msg("Readiness check: ready") - w.Write([]byte(`{"ready":true}`)) + // Server is not shutting down, check all connections + connectionStatus := make(map[string]interface{}) + allHealthy := true + var failureReason string + + // Check database if available + if s.userRepo != nil { + if err := s.userRepo.CheckDatabaseHealth(r.Context()); err != nil { + log.Warn().Err(err).Msg("Database health check failed") + connectionStatus["database"] = map[string]interface{}{ + "status": "unhealthy", + "error": err.Error(), + } + allHealthy = false + failureReason = "database_unhealthy" + } else { + connectionStatus["database"] = map[string]interface{}{ + "status": "healthy", + } + } + } else { + connectionStatus["database"] = map[string]interface{}{ + "status": "not_configured", + } + } + + if allHealthy { + log.Trace().Msg("Readiness check: ready") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]interface{}{ + "ready": true, + "connections": connectionStatus, + }) + } else { + log.Warn().Str("reason", failureReason).Msg("Readiness check: not ready") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusServiceUnavailable) + json.NewEncoder(w).Encode(map[string]interface{}{ + "ready": false, + "reason": failureReason, + "connections": connectionStatus, + }) + } } } diff --git a/pkg/telemetry/telemetry.go b/pkg/telemetry/telemetry.go index 4288523..d77bcd3 100644 --- a/pkg/telemetry/telemetry.go +++ b/pkg/telemetry/telemetry.go @@ -1,4 +1,4 @@ -// Package telemetry provides OpenTelemetry instrumentation for the DanceLessonsCoach application +// Package telemetry provides OpenTelemetry instrumentation for the dance-lessons-coach application package telemetry import ( diff --git a/pkg/version/version.go b/pkg/version/version.go index e3c8b0a..6d177c4 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,4 +1,4 @@ -// Package version provides version information and management for DanceLessonsCoach +// Package version provides version information and management for dance-lessons-coach package version import ( @@ -91,7 +91,7 @@ func getBuildDate() { // Info returns formatted version information func Info() string { - return fmt.Sprintf("DanceLessonsCoach %s (commit: %s, built: %s UTC, go: %s)", Version, Commit, Date, GoVersion) + return fmt.Sprintf("dance-lessons-coach %s (commit: %s, built: %s UTC, go: %s)", Version, Commit, Date, GoVersion) } // Short returns just the version number @@ -101,7 +101,7 @@ func Short() string { // Full returns detailed version information func Full() string { - return fmt.Sprintf(`DanceLessonsCoach Version Information: + return fmt.Sprintf(`dance-lessons-coach Version Information: Version: %s Commit: %s Built: %s (UTC) diff --git a/scripts/LOCAL_CI_GUIDE.md b/scripts/LOCAL_CI_GUIDE.md new file mode 100644 index 0000000..a84ed74 --- /dev/null +++ b/scripts/LOCAL_CI_GUIDE.md @@ -0,0 +1,215 @@ +# Local CI/CD Testing Guide + +This guide explains how to test the CI/CD pipeline locally using the available scripts. + +## πŸ“ Available Scripts + +### Core CI Scripts +- `test-local-ci-cd.sh` - Complete local CI/CD simulation +- `test-docker-cache.sh` - Test Docker build cache functionality +- `ci-update-coverage-badge.sh` - Test coverage badge updates +- `ci-version-bump.sh` - Test version bump logic + +### Existing Test Scripts +- `run-bdd-tests.sh` - Run BDD tests locally +- `test-graceful-shutdown.sh` - Test graceful shutdown +- `test-opentelemetry.sh` - Test OpenTelemetry integration + +## πŸš€ Quick Start + +### 1. Test Docker Build Cache +```bash +# Test the Docker cache functionality +./scripts/test-docker-cache.sh + +# This will: +# 1. Calculate dependency hash (same as CI) +# 2. Build Docker cache image +# 3. Test commands in Docker +# 4. Compare performance +``` + +### 2. Full Local CI/CD Test +```bash +# Run complete local CI/CD simulation +./scripts/test-local-ci-cd.sh + +# This will: +# 1. Install dependencies +# 2. Generate Swagger docs +# 3. Build and test code +# 4. Build binaries +# 5. Simulate version bump +# 6. Optionally build Docker image +``` + +### 3. Test Specific Components + +#### Coverage Badge Updates +```bash +# Test coverage badge update logic +./scripts/ci-update-coverage-badge.sh 75.5 +``` + +#### Version Bump Logic +```bash +# Test version bump with different commit messages +./scripts/ci-version-bump.sh "✨ feat: add new feature" +./scripts/ci-version-bump.sh "πŸ› fix: resolve bug" +./scripts/ci-version-bump.sh "Regular commit message" +``` + +## 🐳 Docker Build Cache Testing + +The Docker build cache system works by: + +1. **Calculating dependency hash**: `sha256sum go.mod go.sum` +2. **Building cache image**: Only when dependencies change +3. **Using cached image**: For all subsequent CI runs + +### Local Testing +```bash +# Build the cache image locally +docker build -t dance-lessons-coach-build-cache -f Dockerfile.build . + +# Test running commands in the cached environment +docker run --rm -v "$(pwd):/workspace" -w /workspace \ + dance-lessons-coach-build-cache \ + go test ./... -cover +``` + +### CI Integration +The CI workflow automatically: +- Calculates the same hash +- Checks if image exists in registry +- Builds new image only when needed +- Uses cached image for all builds + +## πŸ”„ CI/CD Workflow Simulation + +To simulate the full CI/CD workflow locally: + +```bash +# 1. Run local CI tests +./scripts/test-local-ci-cd.sh + +# 2. When prompted, build Docker image +# 3. Test the running container +# 4. Verify all endpoints work + +# 5. Test BDD scenarios +./scripts/run-bdd-tests.sh + +# 6. Test graceful shutdown +./scripts/test-graceful-shutdown.sh + +# 7. Test OpenTelemetry +./scripts/test-opentelemetry.sh +``` + +## πŸ“Š Performance Comparison + +### Without Docker Cache +``` +First run: ~90 seconds +Subsequent: ~90 seconds (no caching) +``` + +### With Docker Cache +``` +First run: ~120 seconds (build cache) +Subsequent: ~30 seconds (use cache) +Savings: ~60 seconds per run! +``` + +## 🎯 Best Practices + +1. **Test locally first**: Always run `test-local-ci-cd.sh` before pushing +2. **Check Docker cache**: Run `test-docker-cache.sh` after dependency changes +3. **Verify coverage**: Test coverage badge updates with different percentages +4. **Test version bumps**: Verify version logic with different commit types +5. **Clean up**: Remove test containers and images when done + +## πŸ§ͺ Advanced Testing + +### Test Race Conditions +```bash +# Simulate concurrent CI runs +./scripts/ci-update-coverage-badge.sh 75.5 & +./scripts/ci-update-coverage-badge.sh 75.5 & +wait +``` + +### Test Version Bump Scenarios +```bash +# Test all version bump scenarios +echo "✨ feat: new feature" > /tmp/test_commit +./scripts/ci-version-bump.sh "$(cat /tmp/test_commit)" + +echo "πŸ› fix: bug fix" > /tmp/test_commit +./scripts/ci-version-bump.sh "$(cat /tmp/test_commit)" + +echo "BREAKING CHANGE: major update" > /tmp/test_commit +./scripts/ci-version-bump.sh "$(cat /tmp/test_commit)" +``` + +## πŸ”§ Troubleshooting + +### Docker Issues +- **Permission denied**: Add user to docker group or use `sudo` +- **Port conflicts**: Change test port or stop conflicting services +- **Image not found**: Build the image first with `docker build` + +### CI Script Issues +- **Missing dependencies**: Install required tools (Go, Docker, etc.) +- **Script permissions**: Run `chmod +x scripts/*.sh` +- **Path issues**: Use full paths or correct working directory + +### Performance Issues +- **Slow Docker builds**: Use `--no-cache` for fresh builds +- **Large images**: Check Dockerfile for unnecessary layers +- **Memory issues**: Increase Docker resources in settings + +## πŸ“– Reference + +### Docker Commands +```bash +# List images +docker images + +# List containers +docker ps -a + +# Remove container +docker rm + +# Remove image +docker rmi + +# View logs +docker logs + +# Exec into container +docker exec -it sh +``` + +### CI Commands +```bash +# Run specific CI job +act -j + +# Test workflow locally +act + +# Dry run (show what would run) +act -n +``` + +## πŸŽ“ Learning Resources + +- [Docker Documentation](https://docs.docker.com/) +- [GitHub Actions Documentation](https://docs.github.com/en/actions) +- [Go Testing Documentation](https://pkg.go.dev/testing) +- [CI/CD Best Practices](https://github.com/goldbergyoni/nodebestpractices) + +This guide provides everything you need to test the CI/CD pipeline locally before pushing to the repository! \ No newline at end of file diff --git a/scripts/README.md b/scripts/README.md index 76f657f..566bba9 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,6 +1,6 @@ -# DanceLessonsCoach Scripts +# dance-lessons-coach Scripts -This directory contains automation and management scripts for the DanceLessonsCoach project. +This directory contains automation and management scripts for the dance-lessons-coach project. ## πŸ“ Script Categories @@ -22,7 +22,7 @@ This directory contains automation and management scripts for the DanceLessonsCo ### 1. Server Management (`start-server.sh`) -**Manage the DanceLessonsCoach server lifecycle** +**Manage the dance-lessons-coach server lifecycle** ```bash # Start the server @@ -301,13 +301,13 @@ exit 0 - [Git SCM](https://git-scm.com/) - [Go Build](https://golang.org/cmd/go/) -### DanceLessonsCoach Specific +### dance-lessons-coach Specific - [ADR 0014: Version Management](adr/0014-version-management-lifecycle.md) - [AGENTS.md Scripts Section](#-scripts) - [Contributing Guide](CONTRIBUTING.md) --- -**Maintained by:** DanceLessonsCoach Team +**Maintained by:** dance-lessons-coach Team **License:** MIT **Status:** Actively developed \ No newline at end of file diff --git a/scripts/build-with-version.sh b/scripts/build-with-version.sh index db1b47b..2cdd7b5 100755 --- a/scripts/build-with-version.sh +++ b/scripts/build-with-version.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Build DanceLessonsCoach with version information +# Build dance-lessons-coach with version information # Usage: ./scripts/build-with-version.sh [output_path] set -e @@ -22,7 +22,7 @@ GIT_DATE=$(git log -1 --format=%cd --date=short 2>/dev/null || echo "unknown") # Build time (UTC for consistency) BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) -echo "πŸ”§ Building DanceLessonsCoach $VERSION" +echo "πŸ”§ Building dance-lessons-coach $VERSION" echo " Commit: $GIT_COMMIT" echo " Date: $GIT_DATE" echo " Output: $OUTPUT_PATH" @@ -31,9 +31,9 @@ echo " Output: $OUTPUT_PATH" go build \ -o "$OUTPUT_PATH" \ -ldflags="\ - -X DanceLessonsCoach/pkg/version.Version=$VERSION \ - -X DanceLessonsCoach/pkg/version.Commit=$GIT_COMMIT \ - -X DanceLessonsCoach/pkg/version.Date=$BUILD_DATE \ + -X dance-lessons-coach/pkg/version.Version=$VERSION \ + -X dance-lessons-coach/pkg/version.Commit=$GIT_COMMIT \ + -X dance-lessons-coach/pkg/version.Date=$BUILD_DATE \ " \ ./cmd/server diff --git a/scripts/build.sh b/scripts/build.sh index 46c46cc..5d89c82 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,11 +1,11 @@ #!/bin/bash -# DanceLessonsCoach Build Script +# dance-lessons-coach Build Script # Builds binaries into the bin/ directory set -e -echo "πŸ”¨ Building DanceLessonsCoach binaries..." +echo "πŸ”¨ Building dance-lessons-coach binaries..." # Create bin directory if it doesn't exist mkdir -p bin diff --git a/scripts/cicd.sh b/scripts/cicd.sh index 23708cf..25320d2 100755 --- a/scripts/cicd.sh +++ b/scripts/cicd.sh @@ -1,12 +1,12 @@ #!/bin/bash -# DanceLessonsCoach CI/CD Management Script +# dance-lessons-coach CI/CD Management Script # Unified interface for all CI/CD operations set -e SCRIPTS_DIR="$(dirname "$0")/cicd" -echo "πŸš€ DanceLessonsCoach CI/CD Management" +echo "πŸš€ dance-lessons-coach CI/CD Management" echo "====================================" echo "" diff --git a/scripts/cicd/README.md b/scripts/cicd/README.md deleted file mode 100644 index 42fb8ab..0000000 --- a/scripts/cicd/README.md +++ /dev/null @@ -1,286 +0,0 @@ -# CI/CD Scripts for DanceLessonsCoach - -## πŸš€ Quick Start for Contributors - -### You Only Need These Commands - -```bash -# 1. Run tests (this is what matters most!) -go test ./... - -# 2. Build binaries -./scripts/build.sh - -# 3. Check formatting -go fmt ./... - -# That's it! The CI/CD pipeline will handle the rest when you create a PR. -``` - -## πŸ“– Understanding the CI/CD Pipeline - -### What Happens Automatically - -When you push code or create a PR, GitHub Actions runs: - -1. **Go CI/CD Pipeline** (`.gitea/workflows/go-ci-cd.yaml`) - - Builds all Go packages - - Runs tests with coverage - - Checks code formatting - - Validates workflow structure - -2. **Docker Image Pipeline** (`.gitea/workflows/dockerimage.yaml`) - - Builds Docker image (on main branch only) - - Publishes to Gitea Container Registry - - Tags with version and commit SHA - -### When Does It Run? - -| Event | Go CI/CD | Docker Image | -|-------|---------|--------------| -| Push to `main` | βœ… Yes | βœ… Yes | -| Push to `feature/*` | βœ… Yes | ❌ No | -| Push to `fix/*` | βœ… Yes | ❌ No | -| Push to `ci/*` | βœ… Yes | ❌ No | -| Pull Request | βœ… Yes | ❌ No | -| Manual trigger | βœ… Yes | βœ… Yes | - -## πŸ§ͺ Local Testing Options - -### Option 1: Simple Validation (No Docker Required) - -```bash -# Just run the essentials -./scripts/cicd/contributor-quickstart.sh -``` - -This checks: -- βœ… Go installation -- βœ… All tests pass -- βœ… Code formatting -- βœ… Go vet analysis -- βœ… Workflow structure - -### Option 2: Docker-Based Testing (Recommended) - -```bash -# Test workflow compatibility with GitHub Actions -./scripts/cicd/test-act-local.sh -``` - -**Requirements:** -- Docker installed and running -- Internet connection (to pull images) - -**What it does:** -- Validates YAML syntax -- Checks workflow structure -- Simulates GitHub Actions execution -- Tests both workflow files - -### Option 3: Full CI/CD Simulation - -```bash -# Complete local simulation -./scripts/cicd/test-cicd-simple.sh -``` - -**Requirements:** -- Docker installed and running -- More time (pulls multiple images) - -**What it does:** -- YAML linting -- YAML validation -- Workflow structure validation -- Simulates build job -- Runs actual Go tests in containers - -## 🐳 Docker Setup Guide - -### For Windows Users - -1. **Install Docker Desktop** - - Download: https://www.docker.com/products/docker-desktop/ - - Enable WSL 2 backend (recommended) - - Allocate at least 4GB RAM - -2. **Verify Installation** - ```powershell - docker --version - docker run hello-world - ``` - -### For macOS Users - -1. **Install Docker Desktop** - - Download: https://www.docker.com/products/docker-desktop/ - - Grant necessary permissions - -2. **Verify Installation** - ```bash - docker --version - docker run hello-world - ``` - -### For Linux Users - -1. **Install Docker Engine** - ```bash - # Ubuntu/Debian - sudo apt-get update - sudo apt-get install docker.io docker-compose - sudo systemctl enable docker - sudo systemctl start docker - - # Add user to docker group (avoid sudo) - sudo usermod -aG docker $USER - newgrp docker # Reload group membership - ``` - -2. **Verify Installation** - ```bash - docker --version - docker run hello-world - ``` - -## πŸ”§ Troubleshooting - -### Docker Permission Issues - -**Symptom:** `Got permission denied while trying to connect to the Docker daemon socket` - -**Solution:** -```bash -# Linux/macOS -sudo usermod -aG docker $USER -newgrp docker - -# Windows -Right-click Docker Desktop β†’ Settings β†’ Resources β†’ WSL Integration β†’ Enable -``` - -### Docker Not Running - -**Symptom:** `Cannot connect to the Docker daemon` - -**Solution:** -- Windows/macOS: Open Docker Desktop app -- Linux: `sudo systemctl start docker` - -### Network Issues - -**Symptom:** `Cannot pull Docker images` - -**Solution:** -```bash -# Check internet connection -ping google.com - -# Try pulling manually first -docker pull mikefarah/yq:latest -docker pull pipelinecomponents/yamllint:latest -``` - -### act Not Installed - -**Symptom:** `act not found` in `test-act-local.sh` - -**Solution:** -```bash -# Install act (optional - only needed for test-act-local.sh) -# macOS -brew install act - -# Linux -curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash - -# Windows (WSL) -curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash -``` - -## πŸ“š Script Reference - -| Script | Purpose | Docker Required? | act Required? | -|--------|---------|------------------|---------------| -| `contributor-quickstart.sh` | Basic validation | ❌ No | ❌ No | -| `validate-workflow.sh` | Workflow structure | ❌ No | ❌ No | -| `test-act-local.sh` | GitHub Actions compatibility | βœ… Yes | βœ… Yes | -| `test-cicd-simple.sh` | Full CI/CD simulation | βœ… Yes | ❌ No | - -## 🎯 Best Practices - -### Before Submitting a PR - -1. **Run tests locally** - ```bash - go test ./... - ``` - -2. **Check formatting** - ```bash - go fmt ./... - ``` - -3. **Build binaries** - ```bash - ./scripts/build.sh - ``` - -4. **Validate workflows** (optional) - ```bash - ./scripts/cicd/validate-workflow.sh - ``` - -### Working with the CI/CD Pipeline - -- **Don't worry about Docker images** - The pipeline builds them automatically -- **Focus on tests** - If tests pass locally, they'll pass in CI/CD -- **Check PR status** - GitHub will show CI/CD results automatically -- **Fix failures** - If CI/CD fails, check the logs and fix issues - -## πŸ”— Useful Links - -- **GitHub Actions Docs**: https://docs.github.com/en/actions -- **Docker Docs**: https://docs.docker.com/ -- **act GitHub**: https://github.com/nektos/act -- **DanceLessonsCoach CI/CD**: See `.gitea/workflows/` directory - -## πŸ’‘ Pro Tips - -### Speed Up Local Testing - -```bash -# Pull Docker images in advance -docker pull mikefarah/yq:latest -docker pull pipelinecomponents/yamllint:latest -docker pull node:16-buster-slim -``` - -### Test Specific Workflows - -```bash -# Test Go CI/CD workflow only -act -W .gitea/workflows/go-ci-cd.yaml - -# Test Docker workflow only -act -W .gitea/workflows/dockerimage.yaml -``` - -### Dry Run (No Execution) - -```bash -# Check workflow syntax without running -echo 'm' | act -n -W .gitea/workflows/go-ci-cd.yaml -``` - -## πŸ“ž Need Help? - -If you're stuck with CI/CD setup: - -1. **Check this documentation** - Most issues are covered here -2. **Run contributor-quickstart.sh** - It validates the essentials -3. **Ask in the PR** - We'll help you resolve any issues -4. **Check CI/CD logs** - GitHub shows detailed error messages - -Remember: **You don't need to run CI/CD locally to contribute!** The pipeline runs automatically when you push code. diff --git a/scripts/cicd/check-pipeline-status.sh b/scripts/cicd/check-pipeline-status.sh deleted file mode 100755 index ae2d5f5..0000000 --- a/scripts/cicd/check-pipeline-status.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -# Check CI/CD pipeline status across all platforms - -set -e - -echo "πŸ” Checking CI/CD Pipeline Status" -echo "================================" - -# 1. Gitea (Primary) - Internal URL -if curl -s -o /dev/null -w "%{http_code}" "https://gitea.arcodange.lab/api/v1/repos/arcodange/DanceLessonsCoach/actions/workflows" 2>/dev/null | grep -q "200"; then - echo "βœ… Gitea Internal API: Accessible" - # Get workflow list - WORKFLOWS=$(curl -s "https://gitea.arcodange.lab/api/v1/repos/arcodange/DanceLessonsCoach/actions/workflows" 2>/dev/null | jq -r '.[] | .name + " (" + .file_name + ")"' 2>/dev/null || echo "Unable to fetch workflow list") - echo "πŸ“‹ Gitea Workflows:" - echo "$WORKFLOWS" | sed 's/^/ - /' -else - echo "❌ Gitea Internal API: Not accessible (check network/vpn)" -fi - -# 2. Gitea (External) - Public URL -echo "" -echo "🌐 Gitea External Status:" -if curl -s -o /dev/null -w "%{http_code}" "https://gitea.arcodange.fr/arcodange/DanceLessonsCoach" 2>/dev/null | grep -q "200"; then - echo "βœ… Gitea External: Accessible" - echo "πŸ”— Repository: https://gitea.arcodange.fr/arcodange/DanceLessonsCoach" -else - echo "❌ Gitea External: Not accessible" -fi - -# 3. Check badge API -echo "" -echo "🏷️ Badge API Status:" -BADGE_URL="https://gitea.arcodange.fr/api/badges/arcodange/DanceLessonsCoach/status" -if curl -s -o /dev/null -w "%{http_code}" "$BADGE_URL" 2>/dev/null | grep -q "200"; then - echo "βœ… Badge API: Accessible" - echo "πŸ”— Badge URL: $BADGE_URL" -else - echo "❌ Badge API: Not accessible" -fi - -# 4. Check workflow file existence -echo "" -echo "πŸ“ Workflow Files:" -if [ -f ".gitea/workflows/ci-cd.yaml" ]; then - echo "βœ… .gitea/workflows/ci-cd.yaml: Found" - if command -v yq >/dev/null 2>&1; then - echo "πŸ“Š Jobs: $(yq eval '.jobs | keys | join(", ")' .gitea/workflows/ci-cd.yaml 2>/dev/null || echo 'Unable to parse')" - else - echo "πŸ“Š Jobs: yq not installed, cannot parse jobs" - fi -else - echo "❌ .gitea/workflows/ci-cd.yaml: Not found" -fi - -echo "" -echo "🎯 Validation Summary" -echo "================================" -echo "βœ… Local workflow file: .gitea/workflows/ci-cd.yaml" -if command -v yq >/dev/null 2>&1; then - echo "βœ… Syntax validation: $(yq eval '.' .gitea/workflows/ci-cd.yaml > /dev/null 2>&1 && echo 'Valid YAML' || echo 'Invalid YAML')" -else - echo "⚠️ Syntax validation: yq not installed" -fi -echo "βœ… Gitea compatibility: Uses .gitea/workflows/ directory" -echo "βœ… Arcodange conventions: Matches webapp workflow style" - -echo "" -echo "πŸ’‘ Next Steps:" -echo " 1. Push to trigger workflow: git push origin main" -echo " 2. Check Gitea Actions: https://gitea.arcodange.lab/arcodange/DanceLessonsCoach/actions" -echo " 3. Monitor badges: https://gitea.arcodange.fr/arcodange/DanceLessonsCoach" \ No newline at end of file diff --git a/scripts/cicd/contributor-quickstart.sh b/scripts/cicd/contributor-quickstart.sh deleted file mode 100755 index 0d11024..0000000 --- a/scripts/cicd/contributor-quickstart.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash -# Simple CI/CD validation for new contributors -# Works without Docker - just validates the essentials - -set -e - -echo "πŸš€ DanceLessonsCoach Contributor Quick Start" -echo "==========================================" -echo "" -echo "This script helps you validate your changes before submitting a PR." -echo "It doesn't require Docker or complex setup." -echo "" - -# 1. Check Go is installed -echo "1. Checking Go installation..." -if ! command -v go >/dev/null 2>&1; then - echo "❌ Go is not installed. Please install Go 1.26.1+" - echo " Download: https://go.dev/dl/" - exit 1 -fi -go_version=$(go version | grep -o 'go[0-9.]*') -echo "βœ… Go $go_version found" - -# 2. Run Go tests -echo "" -echo "2. Running Go tests..." -if go test ./...; then - echo "βœ… All Go tests passed" -else - echo "❌ Some tests failed. Please fix and try again." - exit 1 -fi - -# 3. Check formatting -echo "" -echo "3. Checking code formatting..." -if [ -n "$(go fmt ./...)" ]; then - echo "❌ Code formatting issues found" - echo " Run: go fmt ./..." - exit 1 -fi -echo "βœ… Code is properly formatted" - -# 4. Run Go vet -echo "" -echo "4. Running Go vet..." -if go vet ./...; then - echo "βœ… Go vet passed" -else - echo "❌ Go vet found issues" - exit 1 -fi - -# 5. Validate workflows (no Docker required) -echo "" -echo "5. Validating CI/CD workflows..." -if [ -f "scripts/cicd/validate-workflow.sh" ]; then - if ./scripts/cicd/validate-workflow.sh; then - echo "βœ… Workflow validation passed" - else - echo "⚠️ Workflow validation issues (not critical)" - fi -else - echo "ℹ️ Workflow validation script not found" -fi - -echo "" -echo "πŸŽ‰ All checks passed!" -echo "==========================================" -echo "" -echo "Your changes are ready to submit! πŸš€" -echo "" -echo "Next steps:" -echo " 1. Commit your changes: git commit -m 'feat: your feature'" -echo " 2. Push to your branch: git push origin your-branch" -echo " 3. Create a Pull Request" -echo "" -echo "The CI/CD pipeline will run automatically on your PR!" diff --git a/scripts/cicd/test-act-local.sh b/scripts/cicd/test-act-local.sh deleted file mode 100755 index 9dfde9b..0000000 --- a/scripts/cicd/test-act-local.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -# Test Gitea workflows locally using GitHub Actions runner (act) -# This allows local testing without requiring a Gitea instance - -set -e - -echo "πŸ§ͺ Testing Gitea Workflows with GitHub Actions Runner" -echo "====================================================" - -# Check if act is installed -if ! command -v act >/dev/null 2>&1; then - echo "❌ act not found. Please install with:" - echo " brew install act # macOS" - echo " or visit: https://github.com/nektos/act" - exit 1 -fi - -# Check if workflow files exist -WORKFLOW_FILES=( - ".gitea/workflows/go-ci-cd.yaml" - ".gitea/workflows/dockerimage.yaml" -) - -for file in "${WORKFLOW_FILES[@]}"; do - if [ ! -f "$file" ]; then - echo "❌ Workflow file not found: $file" - exit 1 - fi -done - -echo "βœ… act installed and workflow file found" -echo "" - -# 1. Dry run (syntax check only) -echo "1. Running dry run (syntax validation)..." -ALL_PASSED=true - -for file in "${WORKFLOW_FILES[@]}"; do - echo " Testing: $file" - if echo 'm' | act -n -W "$file" --container-architecture linux/amd64; then - echo " βœ… Dry run completed for $file" - else - echo " ❌ Dry run failed for $file" - ALL_PASSED=false - fi -done - -if [ "$ALL_PASSED" = true ]; then - echo "βœ… All dry runs completed successfully" -else - echo "❌ Some dry runs failed" - exit 1 -fi - - -echo "" -echo "πŸŽ‰ Gitea workflows are compatible with GitHub Actions!" -echo "==================================================" -echo "" -echo "πŸ“‹ Summary:" -echo " βœ… Syntax validation passed for all workflows" -echo " βœ… All jobs parsed correctly" -echo " βœ… Job dependencies resolved" -echo " βœ… Conditional execution working" -echo " βœ… Gitea/GitHub Actions compatibility confirmed" -echo "" -echo "πŸš€ You can now test locally without Gitea instance:" -for file in "${WORKFLOW_FILES[@]}"; do - workflow_name=$(basename "$file" .yaml) - echo " act -n -W $file # Dry run $workflow_name" - echo " act -W $file # Full execution $workflow_name" -done - -echo "" -echo "πŸ’‘ Tip: Add this to your pre-commit hook to validate workflows automatically!" diff --git a/scripts/cicd/test-cicd-docker.sh b/scripts/cicd/test-cicd-docker.sh deleted file mode 100755 index cf08b92..0000000 --- a/scripts/cicd/test-cicd-docker.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash -# Comprehensive Docker-based CI/CD testing script -# Tests workflows locally using Docker containers - -set -e - -echo "🐳 Docker-based CI/CD Testing" -echo "================================" - -# 1. Check Docker is available -if ! command -v docker >/dev/null 2>&1; then - echo "❌ Docker not found. Please install Docker first." - echo " https://docs.docker.com/get-docker/" - exit 1 -fi - -echo "βœ… Docker is available" - -# 2. Pull required images -echo "" -echo "πŸ“¦ Pulling Docker images..." -docker pull gitea/act_runner:latest -docker pull pipelinecomponents/yamllint:latest -docker pull mikefarah/yq:latest - -echo "βœ… Images pulled successfully" - -# 3. Validate YAML syntax with yq -echo "" -echo "πŸ” Validating YAML syntax..." -docker run --rm \ - -v $(pwd):/workspace \ - -w /workspace \ - mikefarah/yq:latest \ - yq eval .gitea/workflows/go-ci-cd.yaml > /dev/null 2>&1 - -if [ $? -eq 0 ]; then - echo "βœ… YAML syntax is valid" -else - echo "❌ YAML syntax error" - docker run --rm \ - -v $(pwd):/workspace \ - -w /workspace \ - mikefarah/yq:latest \ - yq eval .gitea/workflows/go-ci-cd.yaml || true - exit 1 -fi - -# 4. Lint YAML with yamllint -echo "" -echo "🧹 Linting YAML..." -docker run --rm \ - -v $(pwd):/workspace \ - -w /workspace \ - pipelinecomponents/yamllint:latest \ - yamllint .gitea/workflows/ - -if [ $? -eq 0 ]; then - echo "βœ… YAML linting passed" -else - echo "❌ YAML linting failed" - exit 1 -fi - -# 5. Run workflow with act -echo "" -echo "πŸš€ Running CI/CD workflow..." -docker run --rm \ - -v $(pwd):/workspace \ - -w /workspace \ - -e GITEA_INTERNAL="https://gitea.arcodange.lab/" \ - -e GITEA_EXTERNAL="https://gitea.arcodange.fr/" \ - -e GITEA_ORG="arcodange" \ - -e GITEA_REPO="DanceLessonsCoach" \ - gitea/act_runner:latest \ - act -W .gitea/workflows/go-ci-cd.yaml --rm - -if [ $? -eq 0 ]; then - echo "βœ… Workflow executed successfully" -else - echo "❌ Workflow execution failed" - exit 1 -fi - -echo "" -echo "πŸŽ‰ All CI/CD tests passed!" -echo "================================" -echo "πŸ“ Workflow: .gitea/workflows/ci-cd.yaml" -echo "βœ… YAML syntax validated" -echo "βœ… YAML linting passed" -echo "βœ… Workflow execution successful" -echo "🎯 Ready for production deployment" - -echo "" -echo "πŸ’‘ Next Steps:" -echo " 1. Commit changes: git commit -m 'πŸ€– ci: update workflow'" -echo " 2. Push to trigger: git push origin main" -echo " 3. Monitor pipeline: https://gitea.arcodange.lab/arcodange/DanceLessonsCoach/actions" -echo " 4. Check badges: https://gitea.arcodange.fr/arcodange/DanceLessonsCoach" diff --git a/scripts/cicd/test-cicd-local.sh b/scripts/cicd/test-cicd-local.sh deleted file mode 100755 index 25d3791..0000000 --- a/scripts/cicd/test-cicd-local.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash -# Test CI/CD setup locally without requiring Gitea instance - -set -e - -echo "πŸ§ͺ Testing CI/CD Local Setup" -echo "==============================" - -# 1. Validate YAML syntax -echo "1. Validating YAML syntax..." -if command -v yq >/dev/null 2>&1; then - yq eval '.' .gitea/workflows/go-ci-cd.yaml > /dev/null - yq eval '.' .gitea/workflows/dockerimage.yaml > /dev/null - echo "βœ… YAML syntax is valid" -else - echo "⚠️ yq not found, skipping YAML validation" -fi - -# 2. Validate workflow structure -echo "2. Validating workflow structure..." -./scripts/cicd/validate-workflow.sh - -# 3. Check docker-compose configuration -echo "3. Checking docker-compose configuration..." -docker compose -f docker-compose.cicd-test.yml config > /dev/null 2>&1 -if [ $? -eq 0 ]; then - echo "βœ… docker-compose configuration is valid" -else - echo "❌ docker-compose configuration has issues" - exit 1 -fi - -# 4. Check for required files -echo "4. Checking required files..." -REQUIRED_FILES=( - ".gitea/workflows/go-ci-cd.yaml" - ".gitea/workflows/dockerimage.yaml" - "docker-compose.cicd-test.yml" - "config/runner.example" -) - -for file in "${REQUIRED_FILES[@]}"; do - if [ -f "$file" ]; then - echo "βœ… $file exists" - else - echo "❌ $file missing" - exit 1 - fi -done - -# 5. Show configuration status -echo "5. Configuration status..." -if [ -f "config/runner" ]; then - echo "βœ… config/runner exists (gitignored)" - echo "πŸ“ You can connect to Gitea instance" -else - echo "ℹ️ config/runner not found (expected - it's gitignored)" - echo "πŸ“ To connect to Gitea:" - echo " 1. Copy config/runner.example to config/runner" - echo " 2. Fill in your Gitea runner configuration" - echo " 3. Set environment variables:" - echo " export GITEA_RUNNER_REGISTRATION_TOKEN=your-token" - echo " 4. Run: docker compose -f docker-compose.cicd-test.yml up" -fi - -echo "" -echo "πŸŽ‰ CI/CD Local Setup Validation Complete!" -echo "==============================" -echo "πŸ“‹ Summary:" -echo " βœ… YAML syntax validated" -echo " βœ… Workflow structure validated" -echo " βœ… Docker-compose configuration validated" -echo " βœ… All required files present" -echo "" -echo "πŸš€ Next steps:" -echo " 1. Create config/runner file with your Gitea runner token" -echo " 2. Set GITEA_RUNNER_REGISTRATION_TOKEN environment variable" -echo " 3. Run: docker compose -f docker-compose.cicd-test.yml up" -echo "" -echo "πŸ’‘ For local testing without Gitea:" -echo " Use: ./scripts/test-cicd-simple.sh (if available)" -echo " Or manually test workflow steps" diff --git a/scripts/cicd/test-cicd-simple.sh b/scripts/cicd/test-cicd-simple.sh deleted file mode 100755 index 7904043..0000000 --- a/scripts/cicd/test-cicd-simple.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -# Simple CI/CD testing without Gitea instance -# Tests the workflow steps locally using docker containers - -set -e - -echo "πŸ§ͺ Simple CI/CD Testing (No Gitea Required)" -echo "==========================================" - -# 1. YAML Linting -echo "1. Running YAML linting..." -if [ -f ".yamllint.yaml" ]; then - docker run --rm -v $(pwd):/workspace -w /workspace pipelinecomponents/yamllint:latest \ - yamllint -c .yamllint.yaml .gitea/workflows/ -else - docker run --rm -v $(pwd):/workspace -w /workspace pipelinecomponents/yamllint:latest \ - yamllint .gitea/workflows/ -fi -echo "βœ… YAML linting passed" - -# 2. YAML Validation -echo "2. Running YAML validation..." -WORKFLOW_FILES=(".gitea/workflows/go-ci-cd.yaml" ".gitea/workflows/dockerimage.yaml") -for file in "${WORKFLOW_FILES[@]}"; do - docker run --rm -v $(pwd):/workspace -w /workspace mikefarah/yq:latest eval '.' "$file" > /dev/null -done -echo "βœ… YAML validation passed" - -# 3. Workflow Structure Validation -echo "3. Running workflow structure validation..." -./scripts/cicd/validate-workflow.sh - -# 4. Simulate Build Job -echo "4. Simulating build-test job..." -docker run --rm -v $(pwd):/workspace -w /workspace golang:1.26.1 bash -c " - apt-get update -qq && apt-get install -y -qq git > /dev/null && \ - go mod tidy && \ - go build ./... && \ - go test ./... -cover -v -" -echo "βœ… Build and test completed" - -# 5. Simulate Lint Job -echo "5. Simulating lint-format job..." -docker run --rm -v $(pwd):/workspace -w /workspace golang:1.26.1 bash -c " - go fmt ./... && \ - go vet ./... && \ - echo 'Formatting check passed' -" -echo "βœ… Linting completed" - -echo "" -echo "πŸŽ‰ Simple CI/CD Testing Complete!" -echo "==========================================" -echo "βœ… All workflow steps validated locally" -echo "πŸ“ Workflow is ready for Gitea deployment" -echo "" -echo "πŸš€ To deploy to Gitea:" -echo " 1. Create config/runner file with your Gitea runner token" -echo " 2. Set GITEA_RUNNER_REGISTRATION_TOKEN environment variable" -echo " 3. Run: docker compose -f docker-compose.cicd-test.yml up" diff --git a/scripts/cicd/validate-workflow.sh b/scripts/cicd/validate-workflow.sh deleted file mode 100755 index d6a73b9..0000000 --- a/scripts/cicd/validate-workflow.sh +++ /dev/null @@ -1,151 +0,0 @@ -#!/bin/bash -# Validate CI/CD workflow syntax and structure - -set -e - -echo "πŸ” Validating CI/CD Workflow" -echo "================================" - -# 1. Check workflow files exist -WORKFLOW_FILES=( - ".gitea/workflows/go-ci-cd.yaml" - ".gitea/workflows/dockerimage.yaml" -) - -for file in "${WORKFLOW_FILES[@]}"; do - if [ ! -f "$file" ]; then - echo "❌ Workflow file not found: $file" - exit 1 - fi - echo "βœ… Workflow file found: $file" -done - -# 2. Validate YAML syntax for all workflows -if command -v yq >/dev/null 2>&1; then - for file in "${WORKFLOW_FILES[@]}"; do - if ! yq eval '.' "$file" > /dev/null 2>&1; then - echo "❌ Invalid YAML syntax in: $file" - yq eval '.' "$file" || true - exit 1 - fi - echo "βœ… YAML syntax valid: $file" - done -else - echo "⚠️ yq not installed, skipping YAML validation" -fi - -# 3. YAML Linting with custom config for all workflows -if command -v yamllint >/dev/null 2>&1; then - for file in "${WORKFLOW_FILES[@]}"; do - if [ -f ".yamllint.yaml" ]; then - yamllint -c "$(pwd)/.yamllint.yaml" "$file" - else - yamllint "$file" - fi - done -elif docker info >/dev/null 2>&1; then - for file in "${WORKFLOW_FILES[@]}"; do - if [ -f ".yamllint.yaml" ]; then - docker run --rm -v $(pwd):/workspace -w /workspace pipelinecomponents/yamllint:latest \ - yamllint -c /workspace/.yamllint.yaml "$file" - else - docker run --rm -v $(pwd):/workspace -w /workspace pipelinecomponents/yamllint:latest \ - yamllint "$file" - fi - done -else - echo "⚠️ Neither yamllint nor docker available, skipping linting" -fi - -# 3. Check required fields for all workflows -for file in "${WORKFLOW_FILES[@]}"; do - MISSING_FIELDS=() - - if command -v yq >/dev/null 2>&1; then - workflow_name=$(basename "$file" .yaml) - - if [ -z "$(yq eval '.name' "$file" 2>/dev/null)" ]; then - MISSING_FIELDS+=("name") - fi - - if [ -z "$(yq eval '.on' "$file" 2>/dev/null)" ]; then - MISSING_FIELDS+=("on") - fi - - if [ -z "$(yq eval '.jobs' "$file" 2>/dev/null)" ]; then - MISSING_FIELDS+=("jobs") - fi - - if [ ${#MISSING_FIELDS[@]} -gt 0 ]; then - echo "❌ Missing required fields in $workflow_name: ${MISSING_FIELDS[*]}" - exit 1 - fi - echo "βœ… All required fields present in $workflow_name" - else - echo "⚠️ yq not installed, skipping field validation for $file" - fi -done - -# 4. Check jobs structure -if command -v yq >/dev/null 2>&1; then - JOBS=$(yq eval '.jobs | keys' .gitea/workflows/ci-cd.yaml 2>/dev/null) - echo "πŸ“‹ Jobs defined: $JOBS" - - for job in $JOBS; do - job_str=$(echo $job | tr -d '"') - - # Check job has steps - if [ -z "$(yq eval ".jobs.$job_str.steps" .gitea/workflows/ci-cd.yaml 2>/dev/null)" ]; then - echo "❌ Job $job_str has no steps" - exit 1 - fi - - steps_count=$(yq eval ".jobs.$job_str.steps | length" .gitea/workflows/ci-cd.yaml 2>/dev/null) - echo " βœ… $job_str: $steps_count steps" - done -else - echo "⚠️ yq not installed, skipping job structure validation" -fi - -# 5. Check Arcodange-specific configurations -if command -v yq >/dev/null 2>&1; then - if [ -n "$(yq eval '.env.GITEA_INTERNAL' .gitea/workflows/ci-cd.yaml 2>/dev/null)" ]; then - echo "βœ… Arcodange internal URL configured" - else - echo "⚠️ Arcodange internal URL not found" - fi - - if [ -n "$(yq eval '.env.GITEA_EXTERNAL' .gitea/workflows/ci-cd.yaml 2>/dev/null)" ]; then - echo "βœ… Arcodange external URL configured" - else - echo "⚠️ Arcodange external URL not found" - fi - - # 6. Check concurrency settings - if [ -n "$(yq eval '.concurrency' .gitea/workflows/ci-cd.yaml 2>/dev/null)" ]; then - echo "βœ… Concurrency control configured" - else - echo "⚠️ No concurrency control (consider adding)" - fi -else - echo "⚠️ yq not installed, skipping Arcodange-specific validations" -fi - -echo "" -echo "πŸŽ‰ Workflow Validation Successful!" -echo "================================" -echo "πŸ“ Workflows validated:" -for file in "${WORKFLOW_FILES[@]}"; do - echo " - $file" -done -if command -v yq >/dev/null 2>&1; then - echo "πŸ”§ Summary:" - for file in "${WORKFLOW_FILES[@]}"; do - workflow_name=$(basename "$file" .yaml) - JOBS=$(yq eval '.jobs | keys | join(", ")' "$file" 2>/dev/null || echo 'Unable to parse') - echo " - $workflow_name: $JOBS" - done -else - echo "πŸ”§ Jobs: yq not installed" -fi -echo "🎯 Ready for deployment" \ No newline at end of file diff --git a/scripts/run-bdd-tests.sh b/scripts/run-bdd-tests.sh index 1d90fbb..3289fea 100755 --- a/scripts/run-bdd-tests.sh +++ b/scripts/run-bdd-tests.sh @@ -6,10 +6,96 @@ set -e echo "πŸ§ͺ Running BDD Tests..." -cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach +SCRIPTS_DIR=$(dirname `realpath ${BASH_SOURCE[0]}`) +cd $SCRIPTS_DIR/.. + +# Check if we're in CI environment +if [ -n "$GITHUB_ACTIONS" ] || [ -n "$GITEA_ACTIONS" ]; then + # CI environment - PostgreSQL is already running as a service + echo "πŸ—οΈ CI environment detected" + echo "πŸ‹ PostgreSQL service is already running" + + # Check if database is accessible + echo "πŸ“¦ Checking PostgreSQL connectivity..." + if ! pg_isready -h postgres -p 5432 -U postgres -d dance_lessons_coach_bdd_test; then + echo "❌ PostgreSQL is not ready or accessible" + exit 1 + fi + echo "βœ… PostgreSQL is ready!" +else + # Local environment - use docker compose + echo "πŸ’» Local environment detected" + + # Check if PostgreSQL container is running, start it if not + echo "πŸ‹ Checking PostgreSQL container..." + if ! docker ps --format '{{.Names}}' | grep -q "^dance-lessons-coach-postgres$"; then + echo "πŸ‹ Starting PostgreSQL container..." + docker compose up -d postgres + + # Wait for PostgreSQL to be ready + echo "⏳ Waiting for PostgreSQL to be ready..." + max_attempts=30 + attempt=0 + while [ $attempt -lt $max_attempts ]; do + if docker exec dance-lessons-coach-postgres pg_isready -U postgres 2>/dev/null; then + echo "βœ… PostgreSQL is ready!" + break + fi + attempt=$((attempt + 1)) + sleep 1 + done + + if [ $attempt -eq $max_attempts ]; then + echo "❌ PostgreSQL failed to start" + exit 1 + fi + + # Create BDD test database (separate from development database) + echo "πŸ“¦ Creating BDD test database..." + # Drop database if it exists, then create fresh + docker exec dance-lessons-coach-postgres psql -U postgres -c "DROP DATABASE IF EXISTS dance_lessons_coach_bdd_test;" + if docker exec dance-lessons-coach-postgres createdb -U postgres dance_lessons_coach_bdd_test; then + echo "βœ… BDD test database created successfully!" + else + echo "❌ Failed to create BDD test database" + exit 1 + fi + else + echo "βœ… PostgreSQL container is already running" + + # Check if BDD test database exists, create if not + echo "πŸ“¦ Checking BDD test database..." + if docker exec dance-lessons-coach-postgres psql -U postgres -lqt | cut -d \| -f 1 | grep -qw "dance_lessons_coach_bdd_test"; then + echo "βœ… BDD test database already exists" + else + echo "πŸ“¦ Creating BDD test database..." + if docker exec dance-lessons-coach-postgres createdb -U postgres dance_lessons_coach_bdd_test; then + echo "βœ… BDD test database created successfully!" + else + echo "❌ Failed to create BDD test database" + exit 1 + fi + fi + fi +fi # Run the BDD tests -test_output=$(go test ./features/... -v 2>&1) +# For local environment, set database environment variables to use localhost +# For CI environment, the database is already configured as a service +if [ -z "$GITHUB_ACTIONS" ] && [ -z "$GITEA_ACTIONS" ]; then + echo "πŸ”§ Setting database environment variables for local environment..." + export DLC_DATABASE_HOST="localhost" + export DLC_DATABASE_PORT="5432" + export DLC_DATABASE_USER="postgres" + export DLC_DATABASE_PASSWORD="postgres" + export DLC_DATABASE_NAME="dance_lessons_coach_bdd_test" + export DLC_DATABASE_SSL_MODE="disable" +else + echo "πŸ—οΈ CI environment detected, using service configuration" +fi + +# Run tests with proper coverage measurement +test_output=$(go test ./features/... -v -cover -coverpkg=./... -coverprofile=coverage.out 2>&1) test_exit_code=$? echo "$test_output" @@ -38,5 +124,6 @@ if [ $test_exit_code -eq 0 ]; then exit 0 else echo "❌ BDD tests failed" + echo echo 'DLC_DATABASE_HOST=localhost DLC_DATABASE_PORT=5432 DLC_DATABASE_USER=postgres DLC_DATABASE_PASSWORD=postgres DLC_DATABASE_NAME=dance_lessons_coach_bdd_test DLC_DATABASE_SSL_MODE=disable go test ./features/... -v' exit 1 fi diff --git a/scripts/run-bdd-tests.sh.backup b/scripts/run-bdd-tests.sh.backup new file mode 100755 index 0000000..abdf8c1 --- /dev/null +++ b/scripts/run-bdd-tests.sh.backup @@ -0,0 +1,177 @@ +#!/bin/bash + +# BDD Test Runner Script +# Runs all BDD tests and fails if there are undefined, pending, or skipped steps + +set -e + +echo "πŸ§ͺ Running BDD Tests..." +cd /Users/gabrielradureau/Work/Vibe/DanceLessonsCoach + +# Check if we're in CI environment +if [ -n "$GITHUB_ACTIONS" ] || [ -n "$GITEA_ACTIONS" ]; then + # CI environment - PostgreSQL is already running as a service + echo "πŸ—οΈ CI environment detected" + echo "πŸ‹ PostgreSQL service is already running" + + # Check if database is accessible + echo "πŸ“¦ Checking PostgreSQL connectivity..." + if ! pg_isready -h postgres -p 5432 -U postgres -d dance_lessons_coach_bdd_test; then + echo "❌ PostgreSQL is not ready or accessible" + exit 1 + fi + echo "βœ… PostgreSQL is ready!" +else + # Local environment - use docker compose + echo "πŸ’» Local environment detected" + + # Check if PostgreSQL container is running, start it if not + echo "πŸ‹ Checking PostgreSQL container..." + if ! docker ps --format '{{.Names}}' | grep -q "^dance-lessons-coach-postgres$"; then + echo "πŸ‹ Starting PostgreSQL container..." + docker compose up -d postgres + + # Wait for PostgreSQL to be ready + echo "⏳ Waiting for PostgreSQL to be ready..." + max_attempts=30 + attempt=0 + while [ $attempt -lt $max_attempts ]; do + if docker exec dance-lessons-coach-postgres pg_isready -U postgres 2>/dev/null; then + echo "βœ… PostgreSQL is ready!" + break + fi + attempt=$((attempt + 1)) + sleep 1 + done + + if [ $attempt -eq $max_attempts ]; then + echo "❌ PostgreSQL failed to start" + exit 1 + fi + + # Create BDD test database (separate from development database) + echo "πŸ“¦ Creating BDD test database..." + # Drop database if it exists, then create fresh + docker exec dance-lessons-coach-postgres psql -U postgres -c "DROP DATABASE IF EXISTS dance_lessons_coach_bdd_test;" + if docker exec dance-lessons-coach-postgres createdb -U postgres dance_lessons_coach_bdd_test; then + echo "βœ… BDD test database created successfully!" + else + echo "❌ Failed to create BDD test database" + exit 1 + fi + else + echo "βœ… PostgreSQL container is already running" + + # Check if BDD test database exists, create if not + echo "πŸ“¦ Checking BDD test database..." + if docker exec dance-lessons-coach-postgres psql -U postgres -lqt | cut -d \| -f 1 | grep -qw "dance_lessons_coach_bdd_test"; then + echo "βœ… BDD test database already exists" + else + echo "πŸ“¦ Creating BDD test database..." + if docker exec dance-lessons-coach-postgres createdb -U postgres dance_lessons_coach_bdd_test; then + echo "βœ… BDD test database created successfully!" + else + echo "❌ Failed to create BDD test database" + exit 1 + fi + fi + fi +else + # CI environment - PostgreSQL is already running as a service + echo "πŸ—οΈ CI environment detected" + echo "πŸ‹ PostgreSQL service is already running" + + # Check if database is accessible + echo "πŸ“¦ Checking PostgreSQL connectivity..." + if ! pg_isready -h postgres -p 5432 -U postgres -d dance_lessons_coach_bdd_test; then + echo "❌ PostgreSQL is not ready or accessible" + exit 1 + fi + echo "βœ… PostgreSQL is ready!" +else + # Check if PostgreSQL container is running, start it if not + echo "πŸ‹ Checking PostgreSQL container..." + if ! docker ps --format '{{.Names}}' | grep -q "^dance-lessons-coach-postgres$"; then + echo "πŸ‹ Starting PostgreSQL container..." + docker compose up -d postgres + + # Wait for PostgreSQL to be ready + echo "⏳ Waiting for PostgreSQL to be ready..." + max_attempts=30 + attempt=0 + while [ $attempt -lt $max_attempts ]; do + if docker exec dance-lessons-coach-postgres pg_isready -U postgres 2>/dev/null; then + echo "βœ… PostgreSQL is ready!" + break + fi + attempt=$((attempt + 1)) + sleep 1 + done + + if [ $attempt -eq $max_attempts ]; then + echo "❌ PostgreSQL failed to start" + exit 1 + fi + + # Create BDD test database (separate from development database) + echo "πŸ“¦ Creating BDD test database..." + # Drop database if it exists, then create fresh + docker exec dance-lessons-coach-postgres psql -U postgres -c "DROP DATABASE IF EXISTS dance_lessons_coach_bdd_test;" + if docker exec dance-lessons-coach-postgres createdb -U postgres dance_lessons_coach_bdd_test; then + echo "βœ… BDD test database created successfully!" + else + echo "❌ Failed to create BDD test database" + exit 1 + fi + else + echo "βœ… PostgreSQL container is already running" + + # Check if BDD test database exists, create if not + echo "πŸ“¦ Checking BDD test database..." + if docker exec dance-lessons-coach-postgres psql -U postgres -lqt | cut -d \| -f 1 | grep -qw "dance_lessons_coach_bdd_test"; then + echo "βœ… BDD test database already exists" + else + echo "πŸ“¦ Creating BDD test database..." + if docker exec dance-lessons-coach-postgres createdb -U postgres dance_lessons_coach_bdd_test; then + echo "βœ… BDD test database created successfully!" + else + echo "❌ Failed to create BDD test database" + exit 1 + fi + fi + fi +fi + +# Run the BDD tests +test_output=$(go test ./features/... -v 2>&1) +test_exit_code=$? + +echo "$test_output" + +# Check for undefined steps +if echo "$test_output" | grep -q "undefined"; then + echo "❌ FAILED: Found undefined steps" + exit 1 +fi + +# Check for pending steps +if echo "$test_output" | grep -q "pending"; then + echo "❌ FAILED: Found pending steps" + exit 1 +fi + +# Check for skipped steps +if echo "$test_output" | grep -q "skipped"; then + echo "❌ FAILED: Found skipped steps" + exit 1 +fi + +# Check if tests passed +if [ $test_exit_code -eq 0 ]; then + echo "βœ… All BDD tests passed successfully!" + exit 0 +else + echo "❌ BDD tests failed" + echo 'DLC_DATABASE_HOST=localhost DLC_DATABASE_PORT=5432 DLC_DATABASE_USER=postgres DLC_DATABASE_PASSWORD=postgres DLC_DATABASE_NAME=dance_lessons_coach_bdd_test DLC_DATABASE_SSL_MODE=disable go test ./features/... -v' + exit 1 +fi diff --git a/scripts/start-server.sh b/scripts/start-server.sh index c7a5551..98229e5 100755 --- a/scripts/start-server.sh +++ b/scripts/start-server.sh @@ -1,10 +1,10 @@ #!/bin/bash -# DanceLessonsCoach Server Start Script +# dance-lessons-coach Server Start Script # This script starts the server in the background and provides control functions # Configuration -PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/DanceLessonsCoach" +PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/dance-lessons-coach" SERVER_CMD="go run ./cmd/server" LOG_FILE="server.log" PID_FILE="server.pid" @@ -14,7 +14,7 @@ cd "$PROJECT_DIR" || { echo "Failed to change to project directory"; exit 1; } # Function to start the server start_server() { - echo "Starting DanceLessonsCoach server..." + echo "Starting dance-lessons-coach server..." # Check if server is already running if [ -f "$PID_FILE" ]; then diff --git a/scripts/test-graceful-shutdown.sh b/scripts/test-graceful-shutdown.sh index 8b94202..e3dd437 100755 --- a/scripts/test-graceful-shutdown.sh +++ b/scripts/test-graceful-shutdown.sh @@ -1,20 +1,20 @@ #!/bin/bash -# DanceLessonsCoach Graceful Shutdown Test Script +# dance-lessons-coach Graceful Shutdown Test Script # This script tests the complete server lifecycle with JSON logging # and validates that all shutdown logs are present set -e # Configuration -PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/DanceLessonsCoach" +PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/dance-lessons-coach" SERVER_CMD="./scripts/start-server.sh" LOG_FILE="server.log" PID_FILE="server.pid" TEST_LOG="shutdown_test.log" # Colors for output - use simple echo -e with inline ANSI codes -echo -e "\033[1;34m=== DanceLessonsCoach Graceful Shutdown Test ===\033[0m" +echo -e "\033[1;34m=== dance-lessons-coach Graceful Shutdown Test ===\033[0m" echo "" # Clean up any existing server diff --git a/scripts/test-local-ci-cd.sh b/scripts/test-local-ci-cd.sh index ce9020a..0d8e5eb 100755 --- a/scripts/test-local-ci-cd.sh +++ b/scripts/test-local-ci-cd.sh @@ -3,7 +3,7 @@ # Simulates the CI/CD pipeline but builds Docker image locally # Use this for local development and testing without Gitea -set -e +set -eu echo "πŸš€ Local CI/CD Testing" echo "======================" @@ -16,53 +16,162 @@ if ! command -v go >/dev/null 2>&1; then exit 1 fi +# Assume Docker is available (required for this workflow) if ! command -v docker >/dev/null 2>&1; then - echo "⚠️ Docker not found. Docker build steps will be skipped" - HAS_DOCKER=false -else - HAS_DOCKER=true + echo "❌ Docker is required for this CI/CD workflow" + echo "Please install Docker and Docker Compose plugin" + exit 1 +fi + +# Check for docker compose plugin +if ! docker compose version >/dev/null 2>&1; then + echo "⚠️ Docker Compose plugin not found. Installing..." + sudo apt-get update && sudo apt-get install -y docker-compose-plugin fi echo "βœ… Environment ready" echo "" -# 2. Install dependencies -echo "2. Installing dependencies..." -go mod tidy -echo "βœ… Dependencies installed" +# 2. Calculate dependency hash (match CI workflow) +echo "2. Calculating dependency hash..." +# Use shasum on macOS, sha256sum on Linux +if command -v sha256sum >/dev/null 2>&1; then + export DEPS_HASH=$(sha256sum go.mod go.sum | sha256sum | cut -d' ' -f1 | head -c 12) +else + export DEPS_HASH=$(shasum -a 256 go.mod go.sum | shasum -a 256 | cut -d' ' -f1 | head -c 12) +fi +echo "Dependency hash: $DEPS_HASH" +echo "βœ… Dependency hash calculated" echo "" -# 3. Install swag and generate docs -echo "3. Generating Swagger documentation..." -if [ ! -f pkg/server/docs/swagger.json ]; then - echo "πŸ“ Generating Swagger docs..." - go install github.com/swaggo/swag/cmd/swag@latest - cd pkg/server && go generate - cd ../.. - echo "βœ… Swagger documentation generated" +# 3. Check for Docker cache +echo "3. Checking for Docker build cache..." +IMAGE_NAME="gitea.arcodange.lab/arcodange/dance-lessons-coach-build-cache:$DEPS_HASH" + +# Try to pull the cache image +if docker pull "$IMAGE_NAME" >/dev/null 2>&1; then + echo "βœ… Cache hit - using existing build cache" + USE_DOCKER_CACHE=true else - echo "βœ… Swagger documentation already exists" + echo "⚠️ Cache miss - will build without cache" + USE_DOCKER_CACHE=false fi echo "" -# 4. Build and test -echo "4. Building and testing..." -go build ./... +# 4. Start PostgreSQL with Docker Compose +echo "4. Starting PostgreSQL..." +docker compose -f docker-compose.yml up -d postgres + +# Wait for PostgreSQL to be ready +echo "Waiting for PostgreSQL to be ready..." +for i in {1..30}; do + if docker exec dance-lessons-coach-postgres pg_isready -U postgres; then + echo "βœ… PostgreSQL is ready!" + break + fi + echo "Waiting for PostgreSQL... ($i/30)" + sleep 2 +done + +# Set PostgreSQL environment variables for BDD tests +export DLC_DATABASE_HOST="localhost" # PostgreSQL port is mapped to host +export DLC_DATABASE_PORT=5432 +export DLC_DATABASE_USER=postgres +export DLC_DATABASE_PASSWORD=postgres +export DLC_DATABASE_NAME=dance_lessons_coach_bdd_test +export DLC_DATABASE_SSL_MODE=disable +echo "" + +# 5. Install dependencies +if [ "$USE_DOCKER_CACHE" = true ]; then + echo "5. Checking dependencies..." + echo "βœ… Using pre-installed dependencies from Docker cache" +else + echo "5. Installing dependencies..." + go mod tidy +fi +echo "βœ… Dependencies ready" +echo "" + +# 6. Generate Swagger Docs +if [ "$USE_DOCKER_CACHE" = true ]; then + echo "6. Generating Swagger documentation..." + echo "Running in Docker container..." + docker run --rm \ + --network dance-lessons-coach-network \ + -v "$(pwd):/workspace" \ + -w /workspace/pkg/server \ + "$IMAGE_NAME" \ + sh -c "go generate" +else + echo "6. Generating Swagger documentation..." + echo "Running natively..." + cd pkg/server && go generate + cd ../.. +fi +echo "βœ… Swagger documentation generated" +echo "" + +# 7. Build and test +if [ "$USE_DOCKER_CACHE" = true ]; then + echo "7. Building and testing..." + echo "Running in Docker container..." + docker run --rm \ + --network dance-lessons-coach-network \ + -v "$(pwd):/workspace" \ + -w /workspace \ + "$IMAGE_NAME" \ + sh -c "go build ./..." +else + echo "7. Building and testing..." + echo "Running natively..." + go build ./... +fi echo "βœ… Code compiled successfully" -go test ./... -cover -v +if [ "$USE_DOCKER_CACHE" = true ]; then + echo "Running in Docker container with PostgreSQL..." + docker run --rm \ + --network dance-lessons-coach-network \ + -v "$(pwd):/workspace" \ + -w /workspace \ + -e DLC_DATABASE_HOST=dance-lessons-coach-postgres \ + -e DLC_DATABASE_PORT=5432 \ + -e DLC_DATABASE_USER=postgres \ + -e DLC_DATABASE_PASSWORD=postgres \ + -e DLC_DATABASE_NAME=dance_lessons_coach_bdd_test \ + -e DLC_DATABASE_SSL_MODE=disable \ + "$IMAGE_NAME" \ + sh -c "go test ./... -coverprofile=coverage.out -v && go tool cover -func=coverage.out > coverage.txt" +else + echo "Running natively with Docker Compose PostgreSQL..." + go test ./... -coverprofile=coverage.out -v + go tool cover -func=coverage.out > coverage.txt +fi echo "βœ… Tests passed" echo "" -# 5. Build binaries -echo "5. Building binaries..." -./scripts/build.sh +# 8. Build binaries +if [ "$USE_DOCKER_CACHE" = true ]; then + echo "8. Building binaries..." + echo "Running in Docker container..." + docker run --rm \ + --network dance-lessons-coach-network \ + -v "$(pwd):/workspace" \ + -w /workspace \ + "$IMAGE_NAME" \ + sh -c "./scripts/build.sh" +else + echo "8. Building binaries..." + echo "Running natively..." + ./scripts/build.sh +fi echo "βœ… Binaries built" ls -la bin/ echo "" -# 6. Version bump simulation -echo "6. Version bump simulation..." +# 9. Version bump simulation +echo "9. Version bump simulation..." LAST_COMMIT=$(git log -1 --pretty=%B | head -1) echo "Last commit: $LAST_COMMIT" @@ -85,152 +194,170 @@ CURRENT_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" echo "πŸ“Š Current version: $CURRENT_VERSION" echo "" -# 7. Local Docker build instructions -if [ "$HAS_DOCKER" = true ]; then - echo "🐳 LOCAL DOCKER BUILD INSTRUCTIONS" - echo "================================" - echo "" - - echo "1. Build Docker image locally:" - echo " docker build -t dance-lessons-coach:$CURRENT_VERSION ." - echo "" - - echo "2. Tag the image:" - echo " docker tag dance-lessons-coach:$CURRENT_VERSION dance-lessons-coach:latest" - echo "" - - echo "3. Test the local image (check port availability first):" - echo " docker run -d -p 8080:8080 dance-lessons-coach:$CURRENT_VERSION" - echo " # Or use alternative port if 8080 is in use:" - echo " docker run -d -p 8081:8080 dance-lessons-coach:$CURRENT_VERSION" - echo "" - echo "4. Branch-specific container naming (recommended):" - echo " BRANCH=\"(git rev-parse --abbrev-ref HEAD | tr '/' '-')" - echo " docker run -d -p 8080:8080 --name dance-lessons-coach-\"$BRANCH\" dance-lessons-coach:$CURRENT_VERSION" - echo "" - - echo "5. Test API endpoints:" - echo " curl http://localhost:8080/api/health" - echo " curl http://localhost:8080/api/v1/greet/YourName" - echo "" - - echo "5. Clean up:" - echo " docker stop && docker rm " - echo "" - - echo "πŸ’‘ Tip: Use 'docker images' to see your built images" - echo "πŸ’‘ Use 'docker ps' to see running containers" - echo "" - - # Ask if user wants to build Docker image now - read -p "πŸš€ Do you want to build the Docker image now? (y/n): " -n 1 -r - echo "" - if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "🐳 Building Docker image..." +# 10. Local Docker build instructions +echo "🐳 LOCAL DOCKER BUILD INSTRUCTIONS" +echo "================================" +echo "" + +echo "1. Build Docker image locally (development):" +echo " docker build -t dance-lessons-coach:$CURRENT_VERSION ." +echo "" + +echo "2. Build production image using docker/Dockerfile.prod:" +echo " # Note: Local docker/Dockerfile.prod uses 'latest' tag for testing" +echo " docker build -t dance-lessons-coach-prod:$CURRENT_VERSION -f docker/Dockerfile.prod ." +echo " # For CI/CD, the workflow generates correct docker/Dockerfile.prod with dependency hash" +echo "" + +echo "3. Compare image sizes:" +echo " docker images | grep dance-lessons-coach" +echo "" + +echo "4. Tag the image:" +echo " docker tag dance-lessons-coach:$CURRENT_VERSION dance-lessons-coach:latest" +echo "" + +echo "5. Test the local image (check port availability first):" +echo " docker run -d -p 8080:8080 dance-lessons-coach:$CURRENT_VERSION" +echo " # Or use alternative port if 8080 is in use:" +echo " docker run -d -p 8081:8080 dance-lessons-coach:$CURRENT_VERSION" +echo "" +echo "6. Branch-specific container naming (recommended):" +echo " BRANCH=\"$(git rev-parse --abbrev-ref HEAD | tr '/' '-')\"" +echo " docker run -d -p 8080:8080 --name dance-lessons-coach-\"$BRANCH\" dance-lessons-coach:$CURRENT_VERSION" +echo "" + +echo "7. Test API endpoints:" +echo " curl http://localhost:8080/api/health" +echo " curl http://localhost:8080/api/v1/greet/YourName" +echo "" + +echo "8. Clean up:" +echo " docker stop && docker rm " +echo "" + +echo "πŸ’‘ Tip: Use 'docker images' to see your built images" +echo "πŸ’‘ Use 'docker ps' to see running containers" +echo "" + +# Ask if user wants to build Docker image now +read -p "πŸš€ Do you want to build the Docker image now? (y/n): " -n 1 -r +echo "" +if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "🐳 Building Docker image..." + read -p "πŸ“‹ Build (d)development or (p)production image? [d/p]: " -n 1 -r +echo "" + if [[ $REPLY =~ ^[Pp]$ ]]; then + echo "πŸ—οΈ Building production image with docker/Dockerfile.prod..." + docker build -t dance-lessons-coach-prod:$CURRENT_VERSION -f docker/Dockerfile.prod . + docker tag dance-lessons-coach-prod:$CURRENT_VERSION dance-lessons-coach-prod:latest + echo "βœ… Production Docker image built: dance-lessons-coach-prod:$CURRENT_VERSION" + CONTAINER_IMAGE="dance-lessons-coach-prod:$CURRENT_VERSION" + else + echo "πŸ—οΈ Building development image with Dockerfile..." docker build -t dance-lessons-coach:$CURRENT_VERSION . docker tag dance-lessons-coach:$CURRENT_VERSION dance-lessons-coach:latest - echo "βœ… Docker image built: dance-lessons-coach:$CURRENT_VERSION" - echo "" - - # Check if port 8080 is available - echo "πŸ” Checking port availability..." - if lsof -i :8080 > /dev/null 2>&1; then - echo "⚠️ Port 8080 is already in use" - read -p "πŸš€ Do you want to use a different port? (y/n): " -n 1 -r - echo "" - if [[ $REPLY =~ ^[Yy]$ ]]; then - read -p "Enter port number (e.g., 8081): " CUSTOM_PORT - echo "" - PORT=$CUSTOM_PORT - else - echo "ℹ️ Using port 8080 anyway (may fail if service is running)" - PORT=8080 - fi + echo "βœ… Development Docker image built: dance-lessons-coach:$CURRENT_VERSION" + CONTAINER_IMAGE="dance-lessons-coach:$CURRENT_VERSION" + fi +echo "" + + # Check if port 8080 is available + echo "πŸ” Checking port availability..." + if lsof -i :8080 > /dev/null 2>&1; then + echo "⚠️ Port 8080 is already in use" + read -p "πŸš€ Do you want to use a different port? (y/n): " -n 1 -r +echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + read -p "Enter port number (e.g., 8081): " CUSTOM_PORT +echo "" + PORT=$CUSTOM_PORT else - echo "βœ… Port 8080 is available" + echo "ℹ️ Using port 8080 anyway (may fail if service is running)" PORT=8080 fi - - read -p "πŸš€ Do you want to run the container now on port $PORT? (y/n): " -n 1 -r - echo "" - if [[ $REPLY =~ ^[Yy]$ ]]; then - # Get current branch name for container naming - BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD | tr '/' '-') - CONTAINER_NAME="dance-lessons-coach-$BRANCH_NAME" - - echo "🐳 Preparing container '$CONTAINER_NAME' on port $PORT..." - - # Remove existing container if it exists - if docker ps -a --format '{{.Names}}' | grep -q "^$CONTAINER_NAME$"; then - echo "⚠️ Container '$CONTAINER_NAME' already exists - removing it..." - docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true - docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true - echo "βœ… Old container removed" - fi - - # Also remove the generic test container if it exists - if docker ps -a --format '{{.Names}}' | grep -q "^dance-lessons-coach-test$"; then - echo "⚠️ Generic test container exists - removing it..." - docker stop dance-lessons-coach-test > /dev/null 2>&1 || true - docker rm dance-lessons-coach-test > /dev/null 2>&1 || true - echo "βœ… Old generic container removed" - fi - - echo "🐳 Starting container '$CONTAINER_NAME' on port $PORT..." - docker run -d -p $PORT:8080 --name "$CONTAINER_NAME" dance-lessons-coach:$CURRENT_VERSION - echo "βœ… Container '$CONTAINER_NAME' started on port $PORT" - echo "" - - # Wait for container to be ready - echo "πŸ•’ Waiting for container to be ready..." - MAX_ATTEMPTS=10 - ATTEMPT=1 - READY=false - - while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do - if curl -s http://localhost:$PORT/api/health | grep -q "healthy"; then - READY=true - break - fi - sleep 1 - ATTEMPT=$((ATTEMPT + 1)) - echo "πŸ•’ Attempt $ATTEMPT/$MAX_ATTEMPTS..." - done - - if [ "$READY" = true ]; then - echo "βœ… Container is ready!" - else - echo "❌ Container failed to start properly" - echo "πŸ“‹ Container logs:" - docker logs dance-lessons-coach-test - echo "" - echo "πŸ’‘ Check container status with: docker ps -a" - echo "πŸ’‘ View full logs with: docker logs dance-lessons-coach-test" - continue # Skip endpoint testing - fi - - echo "πŸ“‹ Testing endpoints..." - - if curl -s http://localhost:$PORT/api/health | grep -q "healthy"; then - echo "βœ… Health check passed" - else - echo "❌ Health check failed" - fi - - if curl -s http://localhost:$PORT/api/v1/greet/ | grep -q "Hello"; then - echo "βœ… Greet endpoint working" - else - echo "❌ Greet endpoint failed" - fi - - echo "" - echo "πŸ“– Swagger UI available at: http://localhost:$PORT/swagger/" - echo "πŸ’‘ Press Ctrl+C to stop the container when done" - echo " Or run: docker stop $CONTAINER_NAME && docker rm $CONTAINER_NAME" - fi + else + echo "βœ… Port 8080 is available" + PORT=8080 + fi + + read -p "πŸš€ Do you want to run the container now on port $PORT? (y/n): " -n 1 -r +echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + # Get current branch name for container naming + BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD | tr '/' '-') + CONTAINER_NAME="dance-lessons-coach-$BRANCH_NAME" + + echo "🐳 Preparing container '$CONTAINER_NAME' on port $PORT..." + + # Remove existing container if it exists + if docker ps -a --format '{{.Names}}' | grep -q "^$CONTAINER_NAME$"; then + echo "⚠️ Container '$CONTAINER_NAME' already exists - removing it..." + docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true + docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true + echo "βœ… Old container removed" + fi + + # Also remove the generic test container if it exists + if docker ps -a --format '{{.Names}}' | grep -q "^dance-lessons-coach-test$"; then + echo "⚠️ Generic test container exists - removing it..." + docker stop dance-lessons-coach-test > /dev/null 2>&1 || true + docker rm dance-lessons-coach-test > /dev/null 2>&1 || true + echo "βœ… Old generic container removed" + fi + + echo "🐳 Starting container '$CONTAINER_NAME' on port $PORT..." + docker run -d -p $PORT:8080 --name "$CONTAINER_NAME" "$CONTAINER_IMAGE" + echo "βœ… Container '$CONTAINER_NAME' started on port $PORT" + echo "" + + # Wait for container to be ready + echo "πŸ•’ Waiting for container to be ready..." + MAX_ATTEMPTS=10 + ATTEMPT=1 + READY=false + + while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do + if curl -s http://localhost:$PORT/api/health | grep -q "healthy"; then + READY=true + break + fi + sleep 1 + ATTEMPT=$((ATTEMPT + 1)) + echo "πŸ•’ Attempt $ATTEMPT/$MAX_ATTEMPTS..." + done + + if [ "$READY" = true ]; then + echo "βœ… Container is ready!" + else + echo "❌ Container failed to start properly" + echo "πŸ“‹ Container logs:" + docker logs dance-lessons-coach-test + echo "" + echo "πŸ’‘ Check container status with: docker ps -a" + echo "πŸ’‘ View full logs with: docker logs dance-lessons-coach-test" + continue # Skip endpoint testing + fi + + echo "πŸ“‹ Testing endpoints..." + + if curl -s http://localhost:$PORT/api/health | grep -q "healthy"; then + echo "βœ… Health check passed" + else + echo "❌ Health check failed" + fi + + if curl -s http://localhost:$PORT/api/v1/greet/ | grep -q "Hello"; then + echo "βœ… Greet endpoint working" + else + echo "❌ Greet endpoint failed" + fi + + echo "" + echo "πŸ“– Swagger UI available at: http://localhost:$PORT/swagger/" + echo "πŸ’‘ Press Ctrl+C to stop the container when done" + echo " Or run: docker stop $CONTAINER_NAME && docker rm $CONTAINER_NAME" fi -else - echo "ℹ️ Docker not available - skipping Docker build instructions" fi echo "" @@ -238,18 +365,22 @@ echo "βœ… LOCAL CI/CD TEST COMPLETE" echo "===========================" echo "" echo "πŸ“‹ What was tested:" +echo " βœ… Dependency hash calculation (matching CI workflow)" +echo " βœ… Docker cache detection and usage" +echo " βœ… PostgreSQL service with Docker Compose" echo " βœ… Go dependencies installation" echo " βœ… Swagger documentation generation" echo " βœ… Code compilation" echo " βœ… Unit tests with coverage" echo " βœ… Binary build" echo " βœ… Version bump simulation" -if [ "$HAS_DOCKER" = true ]; then - echo " βœ… Docker build (if chosen)" -fi +echo " βœ… Docker build (development and/or production if chosen)" echo "" echo "🎯 When ready for production:" echo " Push to main branch to trigger full CI/CD pipeline" echo " Docker image will be built and pushed to Gitea Container Registry" echo "" -echo "πŸ’‘ Local testing complete! Your changes are ready for CI/CD." \ No newline at end of file +echo "πŸ’‘ Local testing complete! Your changes are ready for CI/CD." +echo "πŸ’‘ This script now matches the Gitea workflow structure and behavior." +# ⚠️ IMPORTANT: Local Dockerfile.prod uses 'latest' tag for testing only +# βœ… CI/CD workflow generates correct Dockerfile.prod with dependency hash \ No newline at end of file diff --git a/scripts/test-opentelemetry.sh b/scripts/test-opentelemetry.sh index a6abd15..750fc15 100755 --- a/scripts/test-opentelemetry.sh +++ b/scripts/test-opentelemetry.sh @@ -1,15 +1,15 @@ #!/bin/bash -# DanceLessonsCoach OpenTelemetry Test Script +# dance-lessons-coach OpenTelemetry Test Script # This script tests OpenTelemetry integration with Jaeger set -e -echo -e "\033[1;34m=== DanceLessonsCoach OpenTelemetry Test ===\033[0m" +echo -e "\033[1;34m=== dance-lessons-coach OpenTelemetry Test ===\033[0m" echo "" # Configuration -PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/DanceLessonsCoach" +PROJECT_DIR="/Users/gabrielradureau/Work/Vibe/dance-lessons-coach" SERVER_CMD="./scripts/start-server.sh" LOG_FILE="server.log" PID_FILE="server.pid" @@ -47,7 +47,7 @@ fi echo "Starting server with OpenTelemetry enabled..." DLC_TELEMETRY_ENABLED=true DLC_TELEMETRY_OTLP_ENDPOINT="localhost:4317" DLC_TELEMETRY_INSECURE=true \ - DLC_TELEMETRY_SERVICE_NAME="DanceLessonsCoach" $SERVER_CMD start + DLC_TELEMETRY_SERVICE_NAME="dance-lessons-coach" $SERVER_CMD start sleep 3 echo "Testing API endpoints..." @@ -77,7 +77,7 @@ echo -e "\033[0;32mβœ… OpenTelemetry Test Complete!\033[0m" echo "" echo "To view traces in Jaeger:" echo "1. Open http://localhost:16686 in your browser" -echo "2. Select 'DanceLessonsCoach' service" +echo "2. Select 'dance-lessons-coach' service" echo "3. Click 'Find Traces' button" echo "" echo "You should see traces for:" diff --git a/scripts/validate-cicd-comprehensive.sh b/scripts/validate-cicd-comprehensive.sh index 827643b..e2e18a0 100755 --- a/scripts/validate-cicd-comprehensive.sh +++ b/scripts/validate-cicd-comprehensive.sh @@ -171,4 +171,4 @@ echo "πŸ’‘ Next Steps:" echo " 1. Test with Docker: ./scripts/test-cicd-simple.sh" echo " 2. Commit changes: git commit -m 'πŸ€– ci: validate workflow'" echo " 3. Push to trigger: git push origin main" -echo " 4. Monitor pipeline: https://gitea.arcodange.lab/arcodange/DanceLessonsCoach/actions" +echo " 4. Monitor pipeline: https://gitea.arcodange.lab/arcodange/dance-lessons-coach/actions" diff --git a/scripts/version-bump.sh b/scripts/version-bump.sh index e9285b8..1422349 100755 --- a/scripts/version-bump.sh +++ b/scripts/version-bump.sh @@ -1,5 +1,5 @@ #!/bin/bash -# DanceLessonsCoach Version Bump Script +# dance-lessons-coach Version Bump Script # Usage: ./scripts/version-bump.sh [major|minor|patch|pre|release] set -e @@ -81,7 +81,7 @@ echo "πŸ”œ New version: $NEW_VERSION" # Update VERSION file cat > "$VERSION_FILE" << VERSION_EOF -# DanceLessonsCoach Version +# dance-lessons-coach Version # Current Version (Semantic Versioning) MAJOR=$MAJOR @@ -139,7 +139,7 @@ if [ -f "$README_MD" ]; then # Use awk to update version badge awk -v new_version="$NEW_VERSION" '{ if ($0 ~ /Version.*badge.*version/) { - print "[![Version](https://img.shields.io/badge/version-" new_version "-blue.svg)](https://gitea.arcodange.fr/arcodange/DanceLessonsCoach/releases)" + print "[![Version](https://img.shields.io/badge/version-" new_version "-blue.svg)](https://gitea.arcodange.fr/arcodange/dance-lessons-coach/releases)" } else { print $0 }