review-to-down 스케줄링 커밋

This commit is contained in:
2026-02-03 10:19:42 +09:00
parent 2cd44f4113
commit 9700ac48b7
228 changed files with 7814 additions and 930 deletions

View File

@@ -1,571 +0,0 @@
#!/bin/bash
# pack_offline_bundle_airgap_macos.sh
# ============================================================================
# Gradle Offline Bundle Packer (macOS)
# ============================================================================
# Version: 4.0
#
# WORKFLOW:
# 1. [ONLINE] Build project (./gradlew bootJar) - downloads all deps
# 2. [ONLINE] Test run (./gradlew bootRun) - verify app works
# 3. [OFFLINE TEST] Verify offline build works
# 4. Create bundle with all cached dependencies
#
# REQUIREMENTS:
# - Internet connection (for initial build)
# - Project with gradlew
# - macOS 10.13+ (High Sierra or later)
# ============================================================================
set -e
# ============================================================================
# Configuration
# ============================================================================
WRAPPER_SEED_PATH="wrapper_jar_seed"
OFFLINE_HOME_NAME="_offline_gradle_home"
BOOTRUN_TIMEOUT_SECONDS=60
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
WHITE='\033[1;37m'
NC='\033[0m' # No Color
echo ""
echo -e "${CYAN}============================================================${NC}"
echo -e "${CYAN} Gradle Offline Bundle Packer v4.0 (macOS)${NC}"
echo -e "${CYAN}============================================================${NC}"
echo ""
echo -e "${WHITE} This script will:${NC}"
echo -e "${GRAY} 1. Build project with internet (download dependencies)${NC}"
echo -e "${GRAY} 2. Test run application (verify it works)${NC}"
echo -e "${GRAY} 3. Test offline build (verify cache is complete)${NC}"
echo -e "${GRAY} 4. Create offline bundle for air-gapped environment${NC}"
echo ""
echo -e "${CYAN}============================================================${NC}"
echo ""
# ============================================================================
# [1/20] Check Current Directory
# ============================================================================
echo -e "${YELLOW}==[1/20] Check Current Directory ==${NC}"
ROOT="$(pwd)"
echo "ROOT_DIR: $ROOT"
echo ""
# ============================================================================
# [2/20] Check Required Files
# ============================================================================
echo -e "${YELLOW}==[2/20] Check Required Files ==${NC}"
if [ ! -f "./gradlew" ]; then
echo -e "${RED}ERROR: gradlew not found. Run from project root.${NC}"
exit 1
fi
chmod +x ./gradlew
echo -e "${GREEN}[OK] gradlew${NC}"
BUILD_FILE=""
if [ -f "./build.gradle" ]; then
BUILD_FILE="build.gradle"
elif [ -f "./build.gradle.kts" ]; then
BUILD_FILE="build.gradle.kts"
else
echo -e "${RED}ERROR: build.gradle(.kts) not found.${NC}"
exit 1
fi
echo -e "${GREEN}[OK] $BUILD_FILE${NC}"
SETTINGS_FILE=""
if [ -f "./settings.gradle" ]; then
SETTINGS_FILE="settings.gradle"
echo -e "${GREEN}[OK] $SETTINGS_FILE${NC}"
elif [ -f "./settings.gradle.kts" ]; then
SETTINGS_FILE="settings.gradle.kts"
echo -e "${GREEN}[OK] $SETTINGS_FILE${NC}"
fi
echo ""
# ============================================================================
# [3/20] Check Gradle Wrapper
# ============================================================================
echo -e "${YELLOW}==[3/20] Check Gradle Wrapper ==${NC}"
WRAPPER_DIR="$ROOT/gradle/wrapper"
WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar"
WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties"
mkdir -p "$WRAPPER_DIR"
if [ ! -f "$WRAPPER_PROP" ]; then
echo -e "${RED}ERROR: gradle-wrapper.properties not found.${NC}"
exit 1
fi
if [ ! -f "$WRAPPER_JAR" ]; then
SEED_JAR="$ROOT/$WRAPPER_SEED_PATH/gradle-wrapper.jar"
if [ -f "$SEED_JAR" ]; then
cp "$SEED_JAR" "$WRAPPER_JAR"
echo -e "${GREEN}[OK] Wrapper jar injected from seed${NC}"
else
echo -e "${RED}ERROR: gradle-wrapper.jar missing${NC}"
exit 1
fi
else
echo -e "${GREEN}[OK] gradle-wrapper.jar exists${NC}"
fi
# Create seed backup
SEED_DIR="$ROOT/$WRAPPER_SEED_PATH"
if [ ! -d "$SEED_DIR" ]; then
mkdir -p "$SEED_DIR"
cp "$WRAPPER_JAR" "$SEED_DIR/gradle-wrapper.jar"
fi
echo ""
# ============================================================================
# [4/20] Set GRADLE_USER_HOME (Project Local)
# ============================================================================
echo -e "${YELLOW}==[4/20] Set GRADLE_USER_HOME ==${NC}"
OFFLINE_HOME="$ROOT/$OFFLINE_HOME_NAME"
mkdir -p "$OFFLINE_HOME"
export GRADLE_USER_HOME="$OFFLINE_HOME"
echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}"
echo -e "${GRAY}[INFO] All dependencies will be cached in project folder${NC}"
echo ""
# ============================================================================
# [5/20] Check Internet Connection
# ============================================================================
echo -e "${YELLOW}==[5/20] Check Internet Connection ==${NC}"
HAS_INTERNET=false
TEST_HOSTS=("plugins.gradle.org" "repo.maven.apache.org" "repo1.maven.org")
for TEST_HOST in "${TEST_HOSTS[@]}"; do
# macOS ping doesn't have -W, use -t instead
if ping -c 1 -t 3 "$TEST_HOST" &>/dev/null; then
HAS_INTERNET=true
echo -e "${GREEN}[OK] Connected to $TEST_HOST${NC}"
break
fi
done
if [ "$HAS_INTERNET" = false ]; then
# Try DNS resolution as fallback
if nslookup google.com &>/dev/null || host google.com &>/dev/null; then
HAS_INTERNET=true
echo -e "${GREEN}[OK] Internet available (DNS)${NC}"
fi
fi
if [ "$HAS_INTERNET" = false ]; then
echo ""
echo -e "${RED}============================================================${NC}"
echo -e "${RED} ERROR: No Internet Connection!${NC}"
echo -e "${RED}============================================================${NC}"
echo ""
echo -e "${YELLOW}This script requires internet for initial build.${NC}"
echo -e "${YELLOW}Please connect to internet and run again.${NC}"
echo ""
exit 1
fi
echo ""
# ============================================================================
# [6/20] Initial Gradle Setup
# ============================================================================
echo -e "${YELLOW}==[6/20] Initial Gradle Setup ==${NC}"
echo -e "${GRAY}[INFO] Downloading Gradle distribution...${NC}"
if ./gradlew --version &>/dev/null; then
GRADLE_VERSION=$(./gradlew --version 2>&1 | grep "^Gradle" | awk '{print $2}')
echo -e "${GREEN}[OK] Gradle $GRADLE_VERSION${NC}"
else
echo -e "${RED}[ERROR] Gradle setup failed${NC}"
exit 1
fi
echo ""
# ============================================================================
# [7/20] ONLINE BUILD - bootJar (Download All Dependencies)
# ============================================================================
echo -e "${YELLOW}==[7/20] ONLINE BUILD - bootJar ==${NC}"
echo ""
echo -e "${CYAN}============================================================${NC}"
echo -e "${CYAN} ONLINE BUILD (with Internet)${NC}"
echo -e "${CYAN} Downloading all dependencies to local cache${NC}"
echo -e "${CYAN}============================================================${NC}"
echo ""
BUILD_SUCCESS=false
./gradlew clean bootJar --no-daemon
if [ $? -eq 0 ]; then
BUILD_SUCCESS=true
echo ""
echo -e "${GREEN}============================================================${NC}"
echo -e "${GREEN} ONLINE BUILD SUCCESS!${NC}"
echo -e "${GREEN}============================================================${NC}"
echo ""
if [ -d "./build/libs" ]; then
echo -e "${CYAN}JAR files:${NC}"
ls -lh ./build/libs/*.jar 2>/dev/null | awk '{print " " $9 " (" $5 ")"}'
fi
else
echo ""
echo -e "${RED}============================================================${NC}"
echo -e "${RED} BUILD FAILED!${NC}"
echo -e "${RED}============================================================${NC}"
echo ""
echo -e "${YELLOW}Build failed. Cannot continue.${NC}"
exit 1
fi
echo ""
# ============================================================================
# [8/20] Stop Daemons
# ============================================================================
echo -e "${YELLOW}==[8/20] Stop Daemons ==${NC}"
./gradlew --stop &>/dev/null || true
sleep 2
echo -e "${GREEN}[OK] Daemons stopped${NC}"
echo ""
# ============================================================================
# [9/20] ONLINE TEST - bootRun (Verify Application Works)
# ============================================================================
echo -e "${YELLOW}==[9/20] ONLINE TEST - bootRun ==${NC}"
echo ""
echo -e "${CYAN}============================================================${NC}"
echo -e "${CYAN} Testing application startup (timeout: ${BOOTRUN_TIMEOUT_SECONDS}s)${NC}"
echo -e "${CYAN} Will automatically stop after successful startup${NC}"
echo -e "${CYAN}============================================================${NC}"
echo ""
BOOTRUN_SUCCESS=false
# macOS uses gtimeout if available, otherwise perl-based timeout
if command -v gtimeout &>/dev/null; then
gtimeout ${BOOTRUN_TIMEOUT_SECONDS}s ./gradlew bootRun --no-daemon &
else
# Fallback: start in background and kill after timeout
./gradlew bootRun --no-daemon &
fi
BOOTRUN_PID=$!
sleep 10
if ps -p $BOOTRUN_PID &>/dev/null; then
BOOTRUN_SUCCESS=true
echo ""
echo -e "${GREEN}[OK] Application started successfully${NC}"
kill $BOOTRUN_PID &>/dev/null || true
sleep 2
else
echo ""
echo -e "${YELLOW}[WARN] Application may not have started properly${NC}"
fi
# Cleanup - macOS process cleanup
pkill -f "gradle.*bootRun" &>/dev/null || true
sleep 2
echo ""
# ============================================================================
# [10/20] Stop Daemons Again
# ============================================================================
echo -e "${YELLOW}==[10/20] Stop Daemons Again ==${NC}"
./gradlew --stop &>/dev/null || true
sleep 2
echo -e "${GREEN}[OK] Daemons stopped${NC}"
echo ""
# ============================================================================
# [11/20] OFFLINE BUILD TEST (Verify Cache Completeness)
# ============================================================================
echo -e "${YELLOW}==[11/20] OFFLINE BUILD TEST ==${NC}"
echo ""
echo -e "${CYAN}============================================================${NC}"
echo -e "${CYAN} OFFLINE BUILD TEST (--offline flag)${NC}"
echo -e "${CYAN} Verifying all dependencies are cached${NC}"
echo -e "${CYAN}============================================================${NC}"
echo ""
OFFLINE_SUCCESS=false
./gradlew clean bootJar --offline --no-daemon
if [ $? -eq 0 ]; then
OFFLINE_SUCCESS=true
echo ""
echo -e "${GREEN}============================================================${NC}"
echo -e "${GREEN} OFFLINE BUILD TEST PASSED!${NC}"
echo -e "${GREEN}============================================================${NC}"
echo ""
echo -e "${GREEN}[OK] All dependencies are cached${NC}"
else
echo ""
echo -e "${RED}============================================================${NC}"
echo -e "${RED} OFFLINE BUILD TEST FAILED!${NC}"
echo -e "${RED}============================================================${NC}"
echo ""
echo -e "${YELLOW}Some dependencies may be missing from cache.${NC}"
echo -e "${YELLOW}The bundle may not work in air-gapped environment.${NC}"
echo ""
read -p "Continue anyway? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
echo ""
# ============================================================================
# [12/20] Stop Daemons Before Archive
# ============================================================================
echo -e "${YELLOW}==[12/20] Stop Daemons Before Archive ==${NC}"
./gradlew --stop &>/dev/null || true
sleep 2
echo -e "${GREEN}[OK] Daemons stopped${NC}"
echo ""
# ============================================================================
# [13/20] Verify settings.gradle for Offline
# ============================================================================
echo -e "${YELLOW}==[13/20] Verify settings.gradle ==${NC}"
if [ -n "$SETTINGS_FILE" ]; then
if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then
echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}"
else
echo -e "${YELLOW}[WARN] settings.gradle may need offline configuration${NC}"
echo -e "${GRAY}[INFO] Consider adding mavenLocal() to pluginManagement and repositories${NC}"
fi
else
echo -e "${GRAY}[INFO] No settings.gradle found${NC}"
fi
echo ""
# ============================================================================
# [14/20] Create Helper Scripts
# ============================================================================
echo -e "${YELLOW}==[14/20] Create Helper Scripts ==${NC}"
# run_offline_build.sh
cat > "$ROOT/run_offline_build.sh" << 'EOF'
#!/bin/bash
# run_offline_build.sh - Build JAR offline
export GRADLE_USER_HOME="$(pwd)/_offline_gradle_home"
echo "GRADLE_USER_HOME = $GRADLE_USER_HOME"
echo ""
./gradlew --offline bootJar --no-daemon
if [ $? -eq 0 ]; then
echo ""
echo "BUILD SUCCESS!"
echo ""
echo "JAR files:"
ls -lh ./build/libs/*.jar 2>/dev/null | awk '{print " " $9}'
else
echo "BUILD FAILED"
fi
EOF
chmod +x "$ROOT/run_offline_build.sh"
echo -e "${GREEN}[OK] run_offline_build.sh${NC}"
# run_offline_bootrun.sh
cat > "$ROOT/run_offline_bootrun.sh" << 'EOF'
#!/bin/bash
# run_offline_bootrun.sh - Run application offline
export GRADLE_USER_HOME="$(pwd)/_offline_gradle_home"
echo "GRADLE_USER_HOME = $GRADLE_USER_HOME"
echo ""
echo "Starting application (Ctrl+C to stop)..."
echo ""
./gradlew --offline bootRun --no-daemon
EOF
chmod +x "$ROOT/run_offline_bootrun.sh"
echo -e "${GREEN}[OK] run_offline_bootrun.sh${NC}"
echo ""
# ============================================================================
# [15/20] Final Daemon Cleanup
# ============================================================================
echo -e "${YELLOW}==[15/20] Final Daemon Cleanup ==${NC}"
./gradlew --stop &>/dev/null || true
sleep 2
echo -e "${GREEN}[OK] Daemons stopped${NC}"
echo ""
# ============================================================================
# [16/20] Clean Lock Files
# ============================================================================
echo -e "${YELLOW}==[16/20] Clean Lock Files ==${NC}"
DAEMON_DIR="$OFFLINE_HOME/daemon"
if [ -d "$DAEMON_DIR" ]; then
rm -rf "$DAEMON_DIR" 2>/dev/null || true
fi
find "$OFFLINE_HOME" -type f \( -name "*.lock" -o -name "*.log" -o -name "*.tmp" \) -delete 2>/dev/null || true
echo -e "${GREEN}[OK] Lock files cleaned${NC}"
echo ""
# ============================================================================
# [17/20] Calculate Cache Size
# ============================================================================
echo -e "${YELLOW}==[17/20] Cache Summary ==${NC}"
CACHES_DIR="$OFFLINE_HOME/caches"
WRAPPER_DISTS="$OFFLINE_HOME/wrapper/dists"
TOTAL_SIZE=0
if [ -d "$CACHES_DIR" ]; then
# macOS uses different options for du
if du -k "$CACHES_DIR" &>/dev/null; then
SIZE=$(du -sk "$CACHES_DIR" 2>/dev/null | cut -f1)
SIZE=$((SIZE * 1024)) # Convert to bytes
else
SIZE=0
fi
TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $SIZE / 1048576}")
echo -e "${CYAN}[INFO] Dependencies: ${SIZE_MB} MB${NC}"
fi
if [ -d "$WRAPPER_DISTS" ]; then
if du -k "$WRAPPER_DISTS" &>/dev/null; then
SIZE=$(du -sk "$WRAPPER_DISTS" 2>/dev/null | cut -f1)
SIZE=$((SIZE * 1024))
else
SIZE=0
fi
TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $SIZE / 1048576}")
echo -e "${CYAN}[INFO] Gradle dist: ${SIZE_MB} MB${NC}"
fi
TOTAL_MB=$(awk "BEGIN {printf \"%.2f\", $TOTAL_SIZE / 1048576}")
echo -e "${CYAN}[INFO] Total cache: ${TOTAL_MB} MB${NC}"
echo ""
# ============================================================================
# [18/20] Create Archive
# ============================================================================
echo -e "${YELLOW}==[18/20] Create Archive ==${NC}"
BASE_NAME=$(basename "$ROOT")
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
PARENT=$(dirname "$ROOT")
ARCHIVE_PATH="${PARENT}/${BASE_NAME}_offline_bundle_${TIMESTAMP}.tar.gz"
echo "Archive: $ARCHIVE_PATH"
echo -e "${GRAY}[INFO] Creating archive (this may take several minutes)...${NC}"
# macOS tar with BSD options
tar -czf "$ARCHIVE_PATH" \
--exclude=".git" \
--exclude=".idea" \
--exclude=".DS_Store" \
--exclude="*.log" \
--exclude="*.lock" \
--exclude="_offline_gradle_home/daemon" \
--exclude="_offline_gradle_home/native" \
--exclude="_offline_gradle_home/jdks" \
--exclude="build" \
--exclude="out" \
--exclude=".gradle" \
-C "$ROOT" .
if [ $? -ne 0 ]; then
echo -e "${RED}ERROR: tar failed${NC}"
exit 1
fi
# macOS stat command
ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE_PATH" 2>/dev/null)
ARCHIVE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $ARCHIVE_SIZE / 1048576}")
echo -e "${GREEN}[OK] Archive created: ${ARCHIVE_SIZE_MB} MB${NC}"
echo ""
# ============================================================================
# [19/20] Verify Archive
# ============================================================================
echo -e "${YELLOW}==[19/20] Verify Archive ==${NC}"
CHECKS=(
"gradle/wrapper/gradle-wrapper.jar"
"gradlew"
"_offline_gradle_home/caches"
"run_offline_build.sh"
)
for CHECK in "${CHECKS[@]}"; do
if tar -tzf "$ARCHIVE_PATH" | grep -q "$CHECK"; then
echo -e " ${GREEN}[OK] $CHECK${NC}"
else
echo -e " ${YELLOW}[WARN] $CHECK${NC}"
fi
done
echo ""
# ============================================================================
# [20/20] Complete
# ============================================================================
echo -e "${GREEN}============================================================${NC}"
echo -e "${GREEN} BUNDLE CREATION COMPLETE!${NC}"
echo -e "${GREEN}============================================================${NC}"
echo ""
echo -e "${CYAN}Archive: $ARCHIVE_PATH${NC}"
echo -e "${CYAN}Size: ${ARCHIVE_SIZE_MB} MB${NC}"
echo ""
echo -e "${CYAN}============================================================${NC}"
echo -e "${CYAN} Test Results${NC}"
echo -e "${CYAN}============================================================${NC}"
if [ "$BUILD_SUCCESS" = true ]; then
echo -e " Online build (bootJar): ${GREEN}PASSED${NC}"
else
echo -e " Online build (bootJar): ${RED}FAILED${NC}"
fi
if [ "$BOOTRUN_SUCCESS" = true ]; then
echo -e " Online test (bootRun): ${GREEN}PASSED${NC}"
else
echo -e " Online test (bootRun): ${YELLOW}SKIPPED${NC}"
fi
if [ "$OFFLINE_SUCCESS" = true ]; then
echo -e " Offline build test: ${GREEN}PASSED${NC}"
else
echo -e " Offline build test: ${RED}FAILED${NC}"
fi
echo ""
echo -e "${YELLOW}============================================================${NC}"
echo -e "${YELLOW} Usage in Air-gapped Environment${NC}"
echo -e "${YELLOW}============================================================${NC}"
echo ""
echo -e "${WHITE}Option 1: Use unpack script${NC}"
echo -e "${GRAY} ./unpack_and_offline_build_airgap.sh${NC}"
echo ""
echo -e "${WHITE}Option 2: Manual extraction${NC}"
echo -e "${GRAY} tar -xzf <archive>.tar.gz${NC}"
echo -e "${GRAY} cd <project>${NC}"
echo -e "${GRAY} ./run_offline_build.sh${NC}"
echo ""
echo -e "${WHITE}Option 3: Direct commands${NC}"
echo -e "${GRAY} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}"
echo -e "${GRAY} ./gradlew --offline bootJar --no-daemon${NC}"
echo ""

View File

@@ -1,359 +0,0 @@
#!/bin/bash
# unpack_and_offline_build_airgap_macos.sh
# ============================================================================
# Execution Environment: OFFLINE (Air-gapped, No Internet)
# Purpose: Extract bundle and run offline build
# ============================================================================
# macOS Bash Script
# Version: 3.1
#
# IMPORTANT: This script automatically:
# 1. Extracts the archive
# 2. Sets GRADLE_USER_HOME to project local cache
# 3. Configures settings.gradle for offline resolution
# 4. Runs build with --offline flag
# ============================================================================
set -e
# ============================================================================
# Configuration
# ============================================================================
WRAPPER_SEED_PATH="wrapper_jar_seed"
OFFLINE_HOME_NAME="_offline_gradle_home"
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
WHITE='\033[1;37m'
NC='\033[0m' # No Color
echo ""
echo -e "${CYAN}============================================================${NC}"
echo -e "${CYAN} Gradle Offline Build Runner (macOS)${NC}"
echo -e "${CYAN} Environment: AIR-GAPPED (No Internet)${NC}"
echo -e "${CYAN} Mode: Fully Offline (--offline enforced)${NC}"
echo -e "${CYAN}============================================================${NC}"
echo ""
# ============================================================================
# [1/16] Check Current Directory
# ============================================================================
echo -e "${YELLOW}==[1/16] Check Current Directory ==${NC}"
START_DIR="$(pwd)"
echo "PWD: $START_DIR"
echo ""
# ============================================================================
# [2/16] Select Archive
# ============================================================================
echo -e "${YELLOW}==[2/16] Select Archive ==${NC}"
ARCHIVE=""
if [ $# -ge 1 ]; then
ARCHIVE="$1"
fi
if [ -z "$ARCHIVE" ]; then
# Auto-detect most recent .tar.gz file (macOS compatible)
ARCHIVE=$(find "$START_DIR" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.tgz" \) -exec stat -f "%m %N" {} \; 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
if [ -z "$ARCHIVE" ]; then
echo -e "${RED}[ERROR] No archive found${NC}"
ls -lh "$START_DIR"
exit 1
fi
echo -e "${CYAN}[AUTO] $(basename "$ARCHIVE")${NC}"
else
if [ ! -f "$ARCHIVE" ]; then
ARCHIVE="$START_DIR/$ARCHIVE"
fi
echo -e "${CYAN}[USER] $(basename "$ARCHIVE")${NC}"
fi
if [ ! -f "$ARCHIVE" ]; then
echo -e "${RED}ERROR: Archive not found: $ARCHIVE${NC}"
exit 1
fi
# macOS stat command
ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE" 2>/dev/null)
ARCHIVE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $ARCHIVE_SIZE / 1048576}")
echo "Size: ${ARCHIVE_SIZE_MB} MB"
echo ""
# ============================================================================
# [3/16] Check tar
# ============================================================================
echo -e "${YELLOW}==[3/16] Check tar ==${NC}"
if ! command -v tar &>/dev/null; then
echo -e "${RED}ERROR: tar not found${NC}"
exit 1
fi
echo -e "${GREEN}[OK] tar found${NC}"
echo ""
# ============================================================================
# [4/16] Extract Archive
# ============================================================================
echo -e "${YELLOW}==[4/16] Extract Archive ==${NC}"
echo -e "${GRAY}[INFO] Extracting...${NC}"
tar -xzf "$ARCHIVE" -C "$START_DIR"
if [ $? -ne 0 ]; then
echo -e "${RED}ERROR: Extraction failed${NC}"
exit 1
fi
echo -e "${GREEN}[OK] Extracted${NC}"
echo ""
# ============================================================================
# [5/16] Set Permissions
# ============================================================================
echo -e "${YELLOW}==[5/16] Set Permissions ==${NC}"
chmod -R u+rw "$START_DIR" 2>/dev/null || true
# Remove extended attributes that macOS may add
xattr -cr "$START_DIR" 2>/dev/null || true
echo -e "${GREEN}[OK] Permissions set${NC}"
echo ""
# ============================================================================
# [6/16] Find Project Root
# ============================================================================
echo -e "${YELLOW}==[6/16] Find Project Root ==${NC}"
GRADLEW=$(find "$START_DIR" -name "gradlew" -type f 2>/dev/null | sort | head -1)
if [ -z "$GRADLEW" ]; then
echo -e "${RED}ERROR: gradlew not found${NC}"
exit 1
fi
PROJECT_DIR=$(dirname "$GRADLEW")
echo -e "${CYAN}Project: $PROJECT_DIR${NC}"
cd "$PROJECT_DIR"
echo ""
# ============================================================================
# [7/16] Fix Permissions
# ============================================================================
echo -e "${YELLOW}==[7/16] Fix Permissions ==${NC}"
chmod +x ./gradlew
find . -name "*.sh" -type f -exec chmod +x {} \; 2>/dev/null || true
# Remove quarantine attributes that macOS adds to downloaded files
xattr -d com.apple.quarantine ./gradlew 2>/dev/null || true
find . -name "*.jar" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true
echo -e "${GREEN}[OK] Permissions fixed${NC}"
echo ""
# ============================================================================
# [8/16] Verify Wrapper
# ============================================================================
echo -e "${YELLOW}==[8/16] Verify Wrapper ==${NC}"
WRAPPER_DIR="$PROJECT_DIR/gradle/wrapper"
WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar"
WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties"
if [ ! -f "$WRAPPER_PROP" ]; then
echo -e "${RED}ERROR: gradle-wrapper.properties missing${NC}"
exit 1
fi
if [ ! -f "$WRAPPER_JAR" ]; then
SEED_JAR="$PROJECT_DIR/$WRAPPER_SEED_PATH/gradle-wrapper.jar"
if [ -f "$SEED_JAR" ]; then
mkdir -p "$WRAPPER_DIR"
cp "$SEED_JAR" "$WRAPPER_JAR"
echo -e "${GREEN}[OK] Injected from seed${NC}"
else
echo -e "${RED}ERROR: wrapper jar missing${NC}"
exit 1
fi
else
echo -e "${GREEN}[OK] Wrapper verified${NC}"
fi
echo ""
# ============================================================================
# [9/16] Set GRADLE_USER_HOME
# ============================================================================
echo -e "${YELLOW}==[9/16] Set GRADLE_USER_HOME ==${NC}"
OFFLINE_HOME="$PROJECT_DIR/$OFFLINE_HOME_NAME"
if [ ! -d "$OFFLINE_HOME" ]; then
echo -e "${RED}ERROR: _offline_gradle_home not found in archive${NC}"
exit 1
fi
export GRADLE_USER_HOME="$OFFLINE_HOME"
echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}"
# Check cache
CACHES_DIR="$OFFLINE_HOME/caches"
if [ -d "$CACHES_DIR" ]; then
# macOS du command
if du -k "$CACHES_DIR" &>/dev/null; then
CACHE_SIZE=$(du -sk "$CACHES_DIR" 2>/dev/null | cut -f1)
CACHE_SIZE=$((CACHE_SIZE * 1024))
else
CACHE_SIZE=0
fi
CACHE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $CACHE_SIZE / 1048576}")
echo -e "${CYAN}[INFO] Cache size: ${CACHE_SIZE_MB} MB${NC}"
else
echo -e "${YELLOW}[WARN] No cache folder found${NC}"
fi
echo ""
# ============================================================================
# [10/16] Verify settings.gradle
# ============================================================================
echo -e "${YELLOW}==[10/16] Verify settings.gradle ==${NC}"
SETTINGS_FILE=""
if [ -f "./settings.gradle" ]; then
SETTINGS_FILE="settings.gradle"
elif [ -f "./settings.gradle.kts" ]; then
SETTINGS_FILE="settings.gradle.kts"
fi
if [ -n "$SETTINGS_FILE" ]; then
if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then
echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}"
else
echo -e "${YELLOW}[WARN] settings.gradle may not be configured for offline${NC}"
echo -e "${GRAY}[INFO] Build may fail if plugins not cached${NC}"
fi
fi
echo ""
# ============================================================================
# [11/16] Test Gradle
# ============================================================================
echo -e "${YELLOW}==[11/16] Test Gradle ==${NC}"
GRADLE_WORKS=false
if ./gradlew --offline --version &>/dev/null; then
GRADLE_WORKS=true
echo -e "${GREEN}[OK] Gradle working in offline mode${NC}"
else
echo -e "${YELLOW}[WARN] Gradle --version failed${NC}"
fi
echo ""
# ============================================================================
# [12/16] Stop Daemon
# ============================================================================
echo -e "${YELLOW}==[12/16] Stop Daemon ==${NC}"
./gradlew --stop &>/dev/null || true
sleep 2
echo -e "${GREEN}[OK] Daemon stopped${NC}"
echo ""
# ============================================================================
# [13/16] Run Offline Build
# ============================================================================
echo -e "${YELLOW}==[13/16] Run Offline Build ==${NC}"
echo ""
echo -e "${CYAN}============================================================${NC}"
echo -e "${CYAN} Building with --offline flag${NC}"
echo -e "${CYAN} All dependencies from local cache${NC}"
echo -e "${CYAN}============================================================${NC}"
echo ""
BUILD_SUCCESS=false
BUILD_TASK=""
# Try bootJar
echo -e "${GRAY}[TRY] --offline bootJar...${NC}"
if ./gradlew --offline clean bootJar --no-daemon; then
BUILD_SUCCESS=true
BUILD_TASK="bootJar"
fi
# Try jar
if [ "$BUILD_SUCCESS" = false ]; then
echo -e "${GRAY}[TRY] --offline jar...${NC}"
if ./gradlew --offline clean jar --no-daemon; then
BUILD_SUCCESS=true
BUILD_TASK="jar"
fi
fi
# Try build
if [ "$BUILD_SUCCESS" = false ]; then
echo -e "${GRAY}[TRY] --offline build...${NC}"
if ./gradlew --offline build --no-daemon; then
BUILD_SUCCESS=true
BUILD_TASK="build"
fi
fi
echo ""
if [ "$BUILD_SUCCESS" = true ]; then
echo -e "${GREEN}============================================================${NC}"
echo -e "${GREEN} BUILD SUCCESS! (task: $BUILD_TASK)${NC}"
echo -e "${GREEN}============================================================${NC}"
else
echo -e "${RED}============================================================${NC}"
echo -e "${RED} BUILD FAILED!${NC}"
echo -e "${RED}============================================================${NC}"
echo ""
echo -e "${YELLOW}Possible causes:${NC}"
echo -e "${WHITE} - Dependencies not in cache${NC}"
echo -e "${WHITE} - Plugin resolution failed${NC}"
echo -e "${WHITE} - Need complete build in online env first${NC}"
exit 1
fi
echo ""
# ============================================================================
# [14/16] Show Build Output
# ============================================================================
echo -e "${YELLOW}==[14/16] Build Output ==${NC}"
LIBS_DIR="$PROJECT_DIR/build/libs"
if [ -d "$LIBS_DIR" ]; then
echo -e "${CYAN}build/libs contents:${NC}"
ls -lh "$LIBS_DIR"/*.jar 2>/dev/null | awk '{printf " %-40s %10s\n", $9, $5}'
MAIN_JAR=$(find "$LIBS_DIR" -name "*.jar" -type f ! -name "*-plain.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" 2>/dev/null | head -1)
else
echo -e "${YELLOW}[WARN] build/libs not found${NC}"
fi
echo ""
# ============================================================================
# [15/16] Run Instructions
# ============================================================================
echo -e "${YELLOW}==[15/16] Run Instructions ==${NC}"
echo ""
if [ -n "$MAIN_JAR" ]; then
echo -e "${CYAN}To run the application:${NC}"
echo -e "${WHITE} java -jar $(basename "$MAIN_JAR")${NC}"
echo ""
fi
echo -e "${CYAN}To rebuild:${NC}"
echo -e "${WHITE} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}"
echo -e "${WHITE} ./gradlew --offline bootJar --no-daemon${NC}"
echo ""
# ============================================================================
# [16/16] Complete
# ============================================================================
echo -e "${GREEN}============================================================${NC}"
echo -e "${GREEN} Offline Build Complete!${NC}"
echo -e "${GREEN}============================================================${NC}"
echo ""
echo -e "${CYAN}Project: $PROJECT_DIR${NC}"
echo ""

View File

View File

@@ -0,0 +1,2 @@
#Mon Feb 02 19:50:45 KST 2026
gradle.version=8.14

Binary file not shown.

View File

@@ -0,0 +1,112 @@
# Code Style 설정 가이드
이 문서는 프로젝트에서 Google Java Style을 자동으로 적용하기 위한 설정 가이드입니다.
## 자동 포맷팅 구성
### 1. 커밋 시점 자동 포맷팅 (Git Pre-commit Hook)
커밋 전에 자동으로 코드를 포맷팅하고 스테이징합니다.
**설정 완료:** `.git/hooks/pre-commit` 파일이 자동으로 실행됩니다.
**동작 방식:**
- 커밋 시도 시 `./gradlew spotlessApply` 자동 실행
- 스테이징된 Java 파일을 자동으로 포맷팅
- 포맷팅된 파일을 자동으로 다시 스테이징
- 포맷팅이 완료되면 커밋 진행
**장점:**
- 수동으로 `spotlessApply`를 실행할 필요 없음
- 항상 일관된 코드 스타일 유지
- 포맷팅 누락 방지
### 2. IntelliJ IDEA 저장 시점 자동 포맷팅
#### 방법 1: Code Style 설정 임포트 (권장)
1. **IntelliJ IDEA 열기**
2. **Settings/Preferences** (Mac: `⌘,` / Windows: `Ctrl+Alt+S`)
3. **Editor > Code Style > Java**
4. **⚙️ (톱니바퀴)** 클릭 > **Import Scheme > IntelliJ IDEA code style XML**
5. 프로젝트 루트의 `intellij-java-google-style.xml` 파일 선택
6. **OK** 클릭
#### 방법 2: 저장 시 자동 포맷팅 활성화
**Option A: Actions on Save 설정**
1. **Settings/Preferences** > **Tools > Actions on Save**
2. 다음 옵션들을 활성화:
-**Reformat code**
-**Optimize imports**
-**Rearrange code** (선택사항)
3. **Changed lines** 또는 **Whole file** 선택
4. **OK** 클릭
**Option B: Save Actions Plugin 사용 (더 많은 옵션)**
1. **Settings/Preferences** > **Plugins**
2. **Marketplace**에서 "Save Actions" 검색 및 설치
3. **Settings/Preferences** > **Other Settings > Save Actions**
4. 다음 옵션 활성화:
-**Activate save actions on save**
-**Reformat file**
-**Optimize imports**
-**Rearrange fields and methods** (선택사항)
### 3. Gradle Spotless Plugin 수동 실행
#### 코드 포맷팅 체크
```bash
# 포맷팅 문제 확인만 (수정하지 않음)
./gradlew spotlessCheck
```
#### 코드 자동 포맷팅
```bash
# 모든 Java 파일 자동 포맷팅 적용
./gradlew spotlessApply
```
#### 빌드 시 자동 체크
```bash
# 빌드 전에 자동으로 spotlessCheck 실행됨
./gradlew build
```
## 코드 스타일 규칙
프로젝트는 **Google Java Style Guide** 기반으로 다음 규칙을 따릅니다:
- **Indentation**: 2 spaces (탭 아님)
- **Line Length**: 180 characters
- **Line Endings**: LF (Unix-style)
- **Charset**: UTF-8
- **Import Order**: Static imports → 빈 줄 → Regular imports
- **Braces**: 모든 if, for, while, do 문에 중괄호 필수
## 문제 해결
### Pre-commit hook이 실행되지 않는 경우
```bash
# 실행 권한 확인 및 부여
chmod +x .git/hooks/pre-commit
```
### Spotless 플러그인이 동작하지 않는 경우
```bash
# Gradle 의존성 다시 다운로드
./gradlew clean build --refresh-dependencies
```
### IntelliJ 포맷팅이 다르게 적용되는 경우
1. `intellij-java-google-style.xml` 다시 임포트
2. **File > Invalidate Caches** > **Invalidate and Restart**
## 추가 정보
- **Google Java Style Guide**: https://google.github.io/styleguide/javaguide.html
- **Spotless Plugin**: https://github.com/diffplug/spotless
- **IntelliJ Code Style**: https://www.jetbrains.com/help/idea/code-style.html

View File

@@ -0,0 +1,282 @@
# 공통코드 Redis 캐시 시스템 - DanielLee
## 요구사항 검토
### 1. **API를 통해 공통코드 제공**
- **구현 완료**: `CommonCodeApiController`에서 전체 공통코드 조회 API 제공
```
GET /api/code
→ 모든 공통코드 조회
```
- **추가 구현**: 캐시 갱신 및 상태 확인 API
```
POST /api/code/cache/refresh → 캐시 갱신
GET /api/code/cache/status → 캐시 상태 확인
```
---
### 2. **애플리케이션 로딩시 Redis 캐시에 올리기**
- **구현 완료**: `CommonCodeCacheManager` 클래스 생성
#### 초기화 메커니즘
```java
@Component
@RequiredArgsConstructor
public class CommonCodeCacheManager {
@EventListener(ApplicationReadyEvent.class)
public void initializeCommonCodeCache() {
// 애플리케이션 완전히 시작된 후 공통코드를 Redis에 미리 로드
List<Basic> allCommonCodes = commonCodeService.getFindAll();
// @Cacheable이 자동으로 Redis에 캐시함
}
}
```
#### 동작 흐름
1. 애플리케이션 시작
2. Spring이 모든 Bean 생성 완료 (`ApplicationReadyEvent` 발생)
3. `CommonCodeCacheManager.initializeCommonCodeCache()` 실행
4. `commonCodeService.getFindAll()` 호출 (DB에서 조회)
5. `@Cacheable(value = "commonCodes")` 에노테이션이 결과를 Redis에 저장
---
### 3. **공통코드 변경시 데이터 갱신**
#### 자동 갱신
- **등록 (CREATE)**: `@CacheEvict` → 캐시 전체 삭제
- **수정 (UPDATE)**: `@CacheEvict` → 캐시 전체 삭제
- **삭제 (DELETE)**: `@CacheEvict` → 캐시 전체 삭제
- **순서 변경**: `@CacheEvict` → 캐시 전체 삭제
```java
@CacheEvict(value = "commonCodes", allEntries = true)
public ResponseObj save(CommonCodeDto.AddReq req) {
// 공통코드 저장
// ↓
// 캐시 전체 삭제 (다음 조회 시 DB에서 새로 로드)
}
```
#### 수동 갱신 (관리자)
```java
POST /api/code/cache/refresh
```
- 공통코드 설정이 변경된 후 API를 호출하여 캐시를 강제 갱신
#### 캐시 상태 모니터링
```java
GET /api/code/cache/status
→ 응답: { "data": 150 } // 캐시된 공통코드 150개
```
---
## 전체 아키텍처
```
┌─────────────────────────────────────────────────────────┐
│ 클라이언트 요청 │
└──────────────────┬──────────────────────────────────────┘
┌──────────▼──────────┐
│ CommonCodeApiController
└──────────┬──────────┘
┌─────────┴──────────┐
│ │
┌────▼─────┐ ┌──────▼────────────┐
│ 조회 API │ │ 캐시 관리 API │
│ (GET) │ │(POST, GET) │
└────┬─────┘ └──────┬────────────┘
│ │
│ ┌────────▼──────────┐
│ │CommonCodeCacheManager
│ │(캐시 초기화/갱신) │
│ └────────┬──────────┘
│ │
┌────▼─────────────────┬─▼────┐
│ CommonCodeService │ │
│ (@Cacheable) │ │
│ (@CacheEvict) │ │
└────┬──────────────────┴──────┘
┌────▼──────────┐
│ Redis 캐시 │
│ (공통코드) │
└────┬──────────┘
┌────▼──────────┐
│ PostgreSQL DB │
│ (공통코드) │
└───────────────┘
```
---
## API 명세
### 1. 공통코드 조회 (캐시됨)
```
GET /api/code
응답:
{
"data": [
{
"id": 1,
"code": "STATUS",
"name": "상태",
"description": "상태 공통코드",
"used": true,
...
},
...
]
}
```
### 2. 공통코드 캐시 갱신
```
POST /api/code/cache/refresh
응답:
{
"data": "공통코드 캐시가 갱신되었습니다."
}
```
### 3. 캐시 상태 확인
```
GET /api/code/cache/status
응답:
{
"data": 150 // Redis에 캐시된 공통코드 개수
}
```
---
## 캐시 갱신 흐름
### 자동 갱신 (CRUD 작업)
```
관리자가 공통코드 등록/수정/삭제
CommonCodeService.save() / update() / removeCode()
(@CacheEvict 실행)
Redis 캐시 전체 삭제
다음 조회 시 DB에서 새로 로드
```
### 수동 갱신 (API 호출)
```
관리자: POST /api/code/cache/refresh
CommonCodeCacheManager.refreshCommonCodeCache()
캐시 정리 + 새로운 데이터 로드
Redis 캐시 업데이트 완료
```
---
## 성능 최적화 효과
| 항목 | 개선 전 | 개선 후 |
|------|--------|--------|
| **조회 속도** | DB 직접 조회 (10-100ms) | Redis 캐시 (1-5ms) |
| **DB 부하** | 매번 조회 | 캐시 미스시만 조회 |
| **네트워크 대역폭** | 높음 (DB 왕복) | 낮음 (로컬 캐시) |
| **응답 시간** | 변동적 | 일정 (캐시) |
---
## 추가 기능
### CommonCodeUtil - 전역 공통코드 조회
```java
@Component
public class CommonCodeUtil {
// 모든 공통코드 조회 (캐시 활용)
public List<Basic> getAllCommonCodes()
// 특정 코드로 조회
public List<Basic> getCommonCodesByCode(String code)
// ID로 단건 조회
public Optional<Basic> getCommonCodeById(Long id)
// 코드명 조회
public Optional<String> getCodeName(String parentCode, String childCode)
// 하위 코드 조회
public List<Basic> getChildCodesByParentCode(String parentCode)
// 코드 사용 가능 여부 확인
public boolean isCodeAvailable(Long parentId, String code)
}
```
### 사용 예시
```java
@RequiredArgsConstructor
@RestController
public class SomeController {
private final CommonCodeUtil commonCodeUtil;
@GetMapping("/example")
public void example() {
// 1. 모든 공통코드 조회 (캐시됨)
List<Basic> allCodes = commonCodeUtil.getAllCommonCodes();
// 2. 특정 코드 조회
Optional<String> name = commonCodeUtil.getCodeName("PARENT", "CHILD");
// 3. 코드 사용 가능 여부 확인
boolean available = commonCodeUtil.isCodeAvailable(1L, "NEW_CODE");
}
}
```
---
## 완료 체크리스트
- Redis 캐싱 어노테이션 적용 (@Cacheable, @CacheEvict)
- 애플리케이션 로딩시 캐시 초기화
- CRUD 작업시 자동 캐시 갱신
- 수동 캐시 갱신 API 제공
- 캐시 상태 모니터링 API
- 전역 공통코드 조회 유틸리티
- 포괄적인 유닛 테스트 (12개)
---
## 모니터링
캐시 상태를 주기적으로 모니터링:
```bash
# 캐시 상태 확인
curl http://localhost:8080/api/code/cache/status
# 캐시 갱신
curl -X POST http://localhost:8080/api/code/cache/refresh
```
로그 확인:
```
=== 공통코드 캐시 초기화 시작 ===
✓ 공통코드 150개가 Redis 캐시에 로드되었습니다.
- [STATUS] 상태 (ID: 1)
- [TYPE] 타입 (ID: 2)
...
=== 공통코드 캐시 초기화 완료 ===
```

View File

@@ -0,0 +1,29 @@
# Stage 1: Build stage (gradle build는 Jenkins에서 이미 수행)
FROM eclipse-temurin:21-jre-jammy
# GDAL 설치
RUN apt-get update && apt-get install -y \
gdal-bin \
libgdal-dev \
&& rm -rf /var/lib/apt/lists/*
ARG UID=1000
ARG GID=1000
RUN groupadd -g ${GID} manager01 \
&& useradd -u ${UID} -g ${GID} -m manager01
USER manager01
# 작업 디렉토리 설정
WORKDIR /app
# JAR 파일 복사 (Jenkins에서 빌드된 ROOT.jar)
COPY build/libs/ROOT.jar app.jar
# 포트 노출
EXPOSE 8080
# 애플리케이션 실행
# dev 프로파일로 실행
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev", "app.jar"]

View File

@@ -0,0 +1,94 @@
pipeline {
agent any
tools {
jdk 'jdk21'
}
environment {
BRANCH = 'develop'
GIT_REPO = 'https://10.100.0.10:3210/dabeeo/kamco-dabeeo-backoffice.git'
}
stages {
stage('Checkout') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: "${env.BRANCH}"]],
userRemoteConfigs: [[
url: "${env.GIT_REPO}",
credentialsId: 'jenkins-dev-token'
]]
])
}
}
stage('Get Commit Hash') {
steps {
script {
env.COMMIT_HASH = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim()
echo "Current commit hash: ${env.COMMIT_HASH}"
}
}
}
stage('Build') {
steps {
sh "./gradlew clean build -x test"
}
}
stage('Docker Build & Deploy') {
steps {
script {
echo "Building Docker image with tag: ${env.COMMIT_HASH}"
// IMAGE_TAG 환경변수 설정 후 docker-compose로 빌드 및 배포
sh """
export IMAGE_TAG=${env.COMMIT_HASH}
# 기존 컨테이너 중지 및 제거
docker-compose -f docker-compose-dev.yml down || true
# 새 이미지 빌드
docker-compose -f docker-compose-dev.yml build
# latest 태그도 추가
docker tag kamco-changedetection-api:${env.COMMIT_HASH} kamco-changedetection-api:latest
# 컨테이너 시작
docker-compose -f docker-compose-dev.yml up -d
"""
// 헬스체크 대기
echo "Waiting for application to be ready..."
sh """
for i in {1..30}; do
if docker exec kamco-changedetection-api curl -f http://localhost:8080/monitor/health > /dev/null 2>&1; then
echo "✅ Application is healthy!"
docker-compose -f docker-compose-dev.yml ps
exit 0
fi
echo "⏳ Waiting for application... (\$i/30)"
sleep 2
done
echo "⚠️ Warning: Health check timeout, checking container status..."
docker-compose -f docker-compose-dev.yml ps
"""
}
}
}
stage('Cleanup Old Images') {
steps {
script {
echo "Cleaning up old Docker images..."
sh """
# Keep latest 5 images, remove older ones
docker images kamco-changedetection-api --format "{{.ID}} {{.Tag}}" | \
grep -v latest | tail -n +6 | awk '{print \$1}' | xargs -r docker rmi || true
"""
}
}
}
}
}

View File

@@ -0,0 +1,26 @@
# IMAGERY MAKE DATASET
> 어제 검수완료된 것 geojson 생성 schedule
## 📋 프로젝트 소개
**review-to-down**는 어제 검수 완료된 것을 geojson 파일로 생성하는 schedule 입니다.
## 🚀 시작하기
TrainingDataReviewJobService 의 exportGeojsonLabelingGeom 메소드가 매일 02:00분에 schedule 실행됨
```bash
./gradlew spotlessApply
```
```bash
./gradlew clean build
```
```bash
Java -jar review-to-down.jar \
```
### 필수 요구사항
- Java 21 (JDK 21)
- PostgreSQL 12+ (PostGIS 확장 필요)
- Gradle 8.x (또는 Gradle Wrapper 사용)
- Docker & Docker Compose (선택사항)

View File

@@ -0,0 +1,110 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.7'
id 'io.spring.dependency-management' version '1.1.7'
id 'com.diffplug.spotless' version '6.25.0'
}
group = 'com.kamco.cd'
version = '0.0.1-SNAPSHOT'
description = 'review-to-down'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
bootJar {
archiveFileName = "review-to-down.jar"
}
jar {
enabled = false // plain.jar 안 만들기(혼동 방지)
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
maven { url "https://repo.osgeo.org/repository/release/" }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-validation'
//geometry
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation "org.geotools:gt-shapefile:30.0"
implementation "org.geotools:gt-referencing:30.0"
implementation "org.geotools:gt-geojson:30.0"
implementation 'org.locationtech.jts.io:jts-io-common:1.20.0'
implementation 'org.locationtech.jts:jts-core:1.19.0'
implementation 'org.hibernate:hibernate-spatial:6.2.7.Final'
implementation 'org.geotools:gt-main:30.0'
implementation("org.geotools:gt-geotiff:30.0") {
exclude group: "javax.media", module: "jai_core"
}
implementation 'org.geotools:gt-epsg-hsql:30.0'
// QueryDSL JPA
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
// Q클래스 생성용 annotationProcessor
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
// actuator
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// SpringDoc OpenAPI (Swagger)
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0'
// Apache Commons Compress for archive handling
implementation 'org.apache.commons:commons-compress:1.26.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
implementation 'org.reflections:reflections:0.10.2'
implementation 'org.locationtech.jts:jts-core:1.19.0'
implementation 'org.locationtech.jts.io:jts-io-common:1.19.0'
}
configurations.configureEach {
exclude group: 'javax.media', module: 'jai_core'
}
tasks.named('test') {
useJUnitPlatform()
}
// Spotless configuration for code formatting (2-space indent)
spotless {
java {
target 'src/**/*.java'
googleJavaFormat('1.19.2') // Default Google Style = 2 spaces (NO .aosp()!)
trimTrailingWhitespace()
endWithNewline()
}
}
// Run spotlessCheck before build
tasks.named('build') {
dependsOn 'spotlessCheck'
}

Some files were not shown because too many files have changed in this diff Show More