first commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# 🛠️ GoPrint Code Generator Tools
|
||||
|
||||
Kumpulan skrip otomatisasi (*Code Generator*) ini dirancang untuk mempercepat proses *development* aplikasi di ekosistem GoPrint.
|
||||
Dengan skrip ini, Anda dapat men-generate *boilerplate* (kode dasar) ratusan baris untuk arsitektur **Clean Architecture**, **CQRS**, **REST API**, dan **gRPC** secara instan.
|
||||
|
||||
Generator ini sangat cerdas, ia dapat membangun kode berdasarkan **Skema Tabel Database (SQL)** maupun **Respons Payload (JSON)** dari API pihak ketiga.
|
||||
|
||||
---
|
||||
|
||||
## 1. 🚀 Advanced Context Generator (`context.sh`)
|
||||
|
||||
Skrip utama (*Swiss Army Knife*) untuk men-generate seluruh lapisan modul aplikasi Anda.
|
||||
|
||||
**Fitur Unggulan:**
|
||||
- 🧩 **Dual Parser**: Mendukung input dari file SQL (`CREATE TABLE`) maupun file JSON (`Response API`).
|
||||
- 🔑 **Dynamic Primary Key**: Otomatis mendeteksi *Primary Key* tipe `int64` maupun `string/UUID` dan menyesuaikan *routing* ID-nya.
|
||||
- 🗑️ **Smart Soft-Delete**: Hanya membuat implementasi GORM *Soft-Delete* jika tabel/JSON tersebut benar-benar memiliki field `deleted_at`.
|
||||
- 📁 **Auto-Package Naming**: Anda bebas meletakkan modul di *path* mana pun, nama *package* Go akan otomatis menyesuaikan nama folder terakhir.
|
||||
- 📡 **All-in-One Generation**: Sekali klik langsung membuat: `Entity`, `DTO`, `Mapper`, `Repository (CQRS)`, `Service`, `REST Handler`, `Proto File`, dan `gRPC Handler`.
|
||||
|
||||
### 📝 Aturan Penulisan (CLI Syntax):
|
||||
```bash
|
||||
./scripts/context.sh [OPTIONS]
|
||||
|
||||
Options:
|
||||
-s, --sql FILE [Wajib*] Path ke file SQL yang berisi CREATE TABLE (Pilih salah satu dengan -j)
|
||||
-j, --json FILE [Wajib*] Path ke file JSON payload response (Pilih salah satu dengan -s)
|
||||
-d, --dir PATH [Wajib] Path destinasi modul/folder Anda (contoh: master/role)
|
||||
-t, --table NAME [Opsional] Menimpa nama tabel secara manual (Sangat disarankan saat memakai -j)
|
||||
-g, --generate TYPE [Opsional] Target generate: domain | handler | proto | grpc | all (Default: all)
|
||||
-v, --verbose [Opsional] Tampilkan log proses secara mendetail
|
||||
# Contoh menggunakan file users.sql dan disimpan di master/users
|
||||
./scripts/context.sh -s db/migrations/users.sql -d master/users -g all
|
||||
|
||||
# Contoh riil menggunakan file role_pages.sql dan disimpan di master/role/pages
|
||||
./scripts/context.sh -s internal/infrastructure/database/sql/00001_role_pages.sql -d master/role/pages -g all
|
||||
# Contoh menggunakan file users.sql dan disimpan di master/users
|
||||
./scripts/context.sh -s db/migrations/users.sql -d master/users -g all
|
||||
./scripts/context.sh -s internal/infrastructure/database/sql/province.sql -d master/reference/province -g grpc
|
||||
./scripts/context.sh -s db/migrations/users.sql -d master/users -v
|
||||
internal/
|
||||
└── master/
|
||||
└── reference/
|
||||
└── province/
|
||||
├── dto.go # Struct Request & Response (Auto-validation tags)
|
||||
├── entity.go # GORM Struct (Auto DB tags)
|
||||
├── repository.go # CQRS Repository (Command & Query builder)
|
||||
├── service.go # Business Logic Layer
|
||||
├── service_test.go # Boilerplate Unit Test & Mocking
|
||||
└── mapper.go # Logic konversi Entity <-> DTO
|
||||
|
||||
internal/
|
||||
└── infrastructure/
|
||||
└── transport/
|
||||
├── http/
|
||||
│ └── handlers/master/reference/province/
|
||||
│ └── province_handler.go # REST API Controller (Gin) dgn anotasi Swagger
|
||||
└── grpc/
|
||||
├── handlers/master/reference/province/
|
||||
│ ├── province_grpc_handler.go
|
||||
│ └── province_grpc_mapper.go
|
||||
├── proto/master/reference/province/v1/
|
||||
│ └── province.proto # Schema antarmuka gRPC
|
||||
└── gen/master/reference/province/v1/
|
||||
└── ... (Hasil Compile .pb.go)
|
||||
./scripts/proto.sh
|
||||
./scripts/proto.sh internal/infrastructure/transport/grpc/proto/master/reference/province/v1
|
||||
# 1. Mengecek daftar service yang terbuka (tes koneksi Server Reflection)
|
||||
grpcurl -plaintext localhost:50051 list
|
||||
|
||||
# 2. Mengecek rincian method yang dimiliki oleh suatu service
|
||||
grpcurl -plaintext localhost:50051 list master.v1.RoleAccessRolMasterService
|
||||
|
||||
# 3. Memanggil Method dengan mengirim Payload JSON
|
||||
grpcurl -plaintext -d '{
|
||||
"id": 1
|
||||
}' localhost:50051 master.v1.RoleAccessRolMasterService/GetRoleAccessRolMaster
|
||||
|
||||
<!--
|
||||
[PROMPT_SUGGESTION]Bagaimana cara kerja fitur `-j` atau `--json` pada `context.sh` untuk mem-parsing payload API eksternal?[/PROMPT_SUGGESTION]
|
||||
[PROMPT_SUGGESTION]Jelaskan alur registrasi handler REST dan gRPC di `main.go` setelah sebuah modul baru di-generate.[/PROMPT_SUGGESTION]
|
||||
-->
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
echo "Building application..."
|
||||
go build -o bin/service cmd/api/main.go
|
||||
Executable
+1958
File diff suppressed because it is too large
Load Diff
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "⚠️ scripts/grpc.sh is deprecated to avoid code duplication."
|
||||
echo "To generate gRPC protobuf files, handlers, and mappers dynamically based on the database schema, please use scripts/context.sh instead."
|
||||
echo ""
|
||||
echo "Usage example:"
|
||||
echo " ./scripts/context.sh -s path/to/sql -d your/module/dir -g grpc"
|
||||
echo " ./scripts/context.sh -s path/to/sql -d your/module/dir -g all"
|
||||
exit 1
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script untuk menjalankan database migrations
|
||||
|
||||
set -e # Exit immediately if a command exits with a non-zero status
|
||||
|
||||
echo "🔧 Running database migrations..."
|
||||
|
||||
# Warna untuk output
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Load environment variables
|
||||
if [ -f .env ]; then
|
||||
export $(cat .env | grep -v '^#' | xargs)
|
||||
echo -e "${GREEN}✅ Environment variables loaded${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ .env file not found, using system environment${NC}"
|
||||
fi
|
||||
|
||||
# Fungsi untuk menjalankan migration
|
||||
run_migration() {
|
||||
local db_type=$1
|
||||
|
||||
case $db_type in
|
||||
"postgres")
|
||||
echo -e "${YELLOW}📊 Running PostgreSQL migrations...${NC}"
|
||||
# Jika menggunakan golang-migrate
|
||||
if command -v migrate &> /dev/null; then
|
||||
migrate -path internal/infrastructure/database/migrations -database "postgresql://$DB_USER:$DB_PASSWORD@$DB_HOST:$DB_PORT/$DB_NAME?sslmode=disable" up
|
||||
# Jika menggunakan go run dengan gorm
|
||||
elif command -v go &> /dev/null; then
|
||||
go run cmd/migrate/main.go
|
||||
else
|
||||
echo -e "${RED}❌ No migration tool found${NC}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"mysql")
|
||||
echo -e "${YELLOW}📊 Running MySQL migrations...${NC}"
|
||||
if command -v migrate &> /dev/null; then
|
||||
migrate -path internal/infrastructure/database/migrations -database "mysql://$DB_USER:$DB_PASSWORD@tcp($DB_HOST:$DB_PORT)/$DB_NAME" up
|
||||
elif command -v go &> /dev/null; then
|
||||
go run cmd/migrate/main.go
|
||||
else
|
||||
echo -e "${RED}❌ No migration tool found${NC}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"mongodb")
|
||||
echo -e "${YELLOW}📊 Running MongoDB migrations...${NC}"
|
||||
# MongoDB biasanya tidak menggunakan traditional migrations
|
||||
echo -e "${GREEN}✅ MongoDB migrations skipped (schema-less)${NC}"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}❌ Unsupported database type: $db_type${NC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Cek apakah ada database configuration
|
||||
if [ -z "$DB_TYPE" ]; then
|
||||
echo -e "${YELLOW}⚠️ DB_TYPE not set, defaulting to postgres${NC}"
|
||||
DB_TYPE="postgres"
|
||||
fi
|
||||
|
||||
# Cek dan buat directory migrations jika belum ada
|
||||
MIGRATIONS_DIR="internal/infrastructure/database/migrations"
|
||||
if [ ! -d "$MIGRATIONS_DIR" ]; then
|
||||
echo -e "${YELLOW}📁 Creating migrations directory...${NC}"
|
||||
mkdir -p $MIGRATIONS_DIR
|
||||
fi
|
||||
|
||||
# Cek koneksi database
|
||||
echo -e "${YELLOW}🔍 Testing database connection...${NC}"
|
||||
if go run scripts/test_db_connection.go; then
|
||||
echo -e "${GREEN}✅ Database connection successful${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Database connection failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Jalankan migration
|
||||
run_migration $DB_TYPE
|
||||
|
||||
echo -e "${GREEN}✅ Database migrations completed successfully${NC}"
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Flexible gRPC and Protobuf code generator for the service project.
|
||||
#
|
||||
# This script can:
|
||||
# 1. Generate code for a specific proto directory.
|
||||
# 2. Automatically find and generate code for all proto files in the project.
|
||||
|
||||
# --- Configuration ---
|
||||
set -e # Exit immediately if a command exits with a non-zero status.
|
||||
set -o pipefail # Return value of a pipeline is the value of the last command to exit with a non-zero status
|
||||
|
||||
# --- Colors for output ---
|
||||
readonly NC='\033[0m' # No Color
|
||||
readonly RED='\033[0;31m'
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly YELLOW='\033[1;33m'
|
||||
readonly BLUE='\033[0;34m'
|
||||
readonly PURPLE='\033[0;35m'
|
||||
readonly CYAN='\033[0;36m'
|
||||
|
||||
# --- Helper Functions ---
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
log_header() { echo -e "\n${PURPLE}==== $1 ====${NC}"; }
|
||||
|
||||
# --- Show Help ---
|
||||
show_help() {
|
||||
cat << EOF
|
||||
${YELLOW}Flexible gRPC and Protobuf Code Generator${NC}
|
||||
|
||||
This script generates Go code from .proto files using the recommended 'paths=import' method.
|
||||
|
||||
${YELLOW}USAGE:${NC}
|
||||
$(basename "$0") [path_to_proto_dir]
|
||||
|
||||
${YELLOW}DESCRIPTION:${NC}
|
||||
- If a ${CYAN}[path_to_proto_dir]${NC} is provided, it generates code only for .proto files in that directory.
|
||||
${CYAN}Example:${NC} $(basename "$0") internal/infrastructure/transport/grpc/proto/permission/v1
|
||||
|
||||
- If no path is provided, it automatically finds and generates code for ${CYAN}all .proto files${NC} within the project.
|
||||
${CYAN}Example:${NC} $(basename "$0")
|
||||
|
||||
${YELLOW}REQUIREMENTS:${NC}
|
||||
- protoc
|
||||
- protoc-gen-go
|
||||
- protoc-gen-go-grpc
|
||||
|
||||
Make sure these are installed and available in your system's PATH.
|
||||
To install them:
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||
EOF
|
||||
}
|
||||
|
||||
# --- Check for required tools ---
|
||||
check_dependencies() {
|
||||
log_header "Checking Dependencies"
|
||||
local missing_deps=false
|
||||
for cmd in protoc protoc-gen-go protoc-gen-go-grpc; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
log_error "Dependency not found: ${CYAN}$cmd${NC}"
|
||||
missing_deps=true
|
||||
else
|
||||
log_success "Found: ${CYAN}$cmd${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$missing_deps" = true ]; then
|
||||
log_error "Please install the missing dependencies. See help for instructions."
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Main Logic ---
|
||||
main() {
|
||||
# Handle help flag
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
show_help
|
||||
exit 0
|
||||
fi
|
||||
|
||||
check_dependencies
|
||||
|
||||
# Get project root directory
|
||||
local project_root
|
||||
project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$project_root"
|
||||
log_info "Operating from project root: ${CYAN}$project_root${NC}"
|
||||
|
||||
local proto_files=()
|
||||
if [ -n "$1" ]; then
|
||||
# Case 1: A specific directory is provided
|
||||
local proto_dir_path="$1"
|
||||
if [ ! -d "$project_root/$proto_dir_path" ]; then
|
||||
log_info "Directory not found. Creating new directory: ${CYAN}$proto_dir_path${NC}"
|
||||
mkdir -p "$project_root/$proto_dir_path"
|
||||
fi
|
||||
log_header "Generating for specific directory: ${CYAN}$proto_dir_path${NC}"
|
||||
while IFS= read -r -d '' file; do
|
||||
proto_files+=("$file")
|
||||
done < <(find "$proto_dir_path" -name '*.proto' -print0)
|
||||
else
|
||||
# Case 2: No directory provided, find all protos
|
||||
log_header "Generating for all .proto files in the project"
|
||||
while IFS= read -r -d '' file; do
|
||||
proto_files+=("$file")
|
||||
done < <(find . -name '*.proto' -not -path './vendor/*' -print0)
|
||||
fi
|
||||
|
||||
if [ ${#proto_files[@]} -eq 0 ]; then
|
||||
log_warning "No .proto files found to generate."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log_info "Found the following .proto files to process:"
|
||||
for f in "${proto_files[@]}"; do echo -e "${CYAN}$f${NC}"; done
|
||||
|
||||
# --- Generation Process ---
|
||||
log_header "Starting Code Generation"
|
||||
|
||||
# The protoc command uses 'paths=import', which respects the 'go_package' option in .proto files.
|
||||
# This is the modern and recommended approach.
|
||||
# -I. : Search for imports in the project root.
|
||||
# --go_out=. : Output generated files relative to the project root.
|
||||
protoc -I. \
|
||||
--experimental_allow_proto3_optional \
|
||||
--go_out=. --go_opt=paths=import \
|
||||
--go-grpc_out=. --go-grpc_opt=paths=import \
|
||||
"${proto_files[@]}"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
log_error "Protocol Buffer code generation failed."
|
||||
log_error "Please check the output from 'protoc' above for details."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Protocol Buffer code generated successfully."
|
||||
|
||||
# --- Post-generation ---
|
||||
log_header "Post-generation Steps"
|
||||
log_info "Running 'go mod tidy' to sync dependencies..."
|
||||
go mod tidy
|
||||
log_success "'go mod tidy' completed."
|
||||
echo ""
|
||||
log_success "All tasks finished successfully! ✨"
|
||||
}
|
||||
|
||||
# --- Run main function ---
|
||||
main "$@"
|
||||
Executable
+536
@@ -0,0 +1,536 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script: scripts/restapi.sh
|
||||
# Description: REST API Generator and Analyzer for Person Service
|
||||
# Usage: ./scripts/restapi.sh [command] [options]
|
||||
# Commands: generate, analyze, test, docs
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Project paths
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
HANDLERS_DIR="$PROJECT_ROOT/internal/infrastructure/transport/http/handlers"
|
||||
GRPC_HANDLERS_DIR="$PROJECT_ROOT/internal/infrastructure/transport/grpc/handlers"
|
||||
OUTPUT_DIR="$PROJECT_ROOT/docs/api"
|
||||
SWAGGER_FILE="$OUTPUT_DIR/openapi.yaml"
|
||||
POSTMAN_FILE="$PROJECT_ROOT/person.postman_collection.json"
|
||||
|
||||
# Default values
|
||||
DEFAULT_HOST="localhost"
|
||||
DEFAULT_PORT="8080"
|
||||
DEFAULT_API_VERSION="v1"
|
||||
|
||||
# Helper functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if required files exist
|
||||
check_requirements() {
|
||||
log_info "Checking requirements..."
|
||||
|
||||
if [[ ! -f "$HANDLERS_DIR/person_handler.go" ]]; then
|
||||
log_error "Person handler not found at $HANDLERS_DIR/person_handler.go"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$GRPC_HANDLERS_DIR/person_handler.go" ]]; then
|
||||
log_error "gRPC person handler not found at $GRPC_HANDLERS_DIR/person_handler.go"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$OUTPUT_DIR" ]]; then
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
fi
|
||||
|
||||
log_success "Requirements check passed"
|
||||
}
|
||||
|
||||
# Extract endpoints from person_handler.go
|
||||
extract_rest_endpoints() {
|
||||
log_info "Extracting REST endpoints from person_handler.go..."
|
||||
|
||||
local handler_file="$HANDLERS_DIR/person_handler.go"
|
||||
local endpoints_file="$OUTPUT_DIR/rest_endpoints.txt"
|
||||
|
||||
cat > "$endpoints_file" << 'EOF'
|
||||
# REST API Endpoints - Person Service
|
||||
# Generated on: $(date)
|
||||
# Handler: internal/infrastructure/transport/http/handlers/person_handler.go
|
||||
|
||||
## Base Path: /api/v1/persons
|
||||
|
||||
### 1. Get List of Persons (Pagination)
|
||||
- **Method**: GET
|
||||
- **Path**: /persons
|
||||
- **Query Parameters**:
|
||||
- page (int, optional): Page number (default: 1)
|
||||
- limit (int, optional): Items per page (default: 10)
|
||||
- **Response**: Paginated list of persons
|
||||
- **Handler**: PersonHandler.GetList()
|
||||
|
||||
### 2. Get Person Detail
|
||||
- **Method**: GET
|
||||
- **Path**: /persons/{id}
|
||||
- **Path Parameters**:
|
||||
- id (int64, required): Person ID
|
||||
- **Response**: Single person details
|
||||
- **Handler**: PersonHandler.GetDetail()
|
||||
|
||||
### 3. Create New Person
|
||||
- **Method**: POST
|
||||
- **Path**: /persons
|
||||
- **Request Body**: CreatePersonRequest JSON
|
||||
- **Response**: Created person details
|
||||
- **Handler**: PersonHandler.Create()
|
||||
|
||||
### 4. Update Person
|
||||
- **Method**: PUT
|
||||
- **Path**: /persons/{id}
|
||||
- **Path Parameters**:
|
||||
- id (int64, required): Person ID
|
||||
- **Request Body**: CreatePersonRequest JSON
|
||||
- **Response**: Updated person details
|
||||
- **Handler**: PersonHandler.Update()
|
||||
|
||||
EOF
|
||||
|
||||
log_success "REST endpoints extracted to $endpoints_file"
|
||||
}
|
||||
|
||||
# Extract gRPC methods from person_handler.go
|
||||
extract_grpc_endpoints() {
|
||||
log_info "Extracting gRPC endpoints from person_handler.go..."
|
||||
|
||||
local grpc_handler_file="$GRPC_HANDLERS_DIR/person_handler.go"
|
||||
local grpc_endpoints_file="$OUTPUT_DIR/grpc_endpoints.txt"
|
||||
|
||||
cat > "$grpc_endpoints_file" << 'EOF'
|
||||
# gRPC API Endpoints - Person Service
|
||||
# Generated on: $(date)
|
||||
# Handler: internal/infrastructure/transport/grpc/handlers/person_handler.go
|
||||
|
||||
## Service: PersonService
|
||||
|
||||
### 1. GetPerson
|
||||
- **Method**: GetPerson
|
||||
- **Request**: GetPersonRequest { id: int64 }
|
||||
- **Response**: GetPersonResponse { person: Person }
|
||||
- **Handler**: PersonHandler.GetPerson()
|
||||
|
||||
### 2. ListPersons
|
||||
- **Method**: ListPersons
|
||||
- **Request**: ListPersonsRequest { page: int32, page_size: int32 }
|
||||
- **Response**: ListPersonsResponse { persons: []Person, total: int64 }
|
||||
- **Handler**: PersonHandler.ListPersons()
|
||||
|
||||
### 3. CreatePerson
|
||||
- **Method**: CreatePerson
|
||||
- **Request**: CreatePersonRequest { data: CreatePersonRequest }
|
||||
- **Response**: GetPersonResponse { person: Person }
|
||||
- **Handler**: PersonHandler.CreatePerson()
|
||||
|
||||
### 4. UpdatePerson
|
||||
- **Method**: UpdatePerson
|
||||
- **Request**: UpdatePersonRequest { id: int64, data: CreatePersonRequest }
|
||||
- **Response**: GetPersonResponse { person: Person }
|
||||
- **Handler**: PersonHandler.UpdatePerson()
|
||||
|
||||
### 5. DeletePerson
|
||||
- **Method**: DeletePerson
|
||||
- **Request**: DeletePersonRequest { id: int64 }
|
||||
- **Response**: Empty {}
|
||||
- **Handler**: PersonHandler.DeletePerson()
|
||||
|
||||
EOF
|
||||
|
||||
log_success "gRPC endpoints extracted to $grpc_endpoints_file"
|
||||
}
|
||||
|
||||
# Generate Postman collection
|
||||
generate_postman_collection() {
|
||||
log_info "Generating Postman collection..."
|
||||
|
||||
cat > "$POSTMAN_FILE" << 'EOF'
|
||||
{
|
||||
"info": {
|
||||
"name": "Person Service API",
|
||||
"description": "REST API Collection for Person Service",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Get Person List",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/v1/persons?page=1&limit=10",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "v1", "persons"],
|
||||
"query": [
|
||||
{
|
||||
"key": "page",
|
||||
"value": "1",
|
||||
"description": "Page number"
|
||||
},
|
||||
{
|
||||
"key": "limit",
|
||||
"value": "10",
|
||||
"description": "Items per page"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get Person Detail",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/v1/persons/1",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "v1", "persons", "1"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Create Person",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"John Doe\",\n \"email\": \"[email protected]\",\n \"phone\": \"+1234567890\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/v1/persons",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "v1", "persons"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Update Person",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"John Doe Updated\",\n \"email\": \"[email protected]\",\n \"phone\": \"+0987654321\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/v1/persons/1",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "v1", "persons", "1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "base_url",
|
||||
"value": "http://localhost:8080",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
log_success "Postman collection generated at $POSTMAN_FILE"
|
||||
}
|
||||
|
||||
# Generate Swagger documentation
|
||||
generate_swagger_docs() {
|
||||
log_info "Generating Swagger documentation..."
|
||||
|
||||
cat > "$SWAGGER_FILE" << 'EOF'
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Person Service API
|
||||
description: REST API for Person Management Service
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: API Support
|
||||
email: [email protected]
|
||||
servers:
|
||||
- url: http://localhost:8080/api/v1
|
||||
description: Development server
|
||||
paths:
|
||||
/persons:
|
||||
get:
|
||||
summary: Get list of persons
|
||||
description: Retrieve paginated list of persons
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
description: Page number
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 1
|
||||
- name: limit
|
||||
in: query
|
||||
description: Items per page
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
responses:
|
||||
'200':
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PaginatedPersonResponse'
|
||||
post:
|
||||
summary: Create new person
|
||||
description: Create a new person record
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreatePersonRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Person created successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PersonResponse'
|
||||
/persons/{id}:
|
||||
get:
|
||||
summary: Get person detail
|
||||
description: Retrieve detailed information about a specific person
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: Person ID
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'200':
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PersonResponse'
|
||||
'404':
|
||||
description: Person not found
|
||||
put:
|
||||
summary: Update person
|
||||
description: Update an existing person record
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: Person ID
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreatePersonRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Person updated successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PersonResponse'
|
||||
'404':
|
||||
description: Person not found
|
||||
components:
|
||||
schemas:
|
||||
CreatePersonRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
phone:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- email
|
||||
PersonResponse:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
phone:
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
PaginatedPersonResponse:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/PersonResponse'
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
page:
|
||||
type: integer
|
||||
limit:
|
||||
type: integer
|
||||
total:
|
||||
type: integer
|
||||
total_pages:
|
||||
type: integer
|
||||
EOF
|
||||
|
||||
log_success "Swagger documentation generated at $SWAGGER_FILE"
|
||||
}
|
||||
|
||||
# Test API endpoints
|
||||
test_api_endpoints() {
|
||||
log_info "Testing API endpoints..."
|
||||
|
||||
local base_url="http://${DEFAULT_HOST}:${DEFAULT_PORT}"
|
||||
local test_results="$OUTPUT_DIR/api_test_results.txt"
|
||||
|
||||
echo "API Test Results - $(date)" > "$test_results"
|
||||
echo "================================" >> "$test_results"
|
||||
echo "" >> "$test_results"
|
||||
|
||||
# Test health endpoint first
|
||||
log_info "Testing health endpoint..."
|
||||
if curl -s -o /dev/null -w "%{http_code}" "$base_url/health" | grep -q "200"; then
|
||||
echo "✅ Health check: PASSED" >> "$test_results"
|
||||
log_success "Health check passed"
|
||||
else
|
||||
echo "❌ Health check: FAILED" >> "$test_results"
|
||||
log_error "Health check failed"
|
||||
fi
|
||||
|
||||
# Test person list endpoint
|
||||
log_info "Testing person list endpoint..."
|
||||
local list_response=$(curl -s -w "\n%{http_code}" "$base_url/api/v1/persons?page=1&limit=5")
|
||||
local list_http_code=$(echo "$list_response" | tail -n1)
|
||||
|
||||
if [[ "$list_http_code" == "200" ]] || [[ "$list_http_code" == "204" ]]; then
|
||||
echo "✅ Person list endpoint: PASSED (HTTP $list_http_code)" >> "$test_results"
|
||||
log_success "Person list endpoint working"
|
||||
else
|
||||
echo "❌ Person list endpoint: FAILED (HTTP $list_http_code)" >> "$test_results"
|
||||
log_error "Person list endpoint failed"
|
||||
fi
|
||||
|
||||
log_success "API test results saved to $test_results"
|
||||
}
|
||||
|
||||
# Generate comprehensive API documentation
|
||||
generate_api_docs() {
|
||||
log_info "Generating comprehensive API documentation..."
|
||||
|
||||
local api_docs="$OUTPUT_DIR/API_DOCUMENTATION.md"
|
||||
|
||||
cat > "$api_docs" << 'EOF'
|
||||
# Person Service API Documentation
|
||||
|
||||
## Overview
|
||||
This document provides comprehensive documentation for the Person Service API, including REST and gRPC endpoints.
|
||||
|
||||
## Table of Contents
|
||||
1. [REST API Endpoints](#rest-api-endpoints)
|
||||
2. [gRPC API Endpoints](#grpc-api-endpoints)
|
||||
3. [Request/Response Examples](#requestresponse-examples)
|
||||
4. [Error Handling](#error-handling)
|
||||
5. [Authentication](#authentication)
|
||||
6. [Rate Limiting](#rate-limiting)
|
||||
|
||||
## REST API Endpoints
|
||||
|
||||
### Base URL
|
||||
|
||||
EOF
|
||||
|
||||
log_success "API documentation generated at $api_docs"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
local command="$1"
|
||||
|
||||
case "$command" in
|
||||
"generate")
|
||||
check_requirements
|
||||
extract_rest_endpoints
|
||||
extract_grpc_endpoints
|
||||
generate_postman_collection
|
||||
generate_swagger_docs
|
||||
generate_api_docs
|
||||
log_success "API generation completed"
|
||||
;;
|
||||
"analyze")
|
||||
check_requirements
|
||||
extract_rest_endpoints
|
||||
extract_grpc_endpoints
|
||||
log_success "API analysis completed"
|
||||
;;
|
||||
"test")
|
||||
check_requirements
|
||||
test_api_endpoints
|
||||
log_success "API testing completed"
|
||||
;;
|
||||
"docs")
|
||||
check_requirements
|
||||
generate_api_docs
|
||||
log_success "API documentation generated"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 [generate|analyze|test|docs]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Executable
+368
@@ -0,0 +1,368 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script untuk generate seeder dari SQL migration files
|
||||
# Usage: ./scripts/generate_seeder.sh [OPTIONS]
|
||||
# Examples:
|
||||
# ./scripts/generate_seeder.sh --sql=internal/infrastructure/database/sql/20260127064613_create_ethnic_table.sql
|
||||
# ./scripts/generate_seeder.sh --sql-dir=internal/infrastructure/database/sql/
|
||||
# ./scripts/generate_seeder.sh --all
|
||||
|
||||
set -e # Exit immediately if a command exits with a non-zero status
|
||||
|
||||
echo "🔧 Seeder Generator Script"
|
||||
|
||||
# Warna untuk output
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Default values
|
||||
SQL_FILE=""
|
||||
SQL_DIR=""
|
||||
GENERATE_ALL=false
|
||||
OUTPUT_DIR="internal/infrastructure/database/seeders"
|
||||
CSV_DIR="internal/infrastructure/database/csv"
|
||||
BATCH_SIZE=100
|
||||
GENERATE_CSV=true
|
||||
VERBOSE=false
|
||||
DRY_RUN=false
|
||||
|
||||
# Fungsi untuk menampilkan usage
|
||||
show_usage() {
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Generate seeder from SQL migration files"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --sql=FILE Path to specific SQL file"
|
||||
echo " --sql-dir=DIR Process all SQL files in directory"
|
||||
echo " --all Process all SQL files in default migrations directory"
|
||||
echo " --output=DIR Output directory for generated seeders (default: $OUTPUT_DIR)"
|
||||
echo " --csv-dir=DIR CSV output directory (default: $CSV_DIR)"
|
||||
echo " --batch-size=NUM Batch size for seeding (default: $BATCH_SIZE)"
|
||||
echo " --no-csv Don't generate CSV templates"
|
||||
echo " --verbose, -v Verbose output"
|
||||
echo " --dry-run Show what would be generated without creating files"
|
||||
echo " --help, -h Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 --sql=internal/infrastructure/database/sql/20260127064613_create_ethnic_table.sql"
|
||||
echo " $0 --sql-dir=internal/infrastructure/database/sql/"
|
||||
echo " $0 --all"
|
||||
echo " $0 --sql=sql/create_table.sql --output=custom/seeders --batch-size=50"
|
||||
echo " $0 --all --dry-run --verbose"
|
||||
}
|
||||
|
||||
# Fungsi untuk logging
|
||||
log_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
log_verbose() {
|
||||
if [ "$VERBOSE" = true ]; then
|
||||
echo -e "${BLUE}🔍 $1${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--sql=*)
|
||||
SQL_FILE="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--sql-dir=*)
|
||||
SQL_DIR="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--all)
|
||||
GENERATE_ALL=true
|
||||
shift
|
||||
;;
|
||||
--output=*)
|
||||
OUTPUT_DIR="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--csv-dir=*)
|
||||
CSV_DIR="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--batch-size=*)
|
||||
BATCH_SIZE="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
--no-csv)
|
||||
GENERATE_CSV=false
|
||||
shift
|
||||
;;
|
||||
--verbose|-v)
|
||||
VERBOSE=true
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
show_usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validasi input
|
||||
if [ "$GENERATE_ALL" = true ] && [ -n "$SQL_FILE" ]; then
|
||||
log_error "Cannot use --all with --sql option"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$GENERATE_ALL" = true ] && [ -n "$SQL_DIR" ]; then
|
||||
log_error "Cannot use --all with --sql-dir option"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$SQL_FILE" ] && [ -n "$SQL_DIR" ]; then
|
||||
log_error "Cannot use --sql with --sql-dir option"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$GENERATE_ALL" = false ] && [ -z "$SQL_FILE" ] && [ -z "$SQL_DIR" ]; then
|
||||
log_error "Must specify either --sql, --sql-dir, or --all"
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set default SQL directory jika menggunakan --all
|
||||
if [ "$GENERATE_ALL" = true ]; then
|
||||
SQL_DIR="internal/infrastructure/database/sql"
|
||||
fi
|
||||
|
||||
# Fungsi untuk cek apakah file SQL valid
|
||||
validate_sql_file() {
|
||||
local file="$1"
|
||||
|
||||
if [ ! -f "$file" ]; then
|
||||
log_error "SQL file not found: $file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! grep -q "CREATE TABLE" "$file"; then
|
||||
log_warning "File does not contain CREATE TABLE statement: $file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Fungsi untuk extract table name dari SQL file
|
||||
extract_table_name() {
|
||||
local sql_file="$1"
|
||||
local filename=$(basename "$sql_file" .sql)
|
||||
|
||||
# Pattern: YYYYMMDDHHMMSS_create_tablename.sql
|
||||
if [[ "$filename" =~ ^[0-9]{14}_create_(.+)$ ]]; then
|
||||
echo "${BASH_REMATCH[1]}"
|
||||
else
|
||||
# Fallback: extract dari CREATE TABLE statement
|
||||
grep -i "CREATE TABLE" "$sql_file" | head -1 | sed -n 's/.*CREATE TABLE[[:space:]]*["\`]\?\([^"\`[:space:]]*\)["\`]\?.*/\1/ip' | tr '[:upper:]' '[:lower:]'
|
||||
fi
|
||||
}
|
||||
|
||||
# Fungsi untuk generate seeder dari single SQL file
|
||||
generate_seeder_from_file() {
|
||||
local sql_file="$1"
|
||||
|
||||
log_info "Processing SQL file: $sql_file"
|
||||
|
||||
if ! validate_sql_file "$sql_file"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local table_name=$(extract_table_name "$sql_file")
|
||||
if [ -z "$table_name" ]; then
|
||||
log_error "Could not extract table name from: $sql_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_verbose "Extracted table name: $table_name"
|
||||
|
||||
local seeder_filename="seeder_${table_name}.go"
|
||||
local seeder_path="$OUTPUT_DIR/$seeder_filename"
|
||||
local csv_filename="${table_name}.csv"
|
||||
local csv_path="$CSV_DIR/$csv_filename"
|
||||
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
log_info "[DRY RUN] Would generate:"
|
||||
log_info " Seeder: $seeder_path"
|
||||
if [ "$GENERATE_CSV" = true ]; then
|
||||
log_info " CSV: $csv_path"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Create directories if they don't exist
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
mkdir -p "$CSV_DIR"
|
||||
|
||||
# Generate seeder using Go program
|
||||
log_info "Generating seeder for table: $table_name"
|
||||
|
||||
local csv_flag=""
|
||||
if [ "$GENERATE_CSV" = true ]; then
|
||||
csv_flag="-csv-template"
|
||||
fi
|
||||
|
||||
local verbose_flag=""
|
||||
if [ "$VERBOSE" = true ]; then
|
||||
verbose_flag="-v"
|
||||
fi
|
||||
|
||||
if go run cmd/seeder-generator/main.go \
|
||||
-sql="$sql_file" \
|
||||
-output="$OUTPUT_DIR" \
|
||||
-csv-dir="$CSV_DIR" \
|
||||
-batch="$BATCH_SIZE" \
|
||||
$csv_flag $verbose_flag; then
|
||||
|
||||
log_success "Generated seeder: $seeder_path"
|
||||
if [ "$GENERATE_CSV" = true ] && [ -f "$csv_path" ]; then
|
||||
log_success "Generated CSV: $csv_path"
|
||||
fi
|
||||
else
|
||||
log_error "Failed to generate seeder for: $table_name"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Fungsi untuk process semua SQL files di directory
|
||||
process_sql_directory() {
|
||||
local dir="$1"
|
||||
|
||||
if [ ! -d "$dir" ]; then
|
||||
log_error "Directory not found: $dir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Processing SQL files in directory: $dir"
|
||||
|
||||
local sql_files=()
|
||||
while IFS= read -r -d $'\0' file; do
|
||||
sql_files+=("$file")
|
||||
done < <(find "$dir" -name "*.sql" -type f -print0 | sort -z)
|
||||
|
||||
if [ ${#sql_files[@]} -eq 0 ]; then
|
||||
log_warning "No SQL files found in directory: $dir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Found ${#sql_files[@]} SQL files to process"
|
||||
|
||||
local success_count=0
|
||||
local failed_count=0
|
||||
|
||||
for sql_file in "${sql_files[@]}"; do
|
||||
if generate_seeder_from_file "$sql_file"; then
|
||||
((success_count++))
|
||||
else
|
||||
((failed_count++))
|
||||
fi
|
||||
done
|
||||
|
||||
log_info "Processing complete: $success_count successful, $failed_count failed"
|
||||
|
||||
if [ $failed_count -gt 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Fungsi untuk update seeder registry
|
||||
update_registry() {
|
||||
local registry_file="$OUTPUT_DIR/seeder_registry.go"
|
||||
|
||||
log_info "Updating seeder registry: $registry_file"
|
||||
|
||||
# TODO: Implement registry update logic
|
||||
# For now, just show instructions
|
||||
log_info "Don't forget to add generated seeders to your seeder registry!"
|
||||
}
|
||||
|
||||
# Fungsi untuk test database connection
|
||||
test_db_connection() {
|
||||
log_info "Testing database connection..."
|
||||
|
||||
if go run scripts/test_db_connection.go; then
|
||||
log_success "Database connection successful"
|
||||
return 0
|
||||
else
|
||||
log_error "Database connection failed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
log_info "Starting seeder generation..."
|
||||
|
||||
if [ "$VERBOSE" = true ]; then
|
||||
log_verbose "Configuration:"
|
||||
log_verbose " SQL_FILE: $SQL_FILE"
|
||||
log_verbose " SQL_DIR: $SQL_DIR"
|
||||
log_verbose " OUTPUT_DIR: $OUTPUT_DIR"
|
||||
log_verbose " CSV_DIR: $CSV_DIR"
|
||||
log_verbose " BATCH_SIZE: $BATCH_SIZE"
|
||||
log_verbose " GENERATE_CSV: $GENERATE_CSV"
|
||||
log_verbose " DRY_RUN: $DRY_RUN"
|
||||
fi
|
||||
|
||||
# Test database connection (optional)
|
||||
# test_db_connection || true
|
||||
|
||||
# Process SQL files
|
||||
if [ -n "$SQL_FILE" ]; then
|
||||
if ! generate_seeder_from_file "$SQL_FILE"; then
|
||||
exit 1
|
||||
fi
|
||||
elif [ -n "$SQL_DIR" ]; then
|
||||
if ! process_sql_directory "$SQL_DIR"; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Update registry
|
||||
update_registry
|
||||
|
||||
log_success "Seeder generation completed!"
|
||||
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
log_info "This was a dry run. No files were created."
|
||||
else
|
||||
log_info "Next steps:"
|
||||
log_info "1. Review generated seeders in: $OUTPUT_DIR"
|
||||
log_info "2. Add seeders to your registry"
|
||||
log_info "3. Run: make seeder-seed-all"
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}📚 Generating Flexible Swagger documentation...${NC}"
|
||||
|
||||
# 1. Periksa apakah swag CLI sudah terinstall
|
||||
if ! command -v swag &> /dev/null; then
|
||||
echo -e "${YELLOW}⚠️ 'swag' command not found. Installing github.com/swaggo/swag/cmd/swag@latest...${NC}"
|
||||
go install github.com/swaggo/swag/cmd/swag@latest
|
||||
|
||||
# Tambahkan GOPATH/bin ke PATH jika belum ada
|
||||
export PATH=$PATH:$(go env GOPATH)/bin
|
||||
fi
|
||||
|
||||
# 2. Format anotasi Swagger di seluruh project (Auto-format)
|
||||
echo -e "${BLUE}📝 Formatting Swagger annotations...${NC}"
|
||||
swag fmt -d ./cmd/api,./internal -g main.go
|
||||
|
||||
# 3. Generate Swagger docs
|
||||
# -d : Root directory scanning (cmd/api untuk anotasi global, internal untuk semua modul domain DDD)
|
||||
# -g : Entrypoint utama aplikasi relatif terhadap argumen -d pertama (main.go)
|
||||
# -o : Output folder untuk file docs/swagger
|
||||
# --parseDependency : Membaca struct dari external package (pkg/response dll)
|
||||
# --parseInternal : Membaca struct/model di dalam folder internal
|
||||
echo -e "${BLUE}⚙️ Building Swagger JSON/YAML files...${NC}"
|
||||
if swag init -d ./cmd/api,./internal -g main.go -o ./docs/swagger --parseDependency --parseInternal; then
|
||||
echo -e "${GREEN}✅ Swagger documentation generated successfully in ./docs/swagger${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Failed to generate Swagger documentation${NC}"
|
||||
exit 1
|
||||
fi
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "🧪 Starting gRPC Test Suite..."
|
||||
echo "================================"
|
||||
|
||||
# Cek apakah server sudah berjalan
|
||||
if ! nc -z localhost 8090 2>/dev/null; then
|
||||
echo "⚠️ gRPC Server not running on port 8090"
|
||||
echo "🚀 Starting server..."
|
||||
|
||||
# Jalankan server di background
|
||||
go run cmd/api/main.go &
|
||||
SERVER_PID=$!
|
||||
|
||||
# Tunggu server siap
|
||||
echo "⏳ Waiting for server to start..."
|
||||
sleep 5
|
||||
|
||||
# Cek lagi
|
||||
if ! nc -z localhost 8090 2>/dev/null; then
|
||||
echo "❌ Failed to start server"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Server started successfully"
|
||||
else
|
||||
echo "✅ Server already running"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "1️⃣ Testing gRPC Connection..."
|
||||
go test -run TestGRPCConnection ./internal/infrastructure/transport/grpc/proto/test/ -v
|
||||
|
||||
echo ""
|
||||
echo "2️⃣ Testing Create Person..."
|
||||
go test -run TestCreatePerson ./internal/infrastructure/transport/grpc/proto/test/ -v
|
||||
|
||||
echo ""
|
||||
echo "3️⃣ Testing List Persons..."
|
||||
go test -run TestListPersons ./internal/infrastructure/transport/grpc/proto/test/ -v
|
||||
|
||||
echo ""
|
||||
echo "4️⃣ Testing Get Person..."
|
||||
go test -run TestGetPerson ./internal/infrastructure/transport/grpc/proto/test/ -v
|
||||
|
||||
echo ""
|
||||
echo "5️⃣ Testing Update Person..."
|
||||
go test -run TestUpdatePerson ./internal/infrastructure/transport/grpc/proto/test/ -v
|
||||
|
||||
echo ""
|
||||
echo "6️⃣ Testing Delete Person..."
|
||||
go test -run TestDeletePerson ./internal/infrastructure/transport/grpc/proto/test/ -v
|
||||
|
||||
echo ""
|
||||
echo "7️⃣ Testing Performance..."
|
||||
go test -run TestGRPCPerformance ./internal/infrastructure/transport/grpc/proto/test/ -v
|
||||
|
||||
echo ""
|
||||
echo "🏁 Test completed!"
|
||||
|
||||
# Jika kita yang start server, matikan lagi
|
||||
if [ ! -z "$SERVER_PID" ]; then
|
||||
echo "🛑 Stopping server..."
|
||||
kill $SERVER_PID
|
||||
fi
|
||||
Reference in New Issue
Block a user