From 0a95861ba52e2777abc247726e160426b501c8b3 Mon Sep 17 00:00:00 2001 From: Darto KLoning Date: Sat, 3 Oct 2026 16:32:36 +0700 Subject: [PATCH] Handcrafted 4.0.15 --- workflow.bat | 601 ++++++++++++++++++++++++++++++++++++++++----------- workflow.sh | 389 +++++++++++++++++++++++++-------- 2 files changed, 770 insertions(+), 220 deletions(-) diff --git a/workflow.bat b/workflow.bat index bd65dd8..1eb6e56 100644 --- a/workflow.bat +++ b/workflow.bat @@ -2,62 +2,44 @@ setlocal EnableExtensions EnableDelayedExpansion cd /d "%~dp0" +REM ============================================================ +REM Handcrafted - Unified Workflow +REM Compile + Git Push + Mod Testing + Gitea Release +REM Windows +REM ============================================================ + +if not defined GITEA_BASE_URL set "GITEA_BASE_URL=https://git.darto.id" +if not defined GITEA_OWNER set "GITEA_OWNER=dartokloning" +if not defined GITEA_REPO set "GITEA_REPO=handcrafted" + set "PROPS=%CD%\gradle.properties" if not exist "%PROPS%" ( - echo [ERROR] gradle.properties tidak ditemukan. - pause - exit /b 1 + echo [ERROR] gradle.properties tidak ditemukan. + pause + exit /b 1 ) -:refresh -set "MOD_VERSION=" -set "MINECRAFT_VERSION=" -set "ARCHIVES_BASE_NAME=" -for /f "usebackq tokens=1,* delims==" %%A in ("%PROPS%") do ( - if "%%A"=="mod_version" set "MOD_VERSION=%%B" - if "%%A"=="minecraft_version" set "MINECRAFT_VERSION=%%B" - if "%%A"=="archives_base_name" set "ARCHIVES_BASE_NAME=%%B" +call :refresh_properties +call :check_tools + +if exist "%JAR_PATH%" ( + echo [INFO] JAR untuk versi %MOD_VERSION% sudah ditemukan. + goto main_menu ) -if not defined MOD_VERSION set "MOD_VERSION=unknown" -if not defined MINECRAFT_VERSION set "MINECRAFT_VERSION=26.2" -if not defined ARCHIVES_BASE_NAME set "ARCHIVES_BASE_NAME=handcrafted" -set "JAR_PATH=%CD%\build\libs\%ARCHIVES_BASE_NAME%-%MOD_VERSION%.jar" -set "TAG=v%MOD_VERSION%" - -if exist "%JAR_PATH%" goto :menu4 +echo [INFO] JAR untuk versi %MOD_VERSION% belum ditemukan. +echo [INFO] Compile otomatis akan dijalankan. +call :compile_mod +if errorlevel 1 goto build_failed_menu +:main_menu +call :refresh_properties echo. echo ============================================ echo Handcrafted Workflow echo Minecraft : %MINECRAFT_VERSION% echo Version : %MOD_VERSION% -echo JAR : belum ditemukan -echo ============================================ -echo. -echo Build untuk versi ini belum ada. Menjalankan compile... -call :compile -if errorlevel 1 goto :menu_nojar -goto :menu4 - -:menu_nojar -echo. -echo Build gagal / JAR belum tersedia. -echo [1] Push Git -echo [2] Mod Testing -echo [3] Exit -choice /C 123 /N /M "Pilih: " -if errorlevel 3 exit /b 0 -if errorlevel 2 (call :test & goto :refresh) -if errorlevel 1 (call :push & goto :refresh) - -:menu4 -echo. -echo ============================================ -echo Handcrafted Workflow -echo Minecraft : %MINECRAFT_VERSION% -echo Version : %MOD_VERSION% -echo JAR : ditemukan +echo JAR : %JAR_NAME% echo ============================================ echo [1] Push Git echo [2] Mod Testing @@ -65,139 +47,500 @@ echo [3] Make Release echo [4] Exit choice /C 1234 /N /M "Pilih: " if errorlevel 4 exit /b 0 -if errorlevel 3 (call :release & goto :after_release) -if errorlevel 2 (call :test & goto :after_test) -if errorlevel 1 (call :push & goto :after_push) +if errorlevel 3 ( + call :make_release + goto after_release +) +if errorlevel 2 ( + call :test_mod + goto after_test +) +if errorlevel 1 ( + call :push_git + goto after_push +) :after_push echo. +echo ============================================ +echo Action berikutnya +echo ============================================ echo [1] Mod Testing echo [2] Make Release echo [3] Exit choice /C 123 /N /M "Pilih: " if errorlevel 3 exit /b 0 -if errorlevel 2 (call :release & goto :after_release) -if errorlevel 1 (call :test & goto :after_test) +if errorlevel 2 ( + call :make_release + goto after_release +) +if errorlevel 1 ( + call :test_mod + goto after_test +) :after_test echo. +echo ============================================ +echo Action berikutnya +echo ============================================ echo [1] Push Git echo [2] Make Release echo [3] Exit choice /C 123 /N /M "Pilih: " if errorlevel 3 exit /b 0 -if errorlevel 2 (call :release & goto :after_release) -if errorlevel 1 (call :push & goto :after_push) +if errorlevel 2 ( + call :make_release + goto after_release +) +if errorlevel 1 ( + call :push_git + goto after_push +) :after_release echo. +echo ============================================ +echo Action berikutnya +echo ============================================ echo [1] Push Git echo [2] Mod Testing echo [3] Exit choice /C 123 /N /M "Pilih: " if errorlevel 3 exit /b 0 -if errorlevel 2 (call :test & goto :after_test) -if errorlevel 1 (call :push & goto :after_push) - -:compile -echo. -echo [COMPILE] Building %ARCHIVES_BASE_NAME% %MOD_VERSION%... -if exist "%CD%\compile.bat" ( - call "%CD%\compile.bat" --build-only -) else if exist "%CD%\gradlew.bat" ( - call "%CD%\gradlew.bat" clean build --console=plain -) else ( - echo [ERROR] compile.bat maupun gradlew.bat tidak ditemukan. - exit /b 1 +if errorlevel 2 ( + call :test_mod + goto after_test ) if errorlevel 1 ( - echo [ERROR] Compile gagal. - exit /b 1 + call :push_git + goto after_push ) + +:build_failed_menu +echo. +echo [ERROR] Build gagal atau JAR belum tersedia. +echo [1] Coba Compile lagi +echo [2] Push Git +echo [3] Mod Testing +echo [4] Exit +choice /C 1234 /N /M "Pilih: " +if errorlevel 4 exit /b 1 +if errorlevel 3 ( + call :test_mod + goto after_test +) +if errorlevel 2 ( + call :push_git + goto after_push +) +if errorlevel 1 ( + call :compile_mod + if errorlevel 1 goto build_failed_menu + goto main_menu +) + +:refresh_properties +set "MOD_VERSION=" +set "MINECRAFT_VERSION=" +set "ARCHIVES_BASE_NAME=" +for /f "usebackq tokens=1,* delims==" %%A in ("%PROPS%") do ( + if "%%A"=="mod_version" set "MOD_VERSION=%%B" + if "%%A"=="minecraft_version" set "MINECRAFT_VERSION=%%B" + if "%%A"=="archives_base_name" set "ARCHIVES_BASE_NAME=%%B" +) +if not defined MOD_VERSION ( + echo [ERROR] mod_version tidak ditemukan di gradle.properties. + exit /b 1 +) +if not defined MINECRAFT_VERSION set "MINECRAFT_VERSION=26.2" +if not defined ARCHIVES_BASE_NAME set "ARCHIVES_BASE_NAME=handcrafted" + +set "TAG=v%MOD_VERSION%" +set "JAR_NAME=%ARCHIVES_BASE_NAME%-%MOD_VERSION%.jar" +set "JAR_PATH=%CD%\build\libs\%JAR_NAME%" +set "PRERELEASE=false" +echo %MOD_VERSION% | findstr /I /C:"alpha" /C:"beta" /C:"rc" >nul && set "PRERELEASE=true" +exit /b 0 + +:check_tools +where git.exe >nul 2>&1 || echo [WARN] Git tidak ditemukan di PATH. Fitur Git/Release tidak akan bekerja. +where curl.exe >nul 2>&1 || echo [WARN] curl.exe tidak ditemukan di PATH. Gitea Release tidak akan bekerja. +exit /b 0 + +:compile_mod +call :refresh_properties +echo. +echo ============================================ +echo COMPILE +echo Handcrafted %MOD_VERSION% / Minecraft %MINECRAFT_VERSION% +echo ============================================ +if not exist "%CD%\gradlew.bat" ( + echo [ERROR] gradlew.bat tidak ditemukan. + exit /b 1 +) +call "%CD%\gradlew.bat" clean build --console=plain +if errorlevel 1 ( + echo [ERROR] Compile gagal. + exit /b 1 +) +call :refresh_properties if not exist "%JAR_PATH%" ( - echo [ERROR] Build selesai tetapi JAR tidak ditemukan: - echo %JAR_PATH% - exit /b 1 + echo [ERROR] Build sukses tetapi JAR tidak ditemukan: + echo %JAR_PATH% + exit /b 1 ) echo [OK] JAR: %JAR_PATH% exit /b 0 -:push +:push_git +call :refresh_properties echo. -echo [GIT] Push... -where git.exe >nul 2>&1 || (echo [ERROR] Git tidak ditemukan.& exit /b 1) +echo ============================================ +echo GIT PUSH +echo ============================================ +where git.exe >nul 2>&1 || ( + echo [ERROR] Git tidak ditemukan di PATH. + exit /b 1 +) git rev-parse --is-inside-work-tree >nul 2>&1 || ( - echo [ERROR] Folder belum menjadi Git repository. - echo Jalankan: git init - exit /b 1 + echo [ERROR] Folder ini bukan Git repository. + echo [INFO] Jika repository baru, jalankan: git init + exit /b 1 +) +git remote get-url origin >nul 2>&1 || ( + echo [ERROR] Remote origin belum dikonfigurasi. + exit /b 1 +) + +set "CURRENT_BRANCH=" +for /f "delims=" %%B in ('git branch --show-current') do set "CURRENT_BRANCH=%%B" +if not defined CURRENT_BRANCH ( + echo [ERROR] Branch aktif tidak ditemukan. + exit /b 1 ) -git remote get-url origin >nul 2>&1 || (echo [ERROR] Remote origin belum dikonfigurasi.& exit /b 1) set "HAS_CHANGES=" for /f "delims=" %%G in ('git status --porcelain') do set "HAS_CHANGES=1" if defined HAS_CHANGES ( - git status --short - set "MSG=" - set /p "MSG=Commit message [Handcrafted %MOD_VERSION%]: " - if not defined MSG set "MSG=Handcrafted %MOD_VERSION%" - git add -A || exit /b 1 - git commit -m "!MSG!" || exit /b 1 + echo. + echo Perubahan yang akan di-commit: + git status --short + echo. + set "COMMIT_MESSAGE=" + set /p "COMMIT_MESSAGE=Commit message [Handcrafted %MOD_VERSION%]: " + if not defined COMMIT_MESSAGE set "COMMIT_MESSAGE=Handcrafted %MOD_VERSION%" + git add -A + if errorlevel 1 exit /b 1 + git commit -m "!COMMIT_MESSAGE!" + if errorlevel 1 exit /b 1 ) else ( - echo [INFO] Working tree bersih. + echo [INFO] Working tree bersih. Tidak ada commit baru. ) -set "BRANCH=" -for /f "delims=" %%B in ('git branch --show-current') do set "BRANCH=%%B" -if not defined BRANCH (echo [ERROR] Branch aktif tidak ditemukan.& exit /b 1) -git push origin "!BRANCH!" -if errorlevel 1 (echo [ERROR] Push gagal.& exit /b 1) -echo [OK] Push selesai. +call :push_branch_with_retry +if errorlevel 1 ( + echo. + echo [ERROR] Push Git belum berhasil. + call :push_failure_menu + exit /b !ERRORLEVEL! +) +echo [OK] Push branch %CURRENT_BRANCH% selesai. exit /b 0 -:test +:push_failure_menu echo. -echo [TEST] Menjalankan Minecraft test client... -if exist "%CD%\gradlew.bat" ( - call "%CD%\gradlew.bat" runClient --console=plain -) else ( - echo [ERROR] gradlew.bat tidak ditemukan. - exit /b 1 +echo ============================================ +echo Push masih gagal +echo ============================================ +echo [1] Coba Push Git lagi +echo [2] Mod Testing +echo [3] Make Release +echo [4] Exit +choice /C 1234 /N /M "Pilih: " +if errorlevel 4 exit /b 1 +if errorlevel 3 ( + call :make_release + exit /b !ERRORLEVEL! +) +if errorlevel 2 ( + call :test_mod + exit /b !ERRORLEVEL! +) +if errorlevel 1 ( + call :push_branch_with_retry + if errorlevel 1 goto push_failure_menu + echo [OK] Push branch %CURRENT_BRANCH% selesai. + exit /b 0 ) -set "RC=%ERRORLEVEL%" -if not "%RC%"=="0" echo [WARN] Test client selesai dengan exit code %RC%. -exit /b 0 -:release +:push_branch_with_retry +set /a PUSH_ATTEMPT=1 +:push_branch_attempt +echo [INFO] Push branch attempt !PUSH_ATTEMPT!/3... +git push -u origin "!CURRENT_BRANCH!" +if not errorlevel 1 exit /b 0 +if !PUSH_ATTEMPT! LSS 3 ( + set /a PUSH_ATTEMPT+=1 + timeout /t 2 /nobreak >nul + goto push_branch_attempt +) +exit /b 1 + +:test_mod echo. -if not exist "%JAR_PATH%" ( - echo [ERROR] Release dibatalkan: JAR %MOD_VERSION% tidak ditemukan. - exit /b 1 -) -where git.exe >nul 2>&1 || (echo [ERROR] Git tidak ditemukan.& exit /b 1) -git rev-parse --is-inside-work-tree >nul 2>&1 || (echo [ERROR] Bukan Git repository.& exit /b 1) - -git rev-parse "%TAG%" >nul 2>&1 -if not errorlevel 1 ( - echo [INFO] Tag %TAG% sudah ada. Tidak membuat ulang. - exit /b 0 -) - -echo JAR : %JAR_PATH% -echo Tag : %TAG% -choice /C YN /N /M "Buat release tag %TAG%? [Y/N]: " -if errorlevel 2 exit /b 0 - -git tag -a "%TAG%" -m "Handcrafted v%MOD_VERSION% for Fabric %MINECRAFT_VERSION%" -if errorlevel 1 (echo [ERROR] Gagal membuat tag.& exit /b 1) - -git remote get-url origin >nul 2>&1 -if not errorlevel 1 ( - git push origin "%TAG%" - if errorlevel 1 ( - echo [WARN] Tag lokal dibuat, tetapi push tag gagal. +echo ============================================ +echo MOD TESTING +echo ============================================ +if not exist "%CD%\gradlew.bat" ( + echo [ERROR] gradlew.bat tidak ditemukan. exit /b 1 - ) ) -echo [OK] Release tag %TAG% selesai. -echo [INFO] JAR release: %JAR_PATH% +call "%CD%\gradlew.bat" runClient --console=plain +set "TEST_RC=%ERRORLEVEL%" +if not "%TEST_RC%"=="0" ( + echo [WARN] Test client selesai dengan exit code %TEST_RC%. +) else ( + echo [OK] Test client selesai. +) +exit /b 0 + +:make_release +call :refresh_properties +echo. +echo ============================================ +echo GITEA RELEASE +echo Minecraft : %MINECRAFT_VERSION% +echo Version : %MOD_VERSION% +echo Tag : %TAG% +echo Asset : %JAR_NAME% +echo Gitea : %GITEA_BASE_URL%/%GITEA_OWNER%/%GITEA_REPO% +echo ============================================ + +if not exist "%JAR_PATH%" ( + echo [ERROR] JAR release tidak ditemukan: + echo %JAR_PATH% + echo [INFO] Compile versi ini lebih dulu. + exit /b 1 +) +where git.exe >nul 2>&1 || ( + echo [ERROR] Git tidak ditemukan di PATH. + exit /b 1 +) +where curl.exe >nul 2>&1 || ( + echo [ERROR] curl.exe tidak ditemukan di PATH. + exit /b 1 +) +git rev-parse --is-inside-work-tree >nul 2>&1 || ( + echo [ERROR] Folder ini bukan Git repository. + exit /b 1 +) +git remote get-url origin >nul 2>&1 || ( + echo [ERROR] Remote origin belum dikonfigurasi. + exit /b 1 +) + +set "CURRENT_BRANCH=" +for /f "delims=" %%B in ('git branch --show-current') do set "CURRENT_BRANCH=%%B" +if not defined CURRENT_BRANCH ( + echo [ERROR] Branch aktif tidak ditemukan. + exit /b 1 +) + +REM Release harus merepresentasikan source saat ini. +set "HAS_CHANGES=" +for /f "delims=" %%G in ('git status --porcelain') do set "HAS_CHANGES=1" +if defined HAS_CHANGES ( + echo. + echo [WARN] Ada perubahan source yang belum di-commit: + git status --short + echo. + choice /C YN /N /M "Commit dan push sebelum release? [Y/N]: " + if errorlevel 2 ( + echo [INFO] Release dibatalkan agar tag tidak berbeda dari source build. + exit /b 0 + ) + set "COMMIT_MESSAGE=" + set /p "COMMIT_MESSAGE=Commit message [Prepare Handcrafted %TAG% release]: " + if not defined COMMIT_MESSAGE set "COMMIT_MESSAGE=Prepare Handcrafted %TAG% release" + git add -A + if errorlevel 1 exit /b 2 + git commit -m "!COMMIT_MESSAGE!" + if errorlevel 1 exit /b 2 +) + +REM Selalu pastikan branch sudah ada di remote sebelum tagging/release. +call :push_branch_with_retry +if errorlevel 1 ( + echo [ERROR] Push branch gagal 3x. Release belum dibuat. + call :release_push_failure_menu + exit /b !ERRORLEVEL! +) + +set "HEAD_COMMIT=" +for /f "delims=" %%H in ('git rev-parse HEAD') do set "HEAD_COMMIT=%%H" +set "TAG_COMMIT=" +for /f "delims=" %%T in ('git rev-list -n 1 "%TAG%" 2^>nul') do set "TAG_COMMIT=%%T" + +if defined TAG_COMMIT ( + if /I not "!TAG_COMMIT!"=="!HEAD_COMMIT!" ( + echo [ERROR] Tag %TAG% sudah ada tetapi menunjuk commit lain. + echo Tag : !TAG_COMMIT! + echo HEAD: !HEAD_COMMIT! + echo [INFO] Naikkan mod_version sebelum membuat release baru. + exit /b 2 + ) + echo [INFO] Tag lokal %TAG% sudah benar pada HEAD saat ini. +) else ( + echo [INFO] Membuat tag %TAG%... + git tag -a "%TAG%" -m "Handcrafted %TAG%" + if errorlevel 1 exit /b 2 +) + +git ls-remote --exit-code --tags origin "refs/tags/%TAG%" >nul 2>&1 +if errorlevel 1 ( + call :push_tag_with_retry + if errorlevel 1 ( + echo [ERROR] Push tag gagal. + exit /b 2 + ) +) else ( + echo [INFO] Tag %TAG% sudah ada di origin. +) + +echo. +choice /C YN /N /M "Buat Gitea Release %TAG% dan upload %JAR_NAME%? [Y/N]: " +if errorlevel 2 ( + echo [INFO] Gitea Release dilewati. Tag tetap tersimpan. + exit /b 0 +) + +if not defined GITEA_TOKEN ( + echo. + set /p "GITEA_TOKEN=Gitea Personal Access Token: " +) +if not defined GITEA_TOKEN ( + echo [ERROR] Token Gitea kosong. + exit /b 2 +) + +set "API_BASE=%GITEA_BASE_URL%/api/v1/repos/%GITEA_OWNER%/%GITEA_REPO%" +set "RELEASE_JSON=%TEMP%\handcrafted-release-%RANDOM%.json" +set "CREATE_JSON=%TEMP%\handcrafted-create-%RANDOM%.json" +set "ASSET_JSON=%TEMP%\handcrafted-asset-%RANDOM%.json" + +set "HTTP_CODE=" +for /f "delims=" %%H in ('curl.exe -sS -o "!RELEASE_JSON!" -w "%%{http_code}" -H "Authorization: token !GITEA_TOKEN!" "!API_BASE!/releases/tags/%TAG%"') do set "HTTP_CODE=%%H" + +if "!HTTP_CODE!"=="200" ( + echo [INFO] Gitea Release %TAG% sudah ada. Release tersebut akan digunakan. +) else if "!HTTP_CODE!"=="404" ( + >"!CREATE_JSON!" echo { + >>"!CREATE_JSON!" echo "tag_name": "%TAG%", + >>"!CREATE_JSON!" echo "target_commitish": "!CURRENT_BRANCH!", + >>"!CREATE_JSON!" echo "name": "Handcrafted %TAG% for Fabric %MINECRAFT_VERSION%", + >>"!CREATE_JSON!" echo "body": "Fabric port of Handcrafted for Minecraft %MINECRAFT_VERSION%.", + >>"!CREATE_JSON!" echo "draft": false, + >>"!CREATE_JSON!" echo "prerelease": %PRERELEASE% + >>"!CREATE_JSON!" echo } + + echo [INFO] Membuat Gitea Release %TAG%... + set "HTTP_CODE=" + for /f "delims=" %%H in ('curl.exe -sS -o "!RELEASE_JSON!" -w "%%{http_code}" -X POST -H "Authorization: token !GITEA_TOKEN!" -H "Content-Type: application/json" --data-binary "@!CREATE_JSON!" "!API_BASE!/releases"') do set "HTTP_CODE=%%H" + if not "!HTTP_CODE!"=="201" ( + echo [ERROR] Gitea gagal membuat release. HTTP !HTTP_CODE! + type "!RELEASE_JSON!" + call :cleanup_temp + exit /b 2 + ) +) else ( + echo [ERROR] Gagal memeriksa Gitea Release. HTTP !HTTP_CODE! + type "!RELEASE_JSON!" + call :cleanup_temp + exit /b 2 +) + +set "RELEASE_ID=" +for /f "delims=" %%I in ('powershell.exe -NoProfile -Command "$r=Get-Content -Raw -LiteralPath '!RELEASE_JSON!' ^| ConvertFrom-Json; $r.id"') do set "RELEASE_ID=%%I" +if not defined RELEASE_ID ( + echo [ERROR] Tidak dapat membaca Release ID dari Gitea. + type "!RELEASE_JSON!" + call :cleanup_temp + exit /b 2 +) + +REM Cek apakah asset dengan nama yang sama sudah ada. +set "ASSET_EXISTS=" +for /f "delims=" %%E in ('powershell.exe -NoProfile -Command "$r=Get-Content -Raw -LiteralPath '!RELEASE_JSON!' ^| ConvertFrom-Json; if($r.assets ^| Where-Object { $_.name -eq '%JAR_NAME%' }) { 'yes' }"') do set "ASSET_EXISTS=%%E" +if /I "!ASSET_EXISTS!"=="yes" ( + echo [INFO] Asset %JAR_NAME% sudah ada di release. Tidak diupload ulang. + call :cleanup_temp + echo [SUCCESS] Gitea Release %TAG% siap. + exit /b 0 +) + +echo [INFO] Release ID: !RELEASE_ID! +echo [INFO] Mengupload %JAR_NAME%... +set "ASSET_CODE=" +for /f "delims=" %%H in ('curl.exe -sS -o "!ASSET_JSON!" -w "%%{http_code}" -X POST -H "Authorization: token !GITEA_TOKEN!" -F "attachment=@%JAR_PATH%" "!API_BASE!/releases/!RELEASE_ID!/assets?name=%JAR_NAME%"') do set "ASSET_CODE=%%H" + +if "!ASSET_CODE!"=="201" ( + echo. + echo [SUCCESS] Release %TAG% berhasil dibuat dan JAR berhasil diupload. +) else if "!ASSET_CODE!"=="409" ( + echo [WARN] Asset %JAR_NAME% sudah ada di release. +) else ( + echo [ERROR] Upload JAR gagal. HTTP !ASSET_CODE! + type "!ASSET_JSON!" + call :cleanup_temp + exit /b 2 +) + +call :cleanup_temp +echo. +echo ============================================ +echo RELEASE SUCCESS +echo Tag : %TAG% +echo Asset : %JAR_NAME% +echo ============================================ +exit /b 0 + +:release_push_failure_menu +echo. +echo [1] Coba Push Git lagi +echo [2] Mod Testing +echo [3] Exit +choice /C 123 /N /M "Pilih: " +if errorlevel 3 exit /b 1 +if errorlevel 2 ( + call :test_mod + exit /b 1 +) +if errorlevel 1 ( + call :push_branch_with_retry + if errorlevel 1 goto release_push_failure_menu + echo [OK] Push berhasil. Jalankan Make Release lagi dari workflow. + exit /b 1 +) + +:push_tag_with_retry +set /a TAG_ATTEMPT=1 +:push_tag_attempt +echo [INFO] Push tag attempt !TAG_ATTEMPT!/3... +git push origin "%TAG%" +if not errorlevel 1 exit /b 0 +if !TAG_ATTEMPT! LSS 3 ( + set /a TAG_ATTEMPT+=1 + timeout /t 2 /nobreak >nul + goto push_tag_attempt +) +choice /C YN /N /M "Push tag gagal 3x. Coba 3x lagi? [Y/N]: " +if errorlevel 2 exit /b 1 +set /a TAG_ATTEMPT=1 +goto push_tag_attempt + +:cleanup_temp +if defined RELEASE_JSON del /q "!RELEASE_JSON!" >nul 2>&1 +if defined CREATE_JSON del /q "!CREATE_JSON!" >nul 2>&1 +if defined ASSET_JSON del /q "!ASSET_JSON!" >nul 2>&1 exit /b 0 diff --git a/workflow.sh b/workflow.sh index 4a83dfc..722b857 100644 --- a/workflow.sh +++ b/workflow.sh @@ -2,119 +2,304 @@ set -u cd "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" || exit 1 +# ============================================================ +# Handcrafted - Unified Workflow +# Compile + Git Push + Mod Testing + Gitea Release +# Linux / macOS +# ============================================================ + +GITEA_BASE_URL="${GITEA_BASE_URL:-https://git.darto.id}" +GITEA_OWNER="${GITEA_OWNER:-dartokloning}" +GITEA_REPO="${GITEA_REPO:-handcrafted}" + [[ -f gradle.properties ]] || { echo "[ERROR] gradle.properties tidak ditemukan."; exit 1; } get_prop() { sed -n "s/^$1=//p" gradle.properties | tail -n 1 | tr -d '\r'; } -refresh() { - MOD_VERSION="$(get_prop mod_version)"; MOD_VERSION="${MOD_VERSION:-unknown}" - MINECRAFT_VERSION="$(get_prop minecraft_version)"; MINECRAFT_VERSION="${MINECRAFT_VERSION:-26.2}" - ARCHIVES_BASE_NAME="$(get_prop archives_base_name)"; ARCHIVES_BASE_NAME="${ARCHIVES_BASE_NAME:-handcrafted}" - JAR_PATH="$PWD/build/libs/$ARCHIVES_BASE_NAME-$MOD_VERSION.jar" +refresh_properties() { + MOD_VERSION="$(get_prop mod_version)" + MINECRAFT_VERSION="$(get_prop minecraft_version)" + ARCHIVES_BASE_NAME="$(get_prop archives_base_name)" + [[ -n "$MOD_VERSION" ]] || { echo "[ERROR] mod_version tidak ditemukan."; return 1; } + MINECRAFT_VERSION="${MINECRAFT_VERSION:-26.2}" + ARCHIVES_BASE_NAME="${ARCHIVES_BASE_NAME:-handcrafted}" TAG="v$MOD_VERSION" + JAR_NAME="$ARCHIVES_BASE_NAME-$MOD_VERSION.jar" + JAR_PATH="$PWD/build/libs/$JAR_NAME" + PRERELEASE=false + [[ "$MOD_VERSION" =~ (alpha|beta|rc) ]] && PRERELEASE=true } compile_mod() { + refresh_properties || return 1 echo - echo "[COMPILE] Building $ARCHIVES_BASE_NAME $MOD_VERSION..." - if [[ -f ./compile.sh ]]; then - bash ./compile.sh --build-only || return 1 - elif [[ -f ./gradlew ]]; then - chmod +x ./gradlew 2>/dev/null || true - ./gradlew clean build --console=plain || return 1 - else - echo "[ERROR] compile.sh maupun gradlew tidak ditemukan." - return 1 - fi + echo "============================================" + echo " COMPILE" + echo " Handcrafted $MOD_VERSION / Minecraft $MINECRAFT_VERSION" + echo "============================================" + [[ -f ./gradlew ]] || { echo "[ERROR] gradlew tidak ditemukan."; return 1; } + chmod +x ./gradlew 2>/dev/null || true + ./gradlew clean build --console=plain || { echo "[ERROR] Compile gagal."; return 1; } + refresh_properties || return 1 [[ -f "$JAR_PATH" ]] || { echo "[ERROR] JAR tidak ditemukan: $JAR_PATH"; return 1; } echo "[OK] JAR: $JAR_PATH" } +current_branch() { + git branch --show-current +} + +push_branch_3x() { + local branch="$1" attempt=1 + while (( attempt <= 3 )); do + echo "[INFO] Push branch attempt $attempt/3..." + git push -u origin "$branch" && return 0 + ((attempt++)) + (( attempt <= 3 )) && sleep 2 + done + return 1 +} + +push_failure_menu() { + local branch="$1" + while true; do + echo + echo "============================================" + echo " Push masih gagal" + echo "============================================" + echo "[1] Coba Push Git lagi" + echo "[2] Mod Testing" + echo "[3] Make Release" + echo "[4] Exit" + read -r -p "Pilih: " x + case "$x" in + 1) push_branch_3x "$branch" && return 0 ;; + 2) test_mod; return 1 ;; + 3) make_release; return $? ;; + *) return 1 ;; + esac + done +} + push_git() { + refresh_properties || return 1 echo - echo "[GIT] Push..." + echo "============================================" + echo " GIT PUSH" + echo "============================================" command -v git >/dev/null 2>&1 || { echo "[ERROR] Git tidak ditemukan."; return 1; } git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { - echo "[ERROR] Folder belum menjadi Git repository." - echo "Jalankan: git init" + echo "[ERROR] Folder ini bukan Git repository." + echo "[INFO] Jika repository baru, jalankan: git init" return 1 } git remote get-url origin >/dev/null 2>&1 || { echo "[ERROR] Remote origin belum dikonfigurasi."; return 1; } + local branch + branch="$(current_branch)" + [[ -n "$branch" ]] || { echo "[ERROR] Branch aktif tidak ditemukan."; return 1; } + if [[ -n "$(git status --porcelain)" ]]; then + echo + echo "Perubahan yang akan di-commit:" git status --short + echo read -r -p "Commit message [Handcrafted $MOD_VERSION]: " msg msg="${msg:-Handcrafted $MOD_VERSION}" git add -A || return 1 git commit -m "$msg" || return 1 else - echo "[INFO] Working tree bersih." + echo "[INFO] Working tree bersih. Tidak ada commit baru." fi - branch="$(git branch --show-current)" - [[ -n "$branch" ]] || { echo "[ERROR] Branch aktif tidak ditemukan."; return 1; } - git push origin "$branch" || { echo "[ERROR] Push gagal."; return 1; } - echo "[OK] Push selesai." + if push_branch_3x "$branch"; then + echo "[OK] Push branch $branch selesai." + return 0 + fi + echo "[ERROR] Push Git belum berhasil." + push_failure_menu "$branch" } test_mod() { echo - echo "[TEST] Menjalankan Minecraft test client..." - if [[ -f ./gradlew ]]; then - chmod +x ./gradlew 2>/dev/null || true - ./gradlew runClient --console=plain - rc=$? - [[ $rc -eq 0 ]] || echo "[WARN] Test client selesai dengan exit code $rc." - else - echo "[ERROR] gradlew tidak ditemukan." - return 1 - fi + echo "============================================" + echo " MOD TESTING" + echo "============================================" + [[ -f ./gradlew ]] || { echo "[ERROR] gradlew tidak ditemukan."; return 1; } + chmod +x ./gradlew 2>/dev/null || true + ./gradlew runClient --console=plain + local rc=$? + [[ $rc -eq 0 ]] && echo "[OK] Test client selesai." || echo "[WARN] Test client selesai dengan exit code $rc." return 0 } -make_release() { - echo - [[ -f "$JAR_PATH" ]] || { echo "[ERROR] Release dibatalkan: JAR $MOD_VERSION tidak ditemukan."; return 1; } - command -v git >/dev/null 2>&1 || { echo "[ERROR] Git tidak ditemukan."; return 1; } - git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "[ERROR] Bukan Git repository."; return 1; } +push_tag_with_retry() { + local tag="$1" attempt + while true; do + attempt=1 + while (( attempt <= 3 )); do + echo "[INFO] Push tag attempt $attempt/3..." + git push origin "$tag" && return 0 + ((attempt++)) + (( attempt <= 3 )) && sleep 2 + done + read -r -p "Push tag gagal 3x. Coba 3x lagi? [Y/N]: " ans + [[ "$ans" =~ ^[Yy]$ ]] || return 1 + done +} - if git rev-parse "$TAG" >/dev/null 2>&1; then - echo "[INFO] Tag $TAG sudah ada. Tidak membuat ulang." +json_escape() { + python3 -c 'import json,sys; print(json.dumps(sys.stdin.read().rstrip("\n")))' +} + +make_release() { + refresh_properties || return 1 + echo + echo "============================================" + echo " GITEA RELEASE" + echo " Minecraft : $MINECRAFT_VERSION" + echo " Version : $MOD_VERSION" + echo " Tag : $TAG" + echo " Asset : $JAR_NAME" + echo " Gitea : $GITEA_BASE_URL/$GITEA_OWNER/$GITEA_REPO" + echo "============================================" + + [[ -f "$JAR_PATH" ]] || { echo "[ERROR] JAR release tidak ditemukan: $JAR_PATH"; return 1; } + command -v git >/dev/null 2>&1 || { echo "[ERROR] Git tidak ditemukan."; return 1; } + command -v curl >/dev/null 2>&1 || { echo "[ERROR] curl tidak ditemukan."; return 1; } + command -v python3 >/dev/null 2>&1 || { echo "[ERROR] python3 diperlukan untuk parsing JSON Gitea."; return 1; } + git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "[ERROR] Bukan Git repository."; return 1; } + git remote get-url origin >/dev/null 2>&1 || { echo "[ERROR] Remote origin belum dikonfigurasi."; return 1; } + + local branch + branch="$(current_branch)" + [[ -n "$branch" ]] || { echo "[ERROR] Branch aktif tidak ditemukan."; return 1; } + + if [[ -n "$(git status --porcelain)" ]]; then + echo "[WARN] Ada perubahan source yang belum di-commit:" + git status --short + read -r -p "Commit dan push sebelum release? [Y/N]: " ans + [[ "$ans" =~ ^[Yy]$ ]] || { echo "[INFO] Release dibatalkan."; return 0; } + read -r -p "Commit message [Prepare Handcrafted $TAG release]: " msg + msg="${msg:-Prepare Handcrafted $TAG release}" + git add -A || return 2 + git commit -m "$msg" || return 2 + fi + + if ! push_branch_3x "$branch"; then + echo "[ERROR] Push branch gagal 3x. Release belum dibuat." + while true; do + echo "[1] Coba Push Git lagi" + echo "[2] Mod Testing" + echo "[3] Exit" + read -r -p "Pilih: " x + case "$x" in + 1) push_branch_3x "$branch" && break ;; + 2) test_mod; return 1 ;; + *) return 1 ;; + esac + done + fi + + local head_commit tag_commit + head_commit="$(git rev-parse HEAD)" + tag_commit="$(git rev-list -n 1 "$TAG" 2>/dev/null || true)" + if [[ -n "$tag_commit" && "$tag_commit" != "$head_commit" ]]; then + echo "[ERROR] Tag $TAG sudah ada tetapi menunjuk commit lain." + echo "Tag : $tag_commit" + echo "HEAD: $head_commit" + echo "[INFO] Naikkan mod_version sebelum membuat release baru." + return 2 + elif [[ -z "$tag_commit" ]]; then + echo "[INFO] Membuat tag $TAG..." + git tag -a "$TAG" -m "Handcrafted $TAG" || return 2 + else + echo "[INFO] Tag lokal $TAG sudah benar pada HEAD saat ini." + fi + + if ! git ls-remote --exit-code --tags origin "refs/tags/$TAG" >/dev/null 2>&1; then + push_tag_with_retry "$TAG" || return 2 + else + echo "[INFO] Tag $TAG sudah ada di origin." + fi + + read -r -p "Buat Gitea Release $TAG dan upload $JAR_NAME? [Y/N]: " ans + [[ "$ans" =~ ^[Yy]$ ]] || { echo "[INFO] Gitea Release dilewati."; return 0; } + + if [[ -z "${GITEA_TOKEN:-}" ]]; then + read -r -s -p "Gitea Personal Access Token: " GITEA_TOKEN + echo + fi + [[ -n "${GITEA_TOKEN:-}" ]] || { echo "[ERROR] Token Gitea kosong."; return 2; } + + local api_base tmpdir release_json create_json asset_json http_code release_id asset_exists + api_base="$GITEA_BASE_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO" + tmpdir="$(mktemp -d)" + release_json="$tmpdir/release.json" + create_json="$tmpdir/create.json" + asset_json="$tmpdir/asset.json" + trap 'rm -rf "$tmpdir"' RETURN + + http_code="$(curl -sS -o "$release_json" -w "%{http_code}" -H "Authorization: token $GITEA_TOKEN" "$api_base/releases/tags/$TAG")" + if [[ "$http_code" == "404" ]]; then + python3 - "$create_json" "$TAG" "$branch" "$MINECRAFT_VERSION" "$PRERELEASE" <<'PY' +import json,sys +path,tag,branch,mc,pre=sys.argv[1:] +data={ + "tag_name":tag, + "target_commitish":branch, + "name":f"Handcrafted {tag} for Fabric {mc}", + "body":f"Fabric port of Handcrafted for Minecraft {mc}.", + "draft":False, + "prerelease":pre.lower()=="true", +} +with open(path,"w",encoding="utf-8") as f: json.dump(data,f) +PY + echo "[INFO] Membuat Gitea Release $TAG..." + http_code="$(curl -sS -o "$release_json" -w "%{http_code}" -X POST \ + -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \ + --data-binary "@$create_json" "$api_base/releases")" + [[ "$http_code" == "201" ]] || { + echo "[ERROR] Gitea gagal membuat release. HTTP $http_code" + cat "$release_json"; return 2; + } + elif [[ "$http_code" == "200" ]]; then + echo "[INFO] Gitea Release $TAG sudah ada. Release tersebut akan digunakan." + else + echo "[ERROR] Gagal memeriksa Gitea Release. HTTP $http_code" + cat "$release_json" + return 2 + fi + + release_id="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["id"])' "$release_json")" + asset_exists="$(python3 - "$release_json" "$JAR_NAME" <<'PY' +import json,sys +r=json.load(open(sys.argv[1])) +print("yes" if any(a.get("name")==sys.argv[2] for a in r.get("assets",[])) else "no") +PY +)" + if [[ "$asset_exists" == "yes" ]]; then + echo "[INFO] Asset $JAR_NAME sudah ada. Tidak diupload ulang." + echo "[SUCCESS] Gitea Release $TAG siap." return 0 fi - echo "JAR : $JAR_PATH" - echo "Tag : $TAG" - read -r -p "Buat release tag $TAG? [Y/N]: " ans - [[ "$ans" =~ ^[Yy]$ ]] || return 0 - - git tag -a "$TAG" -m "Handcrafted v$MOD_VERSION for Fabric $MINECRAFT_VERSION" || return 1 - if git remote get-url origin >/dev/null 2>&1; then - git push origin "$TAG" || { echo "[WARN] Tag lokal dibuat, tetapi push tag gagal."; return 1; } + echo "[INFO] Release ID: $release_id" + echo "[INFO] Mengupload $JAR_NAME..." + local asset_code + asset_code="$(curl -sS -o "$asset_json" -w "%{http_code}" -X POST \ + -H "Authorization: token $GITEA_TOKEN" \ + -F "attachment=@$JAR_PATH" \ + "$api_base/releases/$release_id/assets?name=$JAR_NAME")" + if [[ "$asset_code" == "201" ]]; then + echo "[SUCCESS] Release $TAG berhasil dibuat dan JAR berhasil diupload." + elif [[ "$asset_code" == "409" ]]; then + echo "[WARN] Asset $JAR_NAME sudah ada di release." + else + echo "[ERROR] Upload JAR gagal. HTTP $asset_code" + cat "$asset_json" + return 2 fi - echo "[OK] Release tag $TAG selesai." - echo "[INFO] JAR release: $JAR_PATH" -} - -menu4() { - echo - echo "============================================" - echo " Handcrafted Workflow" - echo " Minecraft : $MINECRAFT_VERSION" - echo " Version : $MOD_VERSION" - echo " JAR : ditemukan" - echo "============================================" - echo "[1] Push Git" - echo "[2] Mod Testing" - echo "[3] Make Release" - echo "[4] Exit" - read -r -p "Pilih: " x - case "$x" in - 1) push_git; after_push ;; - 2) test_mod; after_test ;; - 3) make_release; after_release ;; - *) exit 0 ;; - esac } after_push() { @@ -153,26 +338,48 @@ after_release() { done } -refresh -if [[ ! -f "$JAR_PATH" ]]; then - echo - echo "[INFO] Build $MOD_VERSION belum ditemukan. Compile otomatis..." - compile_mod || true -fi +main_menu() { + while true; do + refresh_properties || exit 1 + echo + echo "============================================" + echo " Handcrafted Workflow" + echo " Minecraft : $MINECRAFT_VERSION" + echo " Version : $MOD_VERSION" + echo " JAR : $JAR_NAME" + echo "============================================" + echo "[1] Push Git" + echo "[2] Mod Testing" + echo "[3] Make Release" + echo "[4] Exit" + read -r -p "Pilih: " x + case "$x" in + 1) push_git; after_push; return ;; + 2) test_mod; after_test; return ;; + 3) make_release; after_release; return ;; + *) exit 0 ;; + esac + done +} -refresh -if [[ -f "$JAR_PATH" ]]; then - menu4 +refresh_properties || exit 1 +if [[ ! -f "$JAR_PATH" ]]; then + echo "[INFO] JAR untuk versi $MOD_VERSION belum ditemukan. Compile otomatis..." + until compile_mod; do + echo + echo "[1] Coba Compile lagi" + echo "[2] Push Git" + echo "[3] Mod Testing" + echo "[4] Exit" + read -r -p "Pilih: " x + case "$x" in + 1) ;; + 2) push_git; after_push; exit 0 ;; + 3) test_mod; after_test; exit 0 ;; + *) exit 1 ;; + esac + done else - echo - echo "Build belum tersedia." - echo "[1] Push Git" - echo "[2] Mod Testing" - echo "[3] Exit" - read -r -p "Pilih: " x - case "$x" in - 1) push_git; after_push ;; - 2) test_mod; after_test ;; - *) exit 0 ;; - esac + echo "[INFO] JAR untuk versi $MOD_VERSION sudah ditemukan." fi +main_menu