Files
agent-unit-testing/install.sh
T
Pham-Tan-Thien 7425b263d5 feat: add comprehensive unit testing support for CakePHP
- Add 4 CakePHP Claude Code skills: cakephp-unit-test, cakephp-test-setup, cakephp-test-review, cakephp-mock-helper
- Add 11 CakePHP PHPUnit component templates (Table, Entity, Controller, Service, Command, Component, Middleware, Mailer, Form, Behavior, Helper)
- Add CakePHP configs (phpunit.xml.dist, app_local.test.php for SQLite in-memory)
- Add comprehensive CakePHP documentation and component guides
- Update test-runner.sh and installer to auto-detect Laravel and CakePHP
- Add CakePHP CI/CD templates for GitHub Actions and GitLab CI
- Update system prompt, verification checklist, and README with dedicated guides
2026-09-14 10:19:40 +07:00

323 lines
14 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# ==============================================================================
# SMARTGIFT AI - MULTI-FRAMEWORK UNIT TESTING TOOLKIT INSTALLER
# Hỗ trợ: Laravel & CakePHP
# Cài đặt bộ công cụ Unit Test vào bất kỳ source code nào mà KHÔNG CẦN clone repo về máy.
#
# Cách dùng 1 (Khuyên dùng - Đứng trong source code và chạy):
# curl -fsSL https://raw.githubusercontent.com/<OWNER>/agent-unit-testing/main/install.sh | bash
#
# Cách dùng 2 (Cài Toàn Cục vào máy):
# curl -fsSL https://raw.githubusercontent.com/<OWNER>/agent-unit-testing/main/install.sh | bash -s -- --global
# ==============================================================================
set -e
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
# Remote Repository URL công khai qua HTTPS
DEFAULT_REPO="https://git.smartgift.io.vn/Smartgift-AI/agent-unit-testing.git"
REPO_URL="${SG_TEST_REPO:-${LARAVEL_TEST_REPO:-$DEFAULT_REPO}}"
TARGET_DIR=""
GLOBAL_MODE=false
FORCE_MODE=false
for arg in "$@"; do
case "$arg" in
--global|-g)
GLOBAL_MODE=true
;;
--force|-f)
FORCE_MODE=true
;;
--help|-h)
echo -e "${BLUE}===================================================================${NC}"
echo -e "${CYAN}${BOLD} SMARTGIFT AI: PHP UNIT TESTING TOOLKIT (LARAVEL & CAKEPHP)${NC}"
echo -e "${BLUE}===================================================================${NC}"
echo -e "Cách dùng:"
echo -e " 1. Cài đặt trực tiếp vào source code hiện tại:"
echo -e " ${YELLOW}curl -fsSL <URL>/install.sh | bash${NC}"
echo -e " 2. Cài đặt vào một source code ở đường dẫn cụ thể:"
echo -e " ${YELLOW}curl -fsSL <URL>/install.sh | bash -s -- /duong-dan/source-code${NC}"
echo -e " 3. Cài đặt Toàn Cục vào máy tính (dùng cho mọi folder):"
echo -e " ${YELLOW}curl -fsSL <URL>/install.sh | bash -s -- --global${NC}"
echo -e " 4. Cài đặt vào thư mục trống:"
echo -e " ${YELLOW}curl -fsSL <URL>/install.sh | bash -s -- . --force${NC}"
exit 0
;;
-*)
# Bỏ qua các flag khác
;;
*)
if [ -z "$TARGET_DIR" ]; then
TARGET_DIR="$arg"
fi
;;
esac
done
TARGET_DIR="${TARGET_DIR:-.}"
echo -e "${BLUE}===================================================================${NC}"
echo -e "${CYAN}${BOLD} 🚀 SMARTGIFT AI - UNIT TESTING TOOLKIT (LARAVEL & CAKEPHP)${NC}"
echo -e "${BLUE}===================================================================${NC}"
# 1. Tìm hoặc Tải nguồn tài nguyên (Local nếu có, hoặc tải tạm qua Git)
CLEANUP_TEMP=false
PACKAGE_ROOT=""
SOURCE="${BASH_SOURCE[0]:-$0}"
SCRIPT_DIR=""
if [ -f "$SOURCE" ]; then
SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE")" 2>/dev/null && pwd || echo "")"
fi
if [ -n "$SCRIPT_DIR" ] && [ -d "$SCRIPT_DIR/.claude/skills" ]; then
PACKAGE_ROOT="$SCRIPT_DIR"
echo -e "${GREEN}✓ Sử dụng tài nguyên có sẵn tại local.${NC}"
else
echo -e "${YELLOW}📥 Đang tải bộ công cụ từ remote repository...${NC}"
TMP_DIR="$(mktemp -d 2>/dev/null || mktemp -d -t 'sg_unit_testing')"
if ! git clone --depth 1 "$REPO_URL" "$TMP_DIR" --quiet 2>/dev/null; then
echo -e "${RED}❌ Không thể clone từ repository: $REPO_URL${NC}"
rm -rf "$TMP_DIR"
exit 1
fi
PACKAGE_ROOT="$TMP_DIR"
CLEANUP_TEMP=true
echo -e "${GREEN}✓ Tải thành công!${NC}"
fi
cleanup() {
if [ "$CLEANUP_TEMP" = true ] && [ -d "$PACKAGE_ROOT" ]; then
rm -rf "$PACKAGE_ROOT"
fi
}
trap cleanup EXIT
# ==============================================================================
# 2. XỬ LÝ CÀI ĐẶT TOÀN CỤC (GLOBAL MODE: CHO TẤT CẢ FOLDER TRÊN MÁY)
# ==============================================================================
if [ "$GLOBAL_MODE" = true ]; then
echo -e "${YELLOW}⚙️ Đang cài đặt chế độ Toàn Cục vào $HOME/.claude/skills/...${NC}"
mkdir -p "$HOME/.claude/skills"
cp -R "$PACKAGE_ROOT/.claude/skills/"* "$HOME/.claude/skills/"
mkdir -p "$HOME/.claude/testing-docs/templates"
cp -R "$PACKAGE_ROOT/docs/"* "$HOME/.claude/testing-docs/"
cp -R "$PACKAGE_ROOT/rules/"* "$HOME/.claude/testing-docs/"
cp -R "$PACKAGE_ROOT/templates/"* "$HOME/.claude/testing-docs/templates/"
mkdir -p "$HOME/.local/bin"
# Lệnh khởi tạo test runner
cat << 'EOF' > "$HOME/.local/bin/sg-test-init"
#!/usr/bin/env bash
TARGET_DIR="${1:-.}"
SOURCE_DIR="$HOME/.claude/testing-docs"
if [ ! -d "$TARGET_DIR" ]; then
echo "Lỗi: Thư mục '$TARGET_DIR' không tồn tại!"
exit 1
fi
echo "🚀 Đang khởi tạo test runner cho dự án tại: $TARGET_DIR"
if [ -f "$SOURCE_DIR/templates/docker/test-runner.sh" ]; then
cp "$SOURCE_DIR/templates/docker/test-runner.sh" "$TARGET_DIR/test-runner.sh"
chmod +x "$TARGET_DIR/test-runner.sh"
echo " ✓ Đã tạo $TARGET_DIR/test-runner.sh"
fi
if [ -f "$SOURCE_DIR/templates/setup-dependencies.sh" ]; then
cp "$SOURCE_DIR/templates/setup-dependencies.sh" "$TARGET_DIR/setup-test-deps.sh"
chmod +x "$TARGET_DIR/setup-test-deps.sh"
echo " ✓ Đã tạo $TARGET_DIR/setup-test-deps.sh"
fi
echo "🎉 Hoàn tất! Mở Claude Code và gõ lệnh test tương ứng:"
echo " - CakePHP: /cakephp-unit-test --all --run"
echo " - Laravel: /laravel-unit-test --all --run"
EOF
chmod +x "$HOME/.local/bin/sg-test-init"
cp "$HOME/.local/bin/sg-test-init" "$HOME/.local/bin/laravel-test-init"
chmod +x "$HOME/.local/bin/laravel-test-init"
cp "$HOME/.local/bin/sg-test-init" "$HOME/.local/bin/cakephp-test-init"
chmod +x "$HOME/.local/bin/cakephp-test-init"
# Lệnh cập nhật bộ công cụ (Update)
cat << 'EOF' > "$HOME/.local/bin/sg-test-update"
#!/usr/bin/env bash
REPO_URL="${SG_TEST_REPO:-https://git.smartgift.io.vn/Smartgift-AI/agent-unit-testing.git}"
echo "🔄 Đang cập nhật bộ công cụ Unit Test từ Git repository..."
TMP_DIR="$(mktemp -d 2>/dev/null || mktemp -d -t 'sg_update')"
if git clone --depth 1 "$REPO_URL" "$TMP_DIR" --quiet 2>/dev/null; then
bash "$TMP_DIR/install.sh" --global
rm -rf "$TMP_DIR"
echo "✅ Cập nhật toàn bộ công cụ thành công!"
else
echo "❌ Lỗi: Không thể kết nối hoặc clone repository $REPO_URL"
rm -rf "$TMP_DIR"
exit 1
fi
EOF
chmod +x "$HOME/.local/bin/sg-test-update"
cp "$HOME/.local/bin/sg-test-update" "$HOME/.local/bin/laravel-test-update"
chmod +x "$HOME/.local/bin/laravel-test-update"
cp "$HOME/.local/bin/sg-test-update" "$HOME/.local/bin/cakephp-test-update"
chmod +x "$HOME/.local/bin/cakephp-test-update"
echo -e "${GREEN}${BOLD}✓ CÀI ĐẶT TOÀN CỤC HOÀN TẤT THÀNH CÔNG!${NC}"
echo -e "Kể từ bây giờ, ở bất kỳ source code nào, bạn mở Claude Code là có thể gõ ngay:"
echo -e " • CakePHP: ${CYAN}/cakephp-test-setup --install${NC} | ${CYAN}/cakephp-unit-test --all --run${NC}"
echo -e " • Laravel: ${CYAN}/laravel-test-setup --install${NC} | ${CYAN}/laravel-unit-test --all --run${NC}"
echo -e "Và các lệnh terminal: ${CYAN}cakephp-test-init${NC}, ${CYAN}laravel-test-init${NC}, ${CYAN}cakephp-test-update${NC}, ${CYAN}laravel-test-update${NC}"
exit 0
fi
# ==============================================================================
# 3. XỬ LÝ CÀI ĐẶT TRỰC TIẾP VÀO SOURCE CODE HIỆN TẠI (PROJECT MODE - KHUYÊN DÙNG)
# ==============================================================================
TARGET_DIR="$(cd "$TARGET_DIR" 2>/dev/null && pwd || echo "$TARGET_DIR")"
if [ ! -d "$TARGET_DIR" ]; then
echo -e "${RED}Lỗi: Thư mục '$TARGET_DIR' không tồn tại!${NC}"
exit 1
fi
# Phát hiện framework
FRAMEWORK="generic"
if [ -f "$TARGET_DIR/bin/cake" ] || ( [ -f "$TARGET_DIR/composer.json" ] && grep -q '"cakephp/cakephp"' "$TARGET_DIR/composer.json" ); then
FRAMEWORK="cakephp"
echo -e "${GREEN}✓ Phát hiện dự án: CakePHP${NC}"
elif [ -f "$TARGET_DIR/artisan" ] || ( [ -f "$TARGET_DIR/composer.json" ] && grep -q '"laravel/framework"' "$TARGET_DIR/composer.json" ); then
FRAMEWORK="laravel"
echo -e "${GREEN}✓ Phát hiện dự án: Laravel${NC}"
elif [ ! -f "$TARGET_DIR/composer.json" ]; then
FILE_COUNT=$(ls -A "$TARGET_DIR" 2>/dev/null | wc -l | tr -d ' ')
if [ "$FILE_COUNT" -le 2 ]; then
echo -e "${YELLOW}ℹ Thư mục mới/trống: Tự động khởi tạo bộ công cụ Unit Test...${NC}"
elif [ "$FORCE_MODE" = false ]; then
echo -e "${YELLOW}⚠️ Cảnh báo: Thư mục '$TARGET_DIR' đang chứa dữ liệu khác và chưa có file composer.json.${NC}"
echo -e "Nếu bạn vẫn muốn cài đặt vào thư mục này, hãy chạy:"
echo -e " ${CYAN}bash <(curl -fsSL <URL>/install.sh) --force${NC}"
exit 1
fi
fi
echo -e "📦 Đang cài đặt công cụ vào source code: ${YELLOW}$TARGET_DIR${NC}"
# A. Copy Claude Skills vào .claude/skills/ của source code
mkdir -p "$TARGET_DIR/.claude/skills"
cp -R "$PACKAGE_ROOT/.claude/skills/"* "$TARGET_DIR/.claude/skills/"
echo -e " ${GREEN}✓${NC} Đã cài bộ Claude Code Skills (Laravel & CakePHP)"
# B. Copy cẩm nang tài liệu vào .claude/testing-docs/
mkdir -p "$TARGET_DIR/.claude/testing-docs"
cp -R "$PACKAGE_ROOT/docs/"* "$TARGET_DIR/.claude/testing-docs/"
cp -R "$PACKAGE_ROOT/rules/"* "$TARGET_DIR/.claude/testing-docs/"
echo -e " ${GREEN}✓${NC} Đã đồng bộ cẩm nang & rules kiểm thử (.claude/testing-docs/)"
# C. Copy Test Runners vào root của source code
cp "$PACKAGE_ROOT/templates/docker/test-runner.sh" "$TARGET_DIR/test-runner.sh"
chmod +x "$TARGET_DIR/test-runner.sh"
echo -e " ${GREEN}✓${NC} Đã tạo smart runner: ./test-runner.sh"
cp "$PACKAGE_ROOT/templates/setup-dependencies.sh" "$TARGET_DIR/setup-test-deps.sh"
chmod +x "$TARGET_DIR/setup-test-deps.sh"
echo -e " ${GREEN}✓${NC} Đã tạo dependency installer: ./setup-test-deps.sh"
# D. Cấu hình môi trường an toàn SQLite In-Memory
if [ "$FRAMEWORK" = "laravel" ]; then
PHPUNIT_XML="$TARGET_DIR/phpunit.xml"
PHPUNIT_DIST="$TARGET_DIR/phpunit.xml.dist"
TARGET_XML=""
if [ -f "$PHPUNIT_XML" ]; then
TARGET_XML="$PHPUNIT_XML"
elif [ -f "$PHPUNIT_DIST" ]; then
TARGET_XML="$PHPUNIT_DIST"
fi
if [ -n "$TARGET_XML" ]; then
if ! grep -q 'name="DB_CONNECTION"' "$TARGET_XML" || ! grep -q 'value="sqlite"' "$TARGET_XML"; then
if grep -q '<php>' "$TARGET_XML"; then
sed -i.bak '/<php>/a\
<env name="DB_CONNECTION" value="sqlite"/>\
<env name="DB_DATABASE" value=":memory:"/>\
<env name="BCRYPT_ROUNDS" value="4"/>\
<env name="CACHE_STORE" value="array"/>\
<env name="QUEUE_CONNECTION" value="sync"/>\
<env name="MAIL_MAILER" value="array"/>
' "$TARGET_XML" 2>/dev/null || true
rm -f "$TARGET_XML.bak" 2>/dev/null || true
echo -e " ${GREEN}✓${NC} Đã cấu hình SQLite in-memory (:memory:) an toàn vào phpunit.xml"
fi
else
echo -e " ${GREEN}✓${NC} Cấu hình SQLite in-memory trong phpunit.xml đã chuẩn xác"
fi
fi
elif [ "$FRAMEWORK" = "cakephp" ]; then
# Nếu chưa có phpunit.xml, copy file mẫu
if [ ! -f "$TARGET_DIR/phpunit.xml" ] && [ ! -f "$TARGET_DIR/phpunit.xml.dist" ]; then
cp "$PACKAGE_ROOT/templates/cakephp/configs/phpunit.xml.dist.template" "$TARGET_DIR/phpunit.xml.dist"
echo -e " ${GREEN}✓${NC} Đã tạo phpunit.xml.dist chuẩn cho CakePHP"
else
echo -e " ${GREEN}✓${NC} Đã phát hiện cấu hình PHPUnit CakePHP"
fi
if [ -f "$TARGET_DIR/config/app_local.php" ]; then
if grep -q "'test'" "$TARGET_DIR/config/app_local.php"; then
echo -e " ${GREEN}✓${NC} Cấu hình Datasources.test trong config/app_local.php đã sẵn sàng"
else
echo -e " ${YELLOW}ℹ${NC} Lưu ý: Hãy đảm bảo Datasources.test trong config/app_local.php sử dụng SQLite :memory:"
fi
fi
fi
# E. Tạo GitHub Actions CI workflow nếu có .git
if [ -d "$TARGET_DIR/.git" ]; then
mkdir -p "$TARGET_DIR/.github/workflows"
if [ ! -f "$TARGET_DIR/.github/workflows/unit-tests.yml" ]; then
if [ "$FRAMEWORK" = "cakephp" ]; then
cp "$PACKAGE_ROOT/templates/ci/github-actions-cakephp.yml.template" "$TARGET_DIR/.github/workflows/unit-tests.yml"
else
cp "$PACKAGE_ROOT/templates/ci/github-actions.yml.template" "$TARGET_DIR/.github/workflows/unit-tests.yml"
fi
echo -e " ${GREEN}✓${NC} Đã tạo CI/CD Quality Gate (.github/workflows/unit-tests.yml)"
fi
fi
echo -e "\n${GREEN}${BOLD}🎉 CÀI ĐẶT HOÀN TẤT THÀNH CÔNG VÀO SOURCE CODE!${NC}"
echo -e "\n${YELLOW}${BOLD}BÂY GIỜ BẠN CÓ THỂ VIẾT UNIT TEST NGAY:${NC}"
echo -e "1. Mở Claude Code tại source code này:"
echo -e " ${CYAN}claude${NC}"
if [ "$FRAMEWORK" = "cakephp" ]; then
echo -e "2. Gõ lệnh dành riêng cho CakePHP:"
echo -e " - Setup môi trường: ${CYAN}/cakephp-test-setup --install${NC}"
echo -e " - Viết test & chạy test: ${CYAN}/cakephp-unit-test --all --run${NC}"
echo -e " - Hoặc theo tầng: ${CYAN}/cakephp-unit-test src/Model/Table/${NC}"
elif [ "$FRAMEWORK" = "laravel" ]; then
echo -e "2. Gõ lệnh dành riêng cho Laravel:"
echo -e " - Setup môi trường: ${CYAN}/laravel-test-setup --install${NC}"
echo -e " - Viết test & chạy test: ${CYAN}/laravel-unit-test --all --run${NC}"
echo -e " - Hoặc theo tầng: ${CYAN}/laravel-unit-test app/Services/${NC}"
else
echo -e "2. Gõ lệnh tương ứng với framework của bạn:"
echo -e " - CakePHP: ${CYAN}/cakephp-unit-test --all --run${NC}"
echo -e " - Laravel: ${CYAN}/laravel-unit-test --all --run${NC}"
fi
echo -e "3. Chạy test trực tiếp từ terminal bất kỳ lúc nào:"
echo -e " ${CYAN}./test-runner.sh${NC}"