feat: Support for MC 26.1 #1373
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: Build and Release | |
| on: | |
| push: | |
| branches: | |
| - root | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version (without "v" prefix)' | |
| required: true | |
| type: string | |
| bypass-test: | |
| description: 'Disable test' | |
| default: false | |
| required: false | |
| type: boolean | |
| bypass-mod-publish: | |
| description: 'Disable publishing the mods to mod hosts (Modrinth, CurseForge)' | |
| default: false | |
| required: false | |
| type: boolean | |
| jobs: | |
| setup: | |
| name: Setup | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.matrix.outputs.matrix }} | |
| changelog: ${{ steps.changelog.outputs.changelog }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup matrix | |
| id: matrix | |
| run: echo "matrix=$(jq -cr . ./versions.json)" >> $GITHUB_OUTPUT | |
| - name: Setup CHANGELOG parser | |
| uses: taiki-e/install-action@parse-changelog | |
| - name: Retrieve changelog | |
| if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' | |
| id: changelog | |
| run: | | |
| # extended SemVer (major.minor.patch.hotfix) | |
| VERSION_FORMAT='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))?(-[0-9A-Za-z\.-]+)?(\+[0-9A-Za-z\.-]+)?$|^Unreleased$' | |
| CHANGELOG="$(parse-changelog CHANGELOG.md ${{ github.event.inputs.version == '' && 'INVALID' || github.event.inputs.version }} --version-format $VERSION_FORMAT || parse-changelog CHANGELOG.md Unreleased --version-format $VERSION_FORMAT || echo "")" | |
| [ "$CHANGELOG" = "" ] && exit 1 | |
| { | |
| echo "changelog<<END_OF_FILE" | |
| echo "$CHANGELOG" | |
| echo "" | |
| echo "END_OF_FILE" | |
| } >> $GITHUB_OUTPUT 2> /dev/null | |
| # To reduce api request, so we don't hit rate-limit | |
| - name: Retrieve JSON | |
| run: | | |
| curl -Ls -o "headlessmc.json" "https://api.github.com/repos/3arthqu4ke/headlessmc/releases/tags/2.7.1" --header "Authorization: ${{ secrets.GITHUB_TOKEN }}" | |
| curl -Ls -o "mc-runtime-test.json" "https://api.github.com/repos/null2264/mc-runtime-test/releases/tags/5.2.5" --header "Authorization: ${{ secrets.GITHUB_TOKEN }}" | |
| - name: Upload jar files | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: runtime-test-kit | |
| path: | | |
| headlessmc.json | |
| mc-runtime-test.json | |
| if-no-files-found: error | |
| retention-days: 1 | |
| build: | |
| name: Build | |
| needs: setup | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false # Don't cancel if one failed | |
| matrix: ${{ fromJson(needs.setup.outputs.matrix) }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| # - name: Cache build | |
| # if: github.event.repository != null && github.ref_name == github.event.repository.default_branch | |
| # uses: actions/cache@v4 | |
| # with: | |
| # path: cobblegen/build | |
| # key: build-${{ hashFiles(format('{0}/[a-z]**', 'cobblegen/build'), 'mclib/**') }}-${{ matrix.mc }}-${{ matrix.loader }} | |
| - name: Setup Gradle | |
| uses: null2264/actions/gradle-java-setup@363cb9cf3d66bd9c72ed6860142c6b2c121d7e94 | |
| with: | |
| distro: temurin | |
| java: | | |
| 8 | |
| 17 | |
| 21 | |
| 25 | |
| gradle-no-cache-if: true | |
| - name: Setup properties | |
| run: | | |
| echo "org.gradle.java.installations.fromEnv=JAVA_HOME,JAVA_HOME_8_X64,JAVA_HOME_17_X64,JAVA_HOME_21_X64" >> gradle.properties | |
| - name: Build with Gradle | |
| run: | | |
| # Retry 5 times because TerraformersMC's Maven keep having a stroke | |
| # and there's no way to workaround it through Gradle as there are no | |
| # public API for it. So we just need to deal with it I guess. | |
| # | |
| # REF: https://discuss.gradle.org/t/how-to-deal-with-network-flakiness-impacting-gradle-builds/25705/3 | |
| # REF: https://github.com/gradle/gradle/issues/4629 | |
| # REF: https://github.com/gradle/gradle/issues/2779 | |
| tries=1 | |
| c="0" | |
| while [ $tries -le 5 ]; | |
| do | |
| ./gradlew build -PmcVer="${{ matrix.mc }}" -Pnull2264.platform="${{ matrix.loader }}" && exit 0 | |
| c="$?" | |
| echo "Try $tries failed. (code:$c)" | |
| sleep 5s | |
| tries=$((tries+1)) | |
| done | |
| [ "$c" = "0" ] || exit 1 | |
| env: | |
| VERSION: ${{ github.event.inputs.version == '' && '0.0.0' || github.event.inputs.version }} | |
| - name: Archive build results | |
| run: tar -I zstd -cf build.tar.zst cobblegen/build/libs/* | |
| - name: Upload build folder | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-artifacts-mc${{ matrix.mc }}-${{ matrix.loader }} | |
| path: build.tar.zst | |
| if-no-files-found: error | |
| retention-days: 3 | |
| - name: Upload jar files | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: jar-mc${{ matrix.mc }}-${{ matrix.loader }} | |
| path: cobblegen/build/libs/* | |
| if-no-files-found: error | |
| retention-days: 3 | |
| - name: GameTest with Gradle | |
| if: github.event.inputs.bypass-test != 'true' && matrix.gradleGameTest | |
| run: | | |
| echo "# GameTest results" >> $GITHUB_STEP_SUMMARY; | |
| echo "<table>" >> $GITHUB_STEP_SUMMARY; | |
| echo "<tr>" >> $GITHUB_STEP_SUMMARY; | |
| echo "<th>Status</th>" >> $GITHUB_STEP_SUMMARY; | |
| echo "</tr>" >> $GITHUB_STEP_SUMMARY; | |
| timeout 20m ./gradlew runGametest -PmcVer="${{ matrix.mc }}" -Pnull2264.platform="${{ matrix.loader }}" && ( | |
| echo "<tr>" >> $GITHUB_STEP_SUMMARY; | |
| echo "<td>🟩 Complete</td>" >> $GITHUB_STEP_SUMMARY; | |
| echo "</tr>" >> $GITHUB_STEP_SUMMARY; | |
| ) || ( | |
| EXIT_CODE="$?" | |
| echo "<tr>" >> $GITHUB_STEP_SUMMARY; | |
| STATUS="Unknown error ($EXIT_CODE)"; | |
| case "$EXIT_CODE" in | |
| "-1") | |
| STATUS="🟥 Test failed" | |
| ;; | |
| "125" | "124") | |
| STATUS="🟨 Timed out" | |
| ;; | |
| "255" | "1") | |
| STATUS="🟥 Crashed" | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| echo "<td>$STATUS</td>" >> $GITHUB_STEP_SUMMARY; | |
| echo "</tr>" >> $GITHUB_STEP_SUMMARY; | |
| case "$EXIT_CODE" in | |
| "255" | "1") | |
| echo "</table>" >> $GITHUB_STEP_SUMMARY | |
| exit $EXIT_CODE | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| ) | |
| env: | |
| VERSION: ${{ github.event.inputs.version == '' && '0.0.0' || github.event.inputs.version }} | |
| - name: Download build artifact | |
| if: github.event.inputs.bypass-test != 'true' | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: runtime-test-kit | |
| - name: Setup HeadlessMC | |
| if: github.event.inputs.bypass-test != 'true' | |
| id: setup-headlessmc | |
| run: | | |
| mkdir -p HeadlessMC run/test-${{ matrix.mc }}-${{ matrix.loader }}/mods run/test-${{ matrix.mc }}-${{ matrix.loader }}/config | |
| cat <<EOF >> HeadlessMC/config.properties | |
| hmc.java.versions=$JAVA_HOME_${{ matrix.java }}_X64/bin/java | |
| hmc.gamedir=$PWD/run/test-${{ matrix.mc }}-${{ matrix.loader }} | |
| hmc.offline=true | |
| hmc.rethrow.launch.exceptions=true | |
| hmc.exit.on.failed.command=true | |
| EOF | |
| cat <<EOF >> run/test-${{ matrix.mc }}-${{ matrix.loader }}/options.txt | |
| onboardAccessibility:false | |
| pauseOnLostFocus:false | |
| EOF | |
| json="$(cat ./headlessmc.json)" | |
| url="$(echo $json | jq -r '.assets[].browser_download_url' | grep .jar | grep launcher | grep -v jfx | grep -v wrapper)" | |
| curl -Ls -o "headlessmc-launcher.jar" $url | |
| sudo DEBIAN_FRONTEND=noninteractive apt-get install -y x11-xserver-utils | |
| - name: Tests with HeadlessMC | |
| if: github.event.inputs.bypass-test != 'true' | |
| env: | |
| ENABLE_NULL2264_COBBLEGEN_GAMETEST: true | |
| run: | | |
| VERSION=v4.45.1 | |
| BINARY=yq_linux_amd64 | |
| wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -O - |\ | |
| tar xz && sudo mv ${BINARY} /usr/bin/yq | |
| cp cobblegen/build/libs/cobblegen-*+${{ matrix.mc }}*-BETA-${{ matrix.loader }}.jar run/test-${{ matrix.mc }}-${{ matrix.loader }}/mods | |
| echo "# [$(echo "${{ matrix.loader }}" | tr '[:lower:]' '[:upper:]') - ${{ matrix.mc }}] Test results" >> $GITHUB_STEP_SUMMARY; | |
| echo "<table>" >> $GITHUB_STEP_SUMMARY; | |
| echo "<tr>" >> $GITHUB_STEP_SUMMARY; | |
| echo "<th>Runtime Version</th><th>Status</th>" >> $GITHUB_STEP_SUMMARY; | |
| echo "</tr>" >> $GITHUB_STEP_SUMMARY; | |
| echo "[TEST] Initializing..." | |
| TEST_VERSIONS=(${{ join(matrix.testVersions, ' ') }}) | |
| for i in "${TEST_VERSIONS[@]}"; do | |
| echo "[TEST] Testing MC $i (${{ matrix.loader }})..." | |
| echo "[TEST] Downloading Runtime Test Mod... [0/3]" | |
| json="$(cat ./mc-runtime-test.json)" | |
| echo "[TEST] Downloading Runtime Test Mod... [1/3]" | |
| TARGET=$i | |
| url="$(echo $json | jq -r '.assets[].browser_download_url' | grep ${TARGET//\./\\.} | grep ${{ matrix.loader == 'forge' && 'lexforge' || matrix.loader }} || echo "[FAIL]")" | |
| [ "$url" = "[FAIL]" ] && ( | |
| >&2 echo "[FAIL] There's no Runtime Test Mod for MC $i!"; | |
| exit 1; | |
| ) | |
| echo "[TEST] Downloading Runtime Test Mod... [2/3]" | |
| curl -Ls -o "mc-runtime-test.jar" $url | |
| echo "[TEST] Downloading Runtime Test Mod... [3/3]" | |
| mv -f ./mc-runtime-test.jar run/test-${{ matrix.mc }}-${{ matrix.loader }}/mods | |
| [ "${{ matrix.loader }}" = "fabric" ] && ( | |
| fapi="$(yq -M ".[\"$i\"]" fabric-versions.yaml || echo 'null')" | |
| [ "$fapi" = "null" ] || ( | |
| url="https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/$fapi+$i/fabric-api-$fapi+$i.jar" | |
| curl -Ls -o "fapi.jar" $url | |
| mv -f ./fapi.jar run/test-${{ matrix.mc }}-${{ matrix.loader }}/mods | |
| ) | |
| gametest="$(yq -M ".[\"$i\"]" fabric-gametest-versions.yaml || echo 'null')" | |
| [ "$gametest" = "null" ] || ( | |
| rm -f run/test-${{ matrix.mc }}-${{ matrix.loader }}/mods/fapi-resource.jar | |
| resource="$(yq -M ".[\"$i\"]" fabric-resource-versions.yaml || echo 'null')" | |
| [ "$resource" = "null" ] || ( | |
| url="https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-resource-loader-v0/$resource/fabric-resource-loader-v0-$resource.jar" | |
| curl -Ls -o "fapi-resource.jar" $url | |
| mv -f ./fapi-resource.jar run/test-${{ matrix.mc }}-${{ matrix.loader }}/mods | |
| ) | |
| url="https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-gametest-api-v1/$gametest/fabric-gametest-api-v1-$gametest.jar" | |
| curl -Ls -o "fapi-gametest.jar" $url | |
| mv -f ./fapi-gametest.jar run/test-${{ matrix.mc }}-${{ matrix.loader }}/mods | |
| ) | |
| ) | |
| echo "[TEST] Downloading MC..." | |
| java -jar ./headlessmc-launcher.jar --command download $i | |
| echo "[TEST] Downloading Mod Loader..." | |
| java -jar ./headlessmc-launcher.jar --command ${{ matrix.loader }} $i | |
| echo "[TEST] Launching MC Headless..." | |
| timeout 20m xvfb-run java -Dhmc.check.xvfb=true -jar ./headlessmc-launcher.jar --command launch ${{ matrix.loader }}:$i --retries 3 --jvm "-Djava.awt.headless=true -DMcRuntimeGameTestMinExpectedGameTests=1" && ( | |
| echo "[TEST] Test complete ($i)"; true; | |
| echo "<tr>" >> $GITHUB_STEP_SUMMARY; | |
| echo "<td>$i</td><td>🟩 Complete</td>" >> $GITHUB_STEP_SUMMARY; | |
| echo "</tr>" >> $GITHUB_STEP_SUMMARY; | |
| ) || ( | |
| EXIT_CODE="$?" | |
| echo "[TEST] Test failed or timed out ($i)"; true; | |
| echo "<tr>" >> $GITHUB_STEP_SUMMARY; | |
| STATUS="Unknown error ($EXIT_CODE)"; | |
| case "$EXIT_CODE" in | |
| "-1") | |
| STATUS="🟥 Test failed" | |
| ;; | |
| "125" | "124") | |
| STATUS="🟨 Timed out" | |
| ;; | |
| "255" | "1") | |
| STATUS="🟥 Crashed" | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| echo "<td>$i</td><td>$STATUS</td>" >> $GITHUB_STEP_SUMMARY; | |
| echo "</tr>" >> $GITHUB_STEP_SUMMARY; | |
| case "$EXIT_CODE" in | |
| "255" | "1") | |
| echo "</table>" >> $GITHUB_STEP_SUMMARY | |
| exit $EXIT_CODE | |
| ;; | |
| *) | |
| ;; | |
| esac | |
| ) | |
| done | |
| echo "</table>" >> $GITHUB_STEP_SUMMARY; | |
| - name: Release | |
| if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' && github.event.inputs.bypass-mod-publish != 'true' | |
| shell: bash | |
| run: | | |
| ./gradlew publishMods -PmcVer="${{ matrix.mc }}" -Pnull2264.platform="${{ matrix.loader }}" | |
| env: | |
| VERSION: ${{ github.event.inputs.version == '' && '0.0.0' || github.event.inputs.version }} | |
| CHANGELOG: ${{ needs.setup.outputs.changelog }} | |
| CURSEFORGE: ${{ secrets.CURSEFORGE }} | |
| MODRINTH: ${{ secrets.MODRINTH }} | |
| release: | |
| name: Release to GitHub | |
| needs: [setup, build] | |
| if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Setup CHANGELOG parser | |
| uses: taiki-e/install-action@parse-changelog | |
| - name: Merge build artifacts | |
| uses: actions/upload-artifact/merge@v4 | |
| with: | |
| name: build-artifacts | |
| pattern: build-artifacts-* | |
| delete-merged: true | |
| - name: Merge jar artifacts | |
| uses: actions/upload-artifact/merge@v4 | |
| with: | |
| name: jars | |
| pattern: jar-* | |
| delete-merged: true | |
| - name: Download build artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: jars | |
| - name: Deploy to GitHub | |
| if: needs.setup.outputs.changelog != '' | |
| uses: softprops/action-gh-release@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: v${{github.event.inputs.version}} | |
| name: v${{github.event.inputs.version}} | |
| body: | | |
| ${{ needs.setup.outputs.changelog }} | |
| files: | | |
| ./!(*-dev-shade|*-sources).jar |