386 lines
12 KiB
Bash
386 lines
12 KiB
Bash
#!/usr/bin/env bash
|
|
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_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 "============================================"
|
|
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 "============================================"
|
|
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 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. Tidak ada commit baru."
|
|
fi
|
|
|
|
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 "============================================"
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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 "[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
|
|
}
|
|
|
|
after_push() {
|
|
while true; do
|
|
echo; echo "[1] Mod Testing"; echo "[2] Make Release"; echo "[3] Exit"
|
|
read -r -p "Pilih: " x
|
|
case "$x" in
|
|
1) test_mod; after_test; return ;;
|
|
2) make_release; after_release; return ;;
|
|
*) exit 0 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
after_test() {
|
|
while true; do
|
|
echo; echo "[1] Push Git"; echo "[2] Make Release"; echo "[3] Exit"
|
|
read -r -p "Pilih: " x
|
|
case "$x" in
|
|
1) push_git; after_push; return ;;
|
|
2) make_release; after_release; return ;;
|
|
*) exit 0 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
after_release() {
|
|
while true; do
|
|
echo; echo "[1] Push Git"; echo "[2] Mod Testing"; echo "[3] Exit"
|
|
read -r -p "Pilih: " x
|
|
case "$x" in
|
|
1) push_git; after_push; return ;;
|
|
2) test_mod; after_test; return ;;
|
|
*) exit 0 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
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_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 "[INFO] JAR untuk versi $MOD_VERSION sudah ditemukan."
|
|
fi
|
|
main_menu
|