Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions .github/actions/nuget-pack/action.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
name: 'NuGet Pack'
description: 'Packs RocketModFix NuGet packages'
description: 'Packs (and optionally pushes) a RocketModFix NuGet package from a .nuspec'
inputs:
nuspec_path:
description: 'Path to .nuspec'
required: true
nuget_push:
description: 'Push to Nuget?'
description: 'Push to NuGet?'
required: false
default: false
default: 'false'
nuget_key:
description: 'NuGet deploy key'
required: false
runs:
using: "composite"
steps:
- name: Pack
run: nuget pack ${{ inputs.nuspec_path }}
shell: bash
- name: Push to NuGet (Release)
run: if ${{ inputs.nuget_push == 'true' }}; then
dotnet nuget push *.nupkg --api-key ${{ inputs.nuget_key }} --source https://api.nuget.org/v3/index.json;
fi
env:
NUSPEC_PATH: ${{ inputs.nuspec_path }}
run: |
set -euo pipefail
nuget pack "$NUSPEC_PATH"
- name: Push to NuGet
shell: bash
env:
NUGET_PUSH: ${{ inputs.nuget_push }}
NUGET_KEY: ${{ inputs.nuget_key }}
run: |
set -euo pipefail
if [ "$NUGET_PUSH" != "true" ]; then
echo "nuget_push is '$NUGET_PUSH' (not 'true') — skipping push."
exit 0
fi
# No --skip-duplicate by design: a duplicate version means something
# upstream went wrong, and the publish should fail loudly.
dotnet nuget push *.nupkg --api-key "$NUGET_KEY" --source https://api.nuget.org/v3/index.json
42 changes: 42 additions & 0 deletions .github/scripts/compare_nuget_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
"""Compare two RocketModFix.Unturned.Redist NuGet versions.

Prints one of: lt | eq | gt (how NEW compares to OLD).

Handles the two version shapes this repo produces:
- stable: X.Y.Z.N (e.g. 3.26.3.2)
- preview: X.Y.Z.N-preview<build> (e.g. 3.26.4.100-preview23479280)

NuGet/SemVer ordering: a stable release outranks any prerelease of the same
core version, and prereleases are ordered by their numeric build id.

Usage: compare_nuget_version.py <new> <old>
Exit codes: 0 on success, 2 on an unrecognized version string.
"""
import re
import sys

_VERSION_RE = re.compile(r"^(\d+)\.(\d+)\.(\d+)\.(\d+)(?:-preview(\d+))?$")


def parse(version: str):
match = _VERSION_RE.match(version.strip())
if not match:
print(f"::error::Unrecognized NuGet version format: {version}", file=sys.stderr)
sys.exit(2)
core = tuple(int(x) for x in match.groups()[:4])
pre = match.group(5)
# (core, is_release, prerelease_build): release (1) sorts above prerelease (0).
return (core, 1, 0) if pre is None else (core, 0, int(pre))


def main() -> None:
if len(sys.argv) != 3:
print("usage: compare_nuget_version.py <new> <old>", file=sys.stderr)
sys.exit(2)
new, old = parse(sys.argv[1]), parse(sys.argv[2])
print("lt" if new < old else ("eq" if new == old else "gt"))


if __name__ == "__main__":
main()
102 changes: 102 additions & 0 deletions .github/variants.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
[
{
"variant": "client",
"appId": "304930",
"depotId": "304931",
"branch": "",
"dir": "redist/redist-client",
"nuspec": "redist/redist-client/RocketModFix.Unturned.Redist.Client.nuspec",
"preview": false,
"publicize": false
},
{
"variant": "server",
"appId": "1110390",
"depotId": "1110391",
"branch": "",
"dir": "redist/redist-server",
"nuspec": "redist/redist-server/RocketModFix.Unturned.Redist.Server.nuspec",
"preview": false,
"publicize": false
},
{
"variant": "client-preview",
"appId": "304930",
"depotId": "304931",
"branch": "preview",
"dir": "redist/redist-client-preview",
"nuspec": "redist/redist-client-preview/RocketModFix.Unturned.Redist.Client.nuspec",
"preview": true,
"publicize": false
},
{
"variant": "server-preview",
"appId": "1110390",
"depotId": "1110391",
"branch": "preview",
"dir": "redist/redist-server-preview",
"nuspec": "redist/redist-server-preview/RocketModFix.Unturned.Redist.Server.nuspec",
"preview": true,
"publicize": false
},
{
"variant": "client-preview-old",
"appId": "304930",
"depotId": "304931",
"branch": "preview",
"dir": "redist/redist-client-preview-old",
"nuspec": "redist/redist-client-preview-old/RocketModFix.Unturned.Redist.Client.nuspec",
"preview": false,
"publicize": false
},
{
"variant": "server-preview-old",
"appId": "1110390",
"depotId": "1110391",
"branch": "preview",
"dir": "redist/redist-server-preview-old",
"nuspec": "redist/redist-server-preview-old/RocketModFix.Unturned.Redist.Server.nuspec",
"preview": false,
"publicize": false
},
{
"variant": "client-publicized",
"appId": "304930",
"depotId": "304931",
"branch": "",
"dir": "redist/redist-client-publicized",
"nuspec": "redist/redist-client-publicized/RocketModFix.Unturned.Redist.Client.nuspec",
"preview": false,
"publicize": true
},
{
"variant": "server-publicized",
"appId": "1110390",
"depotId": "1110391",
"branch": "",
"dir": "redist/redist-server-publicized",
"nuspec": "redist/redist-server-publicized/RocketModFix.Unturned.Redist.Server.nuspec",
"preview": false,
"publicize": true
},
{
"variant": "client-preview-publicized",
"appId": "304930",
"depotId": "304931",
"branch": "preview",
"dir": "redist/redist-client-preview-publicized",
"nuspec": "redist/redist-client-preview-publicized/RocketModFix.Unturned.Redist.Client.nuspec",
"preview": false,
"publicize": true
},
{
"variant": "server-preview-publicized",
"appId": "1110390",
"depotId": "1110391",
"branch": "preview",
"dir": "redist/redist-server-preview-publicized",
"nuspec": "redist/redist-server-preview-publicized/RocketModFix.Unturned.Redist.Server.nuspec",
"preview": false,
"publicize": true
}
]
24 changes: 13 additions & 11 deletions .github/workflows/Cleanup.RedistBranch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@ jobs:
pull-requests: write
steps:
- name: Lock PR conversation
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
echo "Locking PR #$PR_NUMBER to prevent further comments"
gh pr lock "$PR_NUMBER" --repo "${{ github.repository }}" --reason resolved
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Delete PR branch
run: |
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
echo "Deleting redist PR branch: $BRANCH_NAME"
gh api \
-X DELETE \
"repos/${{ github.repository }}/git/refs/heads/$BRANCH_NAME"
echo "Locking PR #${{ github.event.pull_request.number }}"
gh pr lock "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}" --reason resolved || true

# Only delete after a successful merge. Never delete the branch of a PR
# that was closed without merging (it may contain work to investigate).
# PRs closed-as-unnecessary by create-pull-request are already cleaned up
# by its delete-branch:true, so this is the merge case.
- name: Delete merged PR branch
if: github.event.pull_request.merged == true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
echo "Deleting merged redist PR branch: $BRANCH_NAME"
gh api -X DELETE "repos/${{ github.repository }}/git/refs/heads/$BRANCH_NAME" || true
137 changes: 65 additions & 72 deletions .github/workflows/RocketModFix.Unturned.Redist.Matrix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,100 +8,93 @@ on:
workflow_dispatch:
inputs:
variant:
description: 'Which variant to update'
description: 'A variant name from .github/variants.json, or "all"'
required: true
type: choice
options:
- all
- client
- client-preview
- client-preview-old
- client-preview-publicized
- client-publicized
- server
- server-preview
- server-preview-old
- server-preview-publicized
- server-publicized
default: 'all'
type: string

jobs:
# Single source of truth: variant definitions live in .github/variants.json.
load-variants:
name: "Load Variants"
runs-on: ubuntu-latest
outputs:
variants: ${{ steps.load.outputs.variants }}
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Load variant matrix
id: load
env:
INPUT_VARIANT: ${{ github.event.inputs.variant }}
EVENT_NAME: ${{ github.event_name }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ -n "${INPUT_VARIANT:-}" ] && [ "$INPUT_VARIANT" != "all" ]; then
if ! jq -e --arg v "$INPUT_VARIANT" 'any(.[]; .variant == $v)' .github/variants.json >/dev/null; then
echo "::error::Unknown variant '$INPUT_VARIANT'. Valid variants:"
jq -r '.[].variant' .github/variants.json
exit 1
fi
variants=$(jq -c --arg v "$INPUT_VARIANT" '[.[] | select(.variant == $v)]' .github/variants.json)
else
variants=$(jq -c '.' .github/variants.json)
fi
echo "variants=$variants" >> "$GITHUB_OUTPUT"

build:
name: "Build ${{ matrix.variant }}"
runs-on: ubuntu-22.04
continue-on-error: true

needs: load-variants
# No job-level continue-on-error: a failed pack/push must surface red.
# fail-fast:false keeps the other (independent) variants building.
strategy:
matrix:
include:
# Client variants
- variant: "client"
nuspec_path: "redist/redist-client/RocketModFix.Unturned.Redist.Client.nuspec"
trigger_path: "redist/redist-client/**"
- variant: "client-preview"
nuspec_path: "redist/redist-client-preview/RocketModFix.Unturned.Redist.Client.nuspec"
trigger_path: "redist/redist-client-preview/**"
- variant: "client-preview-old"
nuspec_path: "redist/redist-client-preview-old/RocketModFix.Unturned.Redist.Client.nuspec"
trigger_path: "redist/redist-client-preview-old/**"
- variant: "client-preview-publicized"
nuspec_path: "redist/redist-client-preview-publicized/RocketModFix.Unturned.Redist.Client.nuspec"
trigger_path: "redist/redist-client-preview-publicized/**"
- variant: "client-publicized"
nuspec_path: "redist/redist-client-publicized/RocketModFix.Unturned.Redist.Client.nuspec"
trigger_path: "redist/redist-client-publicized/**"

# Server variants
- variant: "server"
nuspec_path: "redist/redist-server/RocketModFix.Unturned.Redist.Server.nuspec"
trigger_path: "redist/redist-server/**"
- variant: "server-preview"
nuspec_path: "redist/redist-server-preview/RocketModFix.Unturned.Redist.Server.nuspec"
trigger_path: "redist/redist-server-preview/**"
- variant: "server-preview-old"
nuspec_path: "redist/redist-server-preview-old/RocketModFix.Unturned.Redist.Server.nuspec"
trigger_path: "redist/redist-server-preview-old/**"
- variant: "server-preview-publicized"
nuspec_path: "redist/redist-server-preview-publicized/RocketModFix.Unturned.Redist.Server.nuspec"
trigger_path: "redist/redist-server-preview-publicized/**"
- variant: "server-publicized"
nuspec_path: "redist/redist-server-publicized/RocketModFix.Unturned.Redist.Server.nuspec"
trigger_path: "redist/redist-server-publicized/**"
fail-fast: false
matrix:
include: ${{ fromJson(needs.load-variants.outputs.variants) }}

steps:
- name: Checkout code
uses: actions/checkout@v6
with:
# Fetches all history for the tj-actions/changed-files to work correctly on push
# Full history so we can diff the push range for per-variant change detection.
fetch-depth: 0

- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v47
with:
files: |
${{ matrix.trigger_path }}

- name: Determine if this variant should run
id: check
env:
EVENT_NAME: ${{ github.event_name }}
DIR: ${{ matrix.dir }}
BEFORE_SHA: ${{ github.event.before }}
AFTER_SHA: ${{ github.sha }}
run: |
SHOULD_RUN=false
# For manual triggers, check the input
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
if [[ "${{ github.event.inputs.variant }}" == "all" || "${{ github.event.inputs.variant }}" == "${{ matrix.variant }}" ]]; then
SHOULD_RUN=true
set -euo pipefail
should_run=false
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
# load-variants already filtered the matrix to the requested variant(s).
should_run=true
else
# Native git diff replaces tj-actions/changed-files (one less third-party
# action). The Update pipeline squash-merges one variant per commit, so
# github.event.before is the prior master tip; fall back to HEAD~1.
before="$BEFORE_SHA"
if [ -z "$before" ] || [ "$before" = "0000000000000000000000000000000000000000" ]; then
before="HEAD~1"
fi
# For push triggers, use the changed-files output
elif [[ "${{ github.event_name }}" == "push" ]]; then
if [[ "${{ steps.changed-files.outputs.any_changed }}" == "true" ]]; then
SHOULD_RUN=true
if ! git rev-parse --verify "$before" >/dev/null 2>&1; then
# No usable baseline (e.g. first push to a branch) -> build to be safe.
should_run=true
elif git diff --name-only "$before" "$AFTER_SHA" -- "$DIR/" | grep -q .; then
should_run=true
fi
fi
echo "should_run=$SHOULD_RUN" >> $GITHUB_OUTPUT
echo "Variant ${{ matrix.variant }} should_run=$should_run"
echo "should_run=$should_run" >> "$GITHUB_OUTPUT"

- name: Setup NuGet
if: steps.check.outputs.should_run == 'true'
uses: nuget/setup-nuget@v4
uses: nuget/setup-nuget@fd55a6f3b34392fa83fde1454582407d8c714123 # v4
with:
nuget-api-key: ${{ secrets.NUGET_DEPLOY_KEY }}

Expand All @@ -110,6 +103,6 @@ jobs:
uses: ./.github/actions/nuget-pack
id: nuget-pack
with:
nuspec_path: ${{ matrix.nuspec_path }}
nuspec_path: ${{ matrix.nuspec }}
nuget_key: ${{ secrets.NUGET_DEPLOY_KEY }}
nuget_push: true
nuget_push: true
Loading