This repository was archived by the owner on Apr 9, 2026. It is now read-only.
Validate & Release #181
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Validate & Release | |
| # ╔══════════════════════════════════════════════════════════════╗ | |
| # ║ TAMAMEN MANUEL — otomatik tetikleyici YOK ║ | |
| # ║ Actions → "Run workflow" → istediğin seçenekleri ayarla ║ | |
| # ║ Job sırası: config → json → pack → functions → ║ | |
| # ║ structure → version → release ║ | |
| # ╚══════════════════════════════════════════════════════════════╝ | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| # ┌─────────────────────────────────────────────────────┐ | |
| # │ CHECKOUT & RUNNER │ | |
| # └─────────────────────────────────────────────────────┘ | |
| checkout_ref: | |
| description: 'Branch / tag / SHA (boş = varsayılan branch)' | |
| required: false | |
| default: '' | |
| runner: | |
| description: 'Runner' | |
| required: true | |
| type: choice | |
| default: 'ubuntu-latest' | |
| options: | |
| - ubuntu-latest | |
| - ubuntu-22.04 | |
| - ubuntu-24.04 | |
| fail_fast: | |
| description: '💥 fail-fast — bir job başarısız olunca sonrakiler iptal edilsin mi?' | |
| required: true | |
| type: boolean | |
| default: false | |
| # ┌─────────────────────────────────────────────────────┐ | |
| # │ DİZİN / DOSYA TANIMLARI │ | |
| # └─────────────────────────────────────────────────────┘ | |
| scan_dirs: | |
| description: '📂 Taranacak dizinler (boşlukla ayrılmış). Validation + ZIP için kullanılır.' | |
| required: true | |
| default: 'data _pre_1_21_4 compat_1_21_4 1_21_6' | |
| required_files: | |
| description: '📄 Zorunlu dosyalar (boşlukla ayrılmış). Örn: pack.mcmeta pack.png' | |
| required: true | |
| default: 'pack.mcmeta pack.png' | |
| required_dirs: | |
| description: '📁 Zorunlu dizinler (boşlukla ayrılmış).' | |
| required: true | |
| default: 'data _pre_1_21_4 compat_1_21_4 1_21_6' | |
| required_mcfunctions: | |
| description: '⚙️ Varlığı kontrol edilecek .mcfunction dosyaları (boşlukla ayrılmış).' | |
| required: true | |
| default: 'data/macro/function/load.mcfunction data/macro/function/tick.mcfunction' | |
| required_tag_jsons: | |
| description: '🏷️ Varlığı kontrol edilecek tag JSON dosyaları (boşlukla ayrılmış).' | |
| required: true | |
| default: 'data/minecraft/tags/function/load.json data/minecraft/tags/function/tick.json' | |
| # ┌─────────────────────────────────────────────────────┐ | |
| # │ VALIDATION TOGGLE │ | |
| # └─────────────────────────────────────────────────────┘ | |
| run_validate_json: | |
| description: '🔵 JSON Validation' | |
| required: true | |
| type: boolean | |
| default: false | |
| run_validate_pack: | |
| description: '🔵 pack.mcmeta Validation' | |
| required: true | |
| type: boolean | |
| default: false | |
| run_validate_functions: | |
| description: '🔵 Function Reference Integrity' | |
| required: true | |
| type: boolean | |
| default: false | |
| run_validate_structure: | |
| description: '🔵 File Structure Check' | |
| required: true | |
| type: boolean | |
| default: false | |
| run_validate_version: | |
| description: '🔵 Version Validation' | |
| required: true | |
| type: boolean | |
| default: false | |
| # ┌─────────────────────────────────────────────────────┐ | |
| # │ VALIDATION DAVRANIŞI │ | |
| # └─────────────────────────────────────────────────────┘ | |
| empty_mcfunction_action: | |
| description: 'Boş .mcfunction davranışı: warn | fail | skip' | |
| required: true | |
| type: choice | |
| default: 'warn' | |
| options: | |
| - warn | |
| - fail | |
| - skip | |
| strict_function_refs: | |
| description: '🔒 Strict function ref — eksik referans FAIL sayılsın' | |
| required: true | |
| type: boolean | |
| default: false | |
| strict_version_match: | |
| description: '🔒 Strict version — versiyon uyuşmazlığı FAIL (default: WARN)' | |
| required: true | |
| type: boolean | |
| default: false | |
| strict_changelog: | |
| description: '🔒 Strict changelog — CHANGELOG eksikse FAIL (default: WARN)' | |
| required: true | |
| type: boolean | |
| default: false | |
| # ┌─────────────────────────────────────────────────────┐ | |
| # │ RELEASE CONFIG │ | |
| # └─────────────────────────────────────────────────────┘ | |
| create_release: | |
| description: '🚀 GitHub Release oluştur?' | |
| required: true | |
| type: boolean | |
| default: false | |
| version: | |
| description: '🏷️ Release version (örn: v1.2.3) — Release için zorunlu' | |
| required: false | |
| default: '' | |
| pack_name: | |
| description: '📦 Pack adı — ZIP ve release başlığında kullanılır. Örn: macroEngine' | |
| required: true | |
| default: 'macroEngine' | |
| release_type: | |
| description: 'Release türü: normal | draft (taslak, yayınlanmaz) | prerelease (ön sürüm)' | |
| required: true | |
| type: choice | |
| default: 'normal' | |
| options: | |
| - normal | |
| - draft | |
| - prerelease | |
| release_generate_notes: | |
| description: '📋 Fallback: CHANGELOG bulunamazsa otomatik notlar üret' | |
| required: true | |
| type: boolean | |
| default: false | |
| zip_name_pattern: | |
| description: 'ZIP adı şablonu. {name} = pack adı, {version} = versiyon. Örn: {name}-{version}' | |
| required: true | |
| default: '{name}-{version}' | |
| zip_include_extra: | |
| description: | | |
| ➕ ZIP — ekstra dahil edilecek dosya/klasörler (boşlukla ayrılmış). | |
| scan_dirs + required_files zaten otomatik dahil edilir. | |
| Örn: docs/ README.md LICENSE | |
| required: false | |
| default: '' | |
| zip_exclude_patterns: | |
| description: | | |
| ➖ ZIP — hariç tutulacak glob desenleri (boşlukla ayrılmış). | |
| Örn: "*.log *.tmp *.bak .git" | |
| required: false | |
| default: '' | |
| concurrency: | |
| group: validate-release-${{ github.run_id }} | |
| cancel-in-progress: false | |
| # ────────────────────────────────────────────────────────────── | |
| # JOBS — sıralı zincir, tek seferde 1 runner | |
| # ────────────────────────────────────────────────────────────── | |
| jobs: | |
| # ───────────────────────────────────────────── | |
| # 0. Config Summary | |
| # ───────────────────────────────────────────── | |
| config-summary: | |
| name: "⚙️ Config Summary" | |
| runs-on: ${{ inputs.runner }} | |
| steps: | |
| - name: Print resolved config | |
| run: | | |
| echo "╔═══════════════════════════════════════════════════╗" | |
| echo "║ WORKFLOW CONFIG ║" | |
| echo "╠═══════════════════════════════════════════════════╣" | |
| echo " runner : ${{ inputs.runner }}" | |
| echo " checkout_ref : '${{ inputs.checkout_ref }}'" | |
| echo " fail_fast : ${{ inputs.fail_fast }}" | |
| echo " ── Dizinler & Dosyalar ──────────────────────────" | |
| echo " scan_dirs : ${{ inputs.scan_dirs }}" | |
| echo " required_files : ${{ inputs.required_files }}" | |
| echo " required_dirs : ${{ inputs.required_dirs }}" | |
| echo " required_mcfunctions : ${{ inputs.required_mcfunctions }}" | |
| echo " required_tag_jsons : ${{ inputs.required_tag_jsons }}" | |
| echo " ── Validation ───────────────────────────────────" | |
| echo " validate_json : ${{ inputs.run_validate_json }}" | |
| echo " validate_pack : ${{ inputs.run_validate_pack }}" | |
| echo " validate_functions : ${{ inputs.run_validate_functions }}" | |
| echo " validate_structure : ${{ inputs.run_validate_structure }}" | |
| echo " validate_version : ${{ inputs.run_validate_version }}" | |
| echo " empty_mcfunc_action : ${{ inputs.empty_mcfunction_action }}" | |
| echo " strict_func_refs : ${{ inputs.strict_function_refs }}" | |
| echo " strict_version : ${{ inputs.strict_version_match }}" | |
| echo " strict_changelog : ${{ inputs.strict_changelog }}" | |
| echo " ── Release ──────────────────────────────────────" | |
| echo " create_release : ${{ inputs.create_release }}" | |
| echo " version : '${{ inputs.version }}'" | |
| echo " pack_name : ${{ inputs.pack_name }}" | |
| echo " release_type : ${{ inputs.release_type }}" | |
| echo " release_generate_notes: ${{ inputs.release_generate_notes }}" | |
| echo " zip_name_pattern : ${{ inputs.zip_name_pattern }}" | |
| echo " zip_include_extra : '${{ inputs.zip_include_extra }}'" | |
| echo " zip_exclude_patterns : '${{ inputs.zip_exclude_patterns }}'" | |
| echo "╚═══════════════════════════════════════════════════╝" | |
| # ───────────────────────────────────────────── | |
| # 1. JSON Validation | |
| # ───────────────────────────────────────────── | |
| validate-json: | |
| name: "🔵 Validate JSON" | |
| runs-on: ${{ inputs.runner }} | |
| needs: config-summary | |
| if: inputs.run_validate_json == true | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || github.ref }} | |
| - name: Validate JSON files in scan_dirs | |
| run: | | |
| FAILED=0 | |
| for d in ${{ inputs.scan_dirs }}; do | |
| while IFS= read -r f; do | |
| if jq . "$f" > /dev/null 2>&1; then | |
| echo "OK: $f" | |
| else | |
| echo "FAIL: $f" | |
| jq . "$f" 2>&1 || true | |
| FAILED=1 | |
| fi | |
| done < <(find "$d" -name "*.json" 2>/dev/null) | |
| done | |
| if jq . pack.mcmeta > /dev/null 2>&1; then | |
| echo "OK: pack.mcmeta" | |
| else | |
| echo "FAIL: pack.mcmeta" | |
| jq . pack.mcmeta 2>&1 || true | |
| FAILED=1 | |
| fi | |
| [ $FAILED -ne 0 ] && { echo "❌ FAILED: Geçersiz JSON dosyaları var."; exit 1; } || echo "✅ PASSED" | |
| # ───────────────────────────────────────────── | |
| # 2. pack.mcmeta Structural Validation | |
| # ───────────────────────────────────────────── | |
| validate-pack: | |
| name: "🔵 Validate pack.mcmeta" | |
| runs-on: ${{ inputs.runner }} | |
| needs: validate-json | |
| if: | | |
| always() && | |
| inputs.run_validate_pack == true && | |
| (needs.validate-json.result == 'success' || needs.validate-json.result == 'skipped') && | |
| (inputs.fail_fast == false || needs.validate-json.result != 'failure') | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || github.ref }} | |
| - name: Check pack_format and description | |
| run: | | |
| FAILED=0 | |
| PF=$(jq '.pack.pack_format // empty' pack.mcmeta) | |
| [ -n "$PF" ] && echo "OK: pack_format = $PF" || { echo "FAIL: pack_format eksik"; FAILED=1; } | |
| DESC=$(jq '.pack.description // empty' pack.mcmeta) | |
| [ -n "$DESC" ] && echo "OK: description mevcut" || { echo "FAIL: description eksik"; FAILED=1; } | |
| SF=$(jq '.pack.supported_formats // empty' pack.mcmeta) | |
| [ -n "$SF" ] && echo "OK: supported_formats = $SF" || echo "INFO: supported_formats tanımlı değil" | |
| [ $FAILED -ne 0 ] && { echo "❌ FAILED"; exit 1; } || echo "✅ PASSED" | |
| - name: Check overlay directories | |
| run: | | |
| FAILED=0 | |
| while IFS= read -r dir; do | |
| [ -z "$dir" ] && continue | |
| [ -d "$dir" ] && echo "OK: $dir/" || { echo "FAIL: Overlay dizini eksik: $dir/"; FAILED=1; } | |
| done < <(jq -r '.overlays.entries[]?.directory // empty' pack.mcmeta 2>/dev/null) | |
| [ $FAILED -ne 0 ] && { echo "❌ FAILED"; exit 1; } || echo "✅ PASSED" | |
| # ───────────────────────────────────────────── | |
| # 3. Function Reference Integrity | |
| # ───────────────────────────────────────────── | |
| validate-functions: | |
| name: "🔵 Validate Function References" | |
| runs-on: ${{ inputs.runner }} | |
| needs: validate-pack | |
| if: | | |
| always() && | |
| inputs.run_validate_functions == true && | |
| (needs.validate-pack.result == 'success' || needs.validate-pack.result == 'skipped') && | |
| (inputs.fail_fast == false || (needs.validate-json.result != 'failure' && needs.validate-pack.result != 'failure')) | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || github.ref }} | |
| - name: Check function tag references | |
| run: | | |
| FAILED=0 | |
| STRICT="${{ inputs.strict_function_refs }}" | |
| while IFS= read -r tag_file; do | |
| while IFS= read -r ref; do | |
| [ -z "$ref" ] && continue | |
| [[ "$ref" == "#"* ]] && continue | |
| [[ "$ref" != *:* ]] && continue | |
| ns="${ref%%:*}"; path="${ref#*:}" | |
| found=0 | |
| for base in . ${{ inputs.scan_dirs }}; do | |
| [ -f "$base/data/$ns/function/$path.mcfunction" ] && found=1 && break | |
| done | |
| if [ $found -eq 1 ]; then | |
| echo "OK: $ref" | |
| else | |
| if [ "$STRICT" == "true" ]; then | |
| echo "FAIL: $tag_file → $ref bulunamadı" | |
| FAILED=1 | |
| else | |
| echo "WARN: $tag_file → $ref bulunamadı" | |
| fi | |
| fi | |
| done < <(jq -r '.values[]? | if type == "object" then .id else . end' "$tag_file" 2>/dev/null) | |
| done < <( | |
| for d in ${{ inputs.scan_dirs }}; do | |
| find "$d" -path "*/tags/function/*.json" 2>/dev/null | |
| done | |
| ) | |
| [ $FAILED -ne 0 ] && { echo "❌ FAILED"; exit 1; } || echo "✅ PASSED" | |
| - name: Check for empty .mcfunction files | |
| run: | | |
| ACTION="${{ inputs.empty_mcfunction_action }}" | |
| [ "$ACTION" == "skip" ] && { echo "INFO: Boş dosya kontrolü atlandı (skip)"; exit 0; } | |
| EMPTY=0 | |
| while IFS= read -r f; do | |
| content=$(grep -v '^[[:space:]]*#' "$f" | grep -v '^[[:space:]]*$' || true) | |
| [ -z "$content" ] && { echo "$(echo $ACTION | tr a-z A-Z): Boş: $f"; EMPTY=$((EMPTY+1)); } | |
| done < <( | |
| for d in ${{ inputs.scan_dirs }}; do | |
| find "$d" -name "*.mcfunction" 2>/dev/null | |
| done | |
| ) | |
| if [ $EMPTY -gt 0 ]; then | |
| echo "$EMPTY boş .mcfunction dosyası bulundu" | |
| [ "$ACTION" == "fail" ] && { echo "❌ FAILED"; exit 1; } || echo "⚠️ WARNED (intentional olabilir)" | |
| else | |
| echo "✅ PASSED: Boş .mcfunction yok" | |
| fi | |
| # ───────────────────────────────────────────── | |
| # 4. File Structure Check | |
| # ───────────────────────────────────────────── | |
| validate-structure: | |
| name: "🔵 Validate File Structure" | |
| runs-on: ${{ inputs.runner }} | |
| needs: validate-functions | |
| if: | | |
| always() && | |
| inputs.run_validate_structure == true && | |
| (needs.validate-functions.result == 'success' || needs.validate-functions.result == 'skipped') && | |
| (inputs.fail_fast == false || (needs.validate-json.result != 'failure' && needs.validate-pack.result != 'failure' && needs.validate-functions.result != 'failure')) | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || github.ref }} | |
| - name: Check required files | |
| run: | | |
| FAILED=0 | |
| for f in ${{ inputs.required_files }}; do | |
| [ -f "$f" ] && echo "OK: $f" || { echo "FAIL: $f eksik"; FAILED=1; } | |
| done | |
| [ $FAILED -ne 0 ] && { echo "❌ FAILED"; exit 1; } || echo "✅ PASSED" | |
| - name: Check required directories | |
| run: | | |
| FAILED=0 | |
| for d in ${{ inputs.required_dirs }}; do | |
| [ -d "$d" ] && echo "OK: $d/ ($(find "$d" -type f | wc -l) dosya)" \ | |
| || { echo "FAIL: $d/ eksik"; FAILED=1; } | |
| done | |
| [ $FAILED -ne 0 ] && { echo "❌ FAILED"; exit 1; } || echo "✅ PASSED" | |
| - name: Check required .mcfunction files | |
| run: | | |
| FAILED=0 | |
| for fn in ${{ inputs.required_mcfunctions }}; do | |
| [ -f "$fn" ] && echo "OK: $fn" || { echo "FAIL: $fn eksik"; FAILED=1; } | |
| done | |
| [ $FAILED -ne 0 ] && { echo "❌ FAILED"; exit 1; } || echo "✅ PASSED" | |
| - name: Check required tag JSON files | |
| run: | | |
| FAILED=0 | |
| for fn in ${{ inputs.required_tag_jsons }}; do | |
| [ -f "$fn" ] && echo "OK: $fn" || { echo "FAIL: $fn eksik"; FAILED=1; } | |
| done | |
| [ $FAILED -ne 0 ] && { echo "❌ FAILED"; exit 1; } || echo "✅ PASSED" | |
| # ───────────────────────────────────────────── | |
| # 5. Version Validation | |
| # ───────────────────────────────────────────── | |
| validate-version: | |
| name: "🔵 Validate Version" | |
| runs-on: ${{ inputs.runner }} | |
| needs: validate-structure | |
| if: | | |
| always() && | |
| inputs.run_validate_version == true && | |
| (needs.validate-structure.result == 'success' || needs.validate-structure.result == 'skipped') && | |
| (inputs.fail_fast == false || (needs.validate-json.result != 'failure' && needs.validate-pack.result != 'failure' && needs.validate-functions.result != 'failure' && needs.validate-structure.result != 'failure')) | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || github.ref }} | |
| - name: Read version from pack.mcmeta | |
| id: mcmeta_ver | |
| run: | | |
| # BUG FIX: Daha geniş versiyon deseni — v1.2.3, test1, her string eşleşir | |
| RAW=$(jq -r '.pack.description // ""' pack.mcmeta) | |
| # Önce semver dene (v1.2.3) | |
| VER=$(echo "$RAW" | grep -oP 'v\d+\.\d+\.\d+[\w.-]*' | head -1 || true) | |
| # Semver bulunamazsa description'dan herhangi bir versiyon benzeri string al | |
| if [ -z "$VER" ]; then | |
| VER=$(echo "$RAW" | grep -oP '\bv?[\w][\w.-]*\d[\w.-]*' | head -1 || true) | |
| fi | |
| if [ -n "$VER" ]; then | |
| echo "OK: pack.mcmeta versiyonu: $VER" | |
| echo "version=$VER" >> $GITHUB_OUTPUT | |
| else | |
| echo "WARN: pack.mcmeta içinde versiyon deseni bulunamadı (description: '$RAW')" | |
| echo "version=" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Match version with workflow input | |
| if: inputs.version != '' | |
| run: | | |
| INPUT_TAG="${{ inputs.version }}" | |
| META_VER="${{ steps.mcmeta_ver.outputs.version }}" | |
| STRICT="${{ inputs.strict_version_match }}" | |
| if [ -z "$META_VER" ]; then | |
| MSG="pack.mcmeta içinde versiyon bulunamadı — '$INPUT_TAG' ile karşılaştırılamadı" | |
| elif [[ "$META_VER" == "$INPUT_TAG" ]]; then | |
| echo "✅ PASSED: $INPUT_TAG — pack.mcmeta ile eşleşiyor"; exit 0 | |
| else | |
| MSG="Uyuşmazlık — input: '$INPUT_TAG' | pack.mcmeta: '$META_VER'" | |
| fi | |
| [ "$STRICT" == "true" ] && { echo "❌ FAILED: $MSG"; exit 1; } || echo "⚠️ WARN: $MSG" | |
| - name: Check CHANGELOG | |
| run: | | |
| TAG="${{ inputs.version }}" | |
| STRICT="${{ inputs.strict_changelog }}" | |
| if [ ! -f "docs/CHANGELOG.md" ]; then | |
| MSG="docs/CHANGELOG.md bulunamadı" | |
| [ "$STRICT" == "true" ] && { echo "❌ FAILED: $MSG"; exit 1; } || { echo "⚠️ WARN: $MSG"; exit 0; } | |
| fi | |
| [ -z "$TAG" ] && { echo "INFO: Versiyon girilmedi, CHANGELOG kontrolü atlandı"; exit 0; } | |
| if grep -q "$TAG" docs/CHANGELOG.md; then | |
| echo "✅ OK: $TAG CHANGELOG içinde mevcut" | |
| else | |
| MSG="$TAG CHANGELOG içinde bulunamadı" | |
| [ "$STRICT" == "true" ] && { echo "❌ FAILED: $MSG"; exit 1; } || echo "⚠️ WARN: $MSG" | |
| fi | |
| # ───────────────────────────────────────────── | |
| # 6. Package & Release | |
| # ───────────────────────────────────────────── | |
| release: | |
| name: "🚀 Package & Release" | |
| runs-on: ${{ inputs.runner }} | |
| needs: validate-version | |
| if: | | |
| always() && | |
| inputs.create_release == true && | |
| (needs.validate-version.result == 'success' || needs.validate-version.result == 'skipped') && | |
| needs.validate-json.result != 'failure' && | |
| needs.validate-pack.result != 'failure' && | |
| needs.validate-functions.result != 'failure' && | |
| needs.validate-structure.result != 'failure' && | |
| needs.validate-version.result != 'failure' | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || github.ref }} | |
| - name: Verify version is provided | |
| run: | | |
| [ -z "${{ inputs.version }}" ] \ | |
| && { echo "❌ FAIL: Release için 'version' alanı zorunlu."; exit 1; } | |
| echo "✅ Release version = ${{ inputs.version }}" | |
| - name: Create git tag | |
| # Tag zaten varsa atla, yoksa oluştur ve push et. | |
| # Push başarısız olursa FAIL — release tag olmadan çalışamaz. | |
| run: | | |
| TAG="${{ inputs.version }}" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| # Tag remote'da zaten var mı? | |
| if git ls-remote --tags origin "refs/tags/$TAG" | grep -q "$TAG"; then | |
| echo "⚠️ WARN: Tag '$TAG' remote'da zaten mevcut, atlanıyor" | |
| exit 0 | |
| fi | |
| # Local tag oluştur (zaten varsa sorun değil) | |
| git tag "$TAG" 2>/dev/null || echo "⚠️ WARN: Local tag '$TAG' zaten var" | |
| # Remote'a push et — başarısız olursa FAIL | |
| if git push origin "$TAG"; then | |
| echo "✅ Tag '$TAG' remote'a push edildi" | |
| else | |
| echo "❌ FAILED: Tag '$TAG' push edilemedi. Settings → Actions → General → Workflow permissions → 'Read and write permissions' olduğundan emin ol." | |
| exit 1 | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build datapack ZIP | |
| id: build | |
| run: | | |
| TAG="${{ inputs.version }}" | |
| PACK="${{ inputs.pack_name }}" | |
| PATTERN="${{ inputs.zip_name_pattern }}" | |
| # Şablon yer tutucularını çöz | |
| BASENAME="${PATTERN//\{name\}/$PACK}" | |
| BASENAME="${BASENAME//\{version\}/$TAG}" | |
| ZIP="${BASENAME}.zip" | |
| echo "── ZIP İçeriği ──────────────────────────────" | |
| PATHS=() | |
| # scan_dirs | |
| for d in ${{ inputs.scan_dirs }}; do | |
| if [ -e "$d" ]; then | |
| PATHS+=("$d") | |
| echo " + $d" | |
| else | |
| echo " ⚠️ bulunamadı, atlandı: $d" | |
| fi | |
| done | |
| # required_files | |
| for f in ${{ inputs.required_files }}; do | |
| if [ -f "$f" ]; then | |
| PATHS+=("$f") | |
| echo " + $f" | |
| else | |
| echo " ⚠️ bulunamadı, atlandı: $f" | |
| fi | |
| done | |
| # zip_include_extra — ekstra dahil edilecekler | |
| EXTRA="${{ inputs.zip_include_extra }}" | |
| if [ -n "$EXTRA" ]; then | |
| for p in $EXTRA; do | |
| if [ -e "$p" ]; then | |
| PATHS+=("$p") | |
| echo " + (ekstra) $p" | |
| else | |
| echo " ⚠️ ekstra yol bulunamadı, atlandı: $p" | |
| fi | |
| done | |
| fi | |
| echo "────────────────────────────────────────────" | |
| # BUG FIX: PATHS boşsa ZIP oluşturulamaz, hata ver | |
| if [ ${#PATHS[@]} -eq 0 ]; then | |
| echo "❌ FAILED: ZIP'e eklenecek dosya/dizin bulunamadı!" | |
| exit 1 | |
| fi | |
| zip -r "$ZIP" "${PATHS[@]}" | |
| # zip_exclude_patterns — hariç tutulacaklar | |
| EXCL="${{ inputs.zip_exclude_patterns }}" | |
| if [ -n "$EXCL" ]; then | |
| echo "── Hariç tutulanlar ─────────────────────────" | |
| for pat in $EXCL; do | |
| zip -d "$ZIP" "$pat" 2>/dev/null \ | |
| && echo " - $pat kaldırıldı" \ | |
| || echo " ~ $pat eşleşmedi, atlandı" | |
| done | |
| fi | |
| SIZE=$(du -sh "$ZIP" | cut -f1) | |
| echo "✅ $ZIP oluşturuldu ($SIZE)" | |
| echo "zip_name=$ZIP" >> $GITHUB_OUTPUT | |
| - name: Create GitHub Release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| DRAFT_FLAG="" | |
| PRERELEASE_FLAG="" | |
| [ "${{ inputs.release_type }}" == "draft" ] && DRAFT_FLAG="--draft" | |
| [ "${{ inputs.release_type }}" == "prerelease" ] && PRERELEASE_FLAG="--prerelease" | |
| # Extract release notes from CHANGELOG.md for this version tag | |
| TAG="${{ inputs.version }}" | |
| NOTES="" | |
| if [ -f "docs/CHANGELOG.md" ] && [ -n "$TAG" ]; then | |
| # Extract section between this version header and the next ## header | |
| NOTES=$(awk "/^## ${TAG}[[:space:]]/"',/^## v/{if(found) exit; found=1; next} found{print}' docs/CHANGELOG.md | head -200) | |
| fi | |
| if [ -n "$NOTES" ]; then | |
| NOTES_FILE=$(mktemp) | |
| printf '%s' "$NOTES" > "$NOTES_FILE" | |
| NOTES_ARG="--notes-file $NOTES_FILE" | |
| else | |
| NOTES_ARG="--generate-notes" | |
| fi | |
| gh release create "$TAG" \ | |
| "${{ steps.build.outputs.zip_name }}" \ | |
| --title "${{ inputs.pack_name }} $TAG" \ | |
| $DRAFT_FLAG \ | |
| $PRERELEASE_FLAG \ | |
| $NOTES_ARG |