Redist Update #49
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: "Redist Update" | |
| # Scheduled: fetch the official Rocket (LDM) assemblies from the Unturned dedicated | |
| # server's Extras/Rocket.Unturned and, when the Rocket version changed, open a PR. | |
| # Never commits to master directly — redist-verify validates it, redist-publish | |
| # publishes on merge. Mirrors RocketModFix.Unturned.Redist's flow (1 variant here). | |
| on: | |
| schedule: | |
| - cron: "0 * * * *" # hourly; LDM changes a few times a year, so most runs are a no-op | |
| workflow_dispatch: | |
| inputs: | |
| force: | |
| description: "Open a PR even if the Rocket version is unchanged" | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ldm-redist-update | |
| cancel-in-progress: false | |
| env: | |
| APP_ID: "1110390" # Unturned Dedicated Server | |
| CONTENT_DEPOT: "1110393" # content depot holding Extras/Rocket.Unturned | |
| ROCKET_DIR: "download/Extras/Rocket.Unturned" | |
| NUSPEC: "RocketModFix.LDM.Redist.nuspec" | |
| PR_BRANCH: "redist-update/ldm" | |
| jobs: | |
| update: | |
| name: "Update LDM redist" | |
| runs-on: ubuntu-22.04 | |
| permissions: | |
| contents: write # peter-evans needs it to push the branch | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Download DepotDownloader | |
| uses: robinraju/release-downloader@28fc21f50d76778e7023361aa1f863e717d3d56f # v1 | |
| with: | |
| repository: SteamRE/DepotDownloader | |
| tag: "DepotDownloader_3.4.0" # Pin its version to avoid breaking changes. | |
| fileName: DepotDownloader-linux-x64.zip | |
| out-file-path: depot_downloader | |
| extract: true | |
| - name: Fetch Rocket assemblies from Steam | |
| run: | | |
| set -euo pipefail | |
| chmod +x depot_downloader/DepotDownloader | |
| printf '%s\n' \ | |
| 'Extras/Rocket.Unturned/Rocket.API.dll' \ | |
| 'Extras/Rocket.Unturned/Rocket.Core.dll' \ | |
| 'Extras/Rocket.Unturned/Rocket.Unturned.dll' \ | |
| 'Extras/Rocket.Unturned/Rocket.Unturned.module' > rocket_filelist.txt | |
| # Anonymous works for the dedicated-server depots. steamcmd can't fetch a | |
| # file subset, so DepotDownloader -filelist is the right tool here; the DLLs | |
| # are MIT (LDM) with public source. Retry: DepotDownloader can drop mid-run. | |
| ok=false | |
| for i in 1 2 3 4; do | |
| rm -rf download | |
| if depot_downloader/DepotDownloader -app "$APP_ID" -depot "$CONTENT_DEPOT" \ | |
| -os linux -dir download -filelist rocket_filelist.txt \ | |
| && [ -f "$ROCKET_DIR/Rocket.Unturned.module" ] \ | |
| && [ -f "$ROCKET_DIR/Rocket.Core.dll" ] \ | |
| && [ -f "$ROCKET_DIR/Rocket.API.dll" ] \ | |
| && [ -f "$ROCKET_DIR/Rocket.Unturned.dll" ]; then | |
| ok=true; break | |
| fi | |
| echo "::warning::DepotDownloader attempt ${i}/4 did not produce the Rocket files (likely a transient Steam drop); retrying after backoff..." | |
| [ "$i" -lt 4 ] && sleep $((i * 15)) | |
| done | |
| if [ "$ok" != "true" ]; then | |
| echo "::error::Could not fetch the Rocket assemblies after 4 attempts." | |
| exit 1 | |
| fi | |
| - name: Resolve version and decide whether to open a PR | |
| id: decide | |
| env: | |
| FORCE: ${{ github.event.inputs.force }} | |
| run: | | |
| set -euo pipefail | |
| new=$(jq -r '.Version' "$ROCKET_DIR/Rocket.Unturned.module") | |
| if [ -z "$new" ] || [ "$new" = "null" ]; then | |
| echo "::error::Could not read .Version from Rocket.Unturned.module." | |
| exit 1 | |
| fi | |
| old=$(sed -n 's:.*<version>\(.*\)</version>.*:\1:p' "$NUSPEC" | head -n1) | |
| echo "On master: ${old:-<none>} | Upstream Rocket: $new" | |
| open=false | |
| if [ "${FORCE:-false}" = "true" ]; then | |
| open=true | |
| elif [ "$old" = "$new" ]; then | |
| echo "Rocket unchanged — no PR." | |
| elif [ "$(printf '%s\n%s\n' "$old" "$new" | sort -V | tail -n1)" = "$new" ]; then | |
| open=true | |
| else | |
| echo "::error::Upstream Rocket version ($new) is older than the one on master ($old); refusing to downgrade." | |
| exit 1 | |
| fi | |
| echo "version=$new" >> "$GITHUB_OUTPUT" | |
| echo "open=$open" >> "$GITHUB_OUTPUT" | |
| - name: Stage assemblies, version and hash manifest | |
| if: steps.decide.outputs.open == 'true' | |
| env: | |
| VERSION: ${{ steps.decide.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p assemblies | |
| rm -f assemblies/*.dll | |
| cp "$ROCKET_DIR"/Rocket.API.dll "$ROCKET_DIR"/Rocket.Core.dll "$ROCKET_DIR"/Rocket.Unturned.dll assemblies/ | |
| sed -i "s|<version>[^<]*</version>|<version>${VERSION}</version>|" "$NUSPEC" | |
| # Integrity manifest redist-verify checks before merge. | |
| python3 - <<'PY' | |
| import hashlib, json, glob, os | |
| m = {os.path.basename(f): hashlib.sha256(open(f,'rb').read()).hexdigest() | |
| for f in sorted(glob.glob("assemblies/*.dll"))} | |
| json.dump(m, open("assemblies/manifest.sha256.json","w"), indent=2) | |
| PY | |
| # Created with PAT (not GITHUB_TOKEN) so the PR triggers redist-verify, and so | |
| # the bot author gates auto-merge there. Mirrors the Unturned Redist. | |
| - name: Create Pull Request | |
| if: steps.decide.outputs.open == 'true' | |
| uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8 | |
| with: | |
| token: ${{ secrets.PAT }} | |
| branch: ${{ env.PR_BRANCH }} | |
| delete-branch: true | |
| base: master | |
| add-paths: | | |
| assemblies/** | |
| ${{ env.NUSPEC }} | |
| commit-message: "Update to Rocket ${{ steps.decide.outputs.version }}" | |
| title: "🤖 Update to Rocket ${{ steps.decide.outputs.version }}" | |
| committer: rocketmodfixadmin <rocketmodfixadmin@users.noreply.github.com> | |
| author: rocketmodfixadmin <rocketmodfixadmin@users.noreply.github.com> | |
| body: | | |
| Automated update of the official Rocket (LDM) assemblies to **${{ steps.decide.outputs.version }}**. | |
| Validation (files, SHA-256 hashes, no version downgrade) runs on this PR via `redist-verify`. On merge, `redist-publish` pushes to NuGet + GitHub Packages. | |
| labels: | | |
| automated | |
| redist-update | |
| # On any scheduled-run failure, open (or comment on) a tracking issue. | |
| notify-failure: | |
| name: "Notify on failure" | |
| needs: update | |
| if: failure() && github.event_name == 'schedule' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| issues: write | |
| steps: | |
| - name: Open or update tracking issue | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| run: | | |
| set -euo pipefail | |
| marker="LDM redist update workflow failed" | |
| body=$(printf '⚠️ The scheduled LDM redist update failed.\n\nRun: %s\n\nA Steam fetch (DepotDownloader) or the PR creation errored. Check the run for the failing step.' "$RUN_URL") | |
| gh label create update-failure --repo "$REPO" --color B60205 --description "Automated LDM redist update failure" --force >/dev/null 2>&1 || true | |
| existing=$(gh issue list --repo "$REPO" --state open --search "in:title \"$marker\"" --json number --jq '.[0].number // empty') | |
| if [ -n "$existing" ]; then | |
| gh issue comment "$existing" --repo "$REPO" --body "$body" | |
| else | |
| gh issue create --repo "$REPO" --title "⚠️ $marker" --body "$body" --label update-failure | |
| fi | |
| workflow-keepalive: | |
| if: github.event_name == 'schedule' | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| permissions: | |
| actions: write | |
| steps: | |
| - name: Re-enable this scheduled workflow | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| case "${GITHUB_WORKFLOW_REF:?}" in | |
| "${GITHUB_REPOSITORY:?}"/.github/workflows/*.y*ml@*) ;; | |
| *) echo "::error::Unexpected GITHUB_WORKFLOW_REF: ${GITHUB_WORKFLOW_REF}"; exit 1 ;; | |
| esac | |
| workflow="${GITHUB_WORKFLOW_REF%%@*}" | |
| workflow="${workflow#"${GITHUB_REPOSITORY}"/.github/workflows/}" | |
| gh api -X PUT "repos/${GITHUB_REPOSITORY}/actions/workflows/${workflow}/enable" |