Compare commits
9
Commits
4e2ccd975b
..
v1.0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce35f98fb7 | ||
|
|
ef2f78ff91 | ||
|
|
159e12c79a | ||
|
|
dae0123a17 | ||
|
|
391127c5b9 | ||
|
|
ffba9651c4 | ||
|
|
100a5cebd8 | ||
|
|
415a3886b0 | ||
|
|
992b2184f6 |
@@ -48,14 +48,14 @@ The uploaded artifact is the whole build folder, so companion files such as a `.
|
|||||||
|
|
||||||
| Input | Required | Default | Description |
|
| Input | Required | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `godot-version` | Yes | — | The Godot 4 release tag to use, without the leading `v`; for example, `4.7.2-stable`. |
|
| `godot-version` | Yes | — | A stable Godot 4 release tag, without the leading `v`; for example, `4.7.2-stable`. Alpha, beta, RC, and dev tags are unsupported. |
|
||||||
| `host-os` | Yes | — | The machine running the job: `linux`, `macos`, or `windows`. The action checks this before it starts. |
|
| `host-os` | Yes | — | The machine running the job: `linux`, `macos`, or `windows`. The action checks this before it starts. |
|
||||||
| `host-arch` | Yes | — | The runner's architecture. Linux supports `x86_32`, `x86_64`, `arm32`, and `arm64`; Windows supports `x86_32`, `x86_64`, and `arm64`; macOS supports `x86_64` and `arm64`. |
|
| `host-arch` | Yes | — | The runner's architecture. Linux supports `x86_32`, `x86_64`, `arm32`, and `arm64`; Windows supports `x86_32`, `x86_64`, and `arm64`; macOS supports `x86_64` and `arm64`. |
|
||||||
|
| `export-preset` | Yes | — | The preset name exactly as it appears in `export_presets.cfg`. |
|
||||||
|
| `export-file-name` | Yes | — | The name of the exported file, such as `my-game.exe` or `my-game.zip`. Use the extension your target expects. |
|
||||||
| `dotnet` | No | `false` | Set this to `true` for a Godot .NET/C# project. |
|
| `dotnet` | No | `false` | Set this to `true` for a Godot .NET/C# project. |
|
||||||
| `project-path` | No | `.` | Where your Godot project sits inside the checked-out repository. |
|
| `project-path` | No | `.` | Where your Godot project sits inside the checked-out repository. |
|
||||||
| `export-preset` | Yes | — | The preset name exactly as it appears in `export_presets.cfg`. |
|
| `export-mode` | No | `debug` | Choose `release` for a shipping build or `debug` for a debug build. |
|
||||||
| `export-mode` | No | `release` | Choose `release` for a shipping build or `debug` for a debug build. |
|
|
||||||
| `export-file-name` | Yes | — | The name of the exported file, such as `my-game.exe` or `my-game.zip`. Use the extension your target expects. |
|
|
||||||
| `cache` | No | `true` | Set to `false` if you need a completely fresh Godot download for a run. |
|
| `cache` | No | `true` | Set to `false` if you need a completely fresh Godot download for a run. |
|
||||||
|
|
||||||
## Outputs
|
## Outputs
|
||||||
@@ -67,7 +67,8 @@ The uploaded artifact is the whole build folder, so companion files such as a `.
|
|||||||
## A few helpful notes
|
## A few helpful notes
|
||||||
|
|
||||||
- Your project needs both `project.godot` and `export_presets.cfg`. Preset names with spaces, such as `Windows Desktop`, are fine.
|
- Your project needs both `project.godot` and `export_presets.cfg`. Preset names with spaces, such as `Windows Desktop`, are fine.
|
||||||
- Downloads are checked against Godot's published `SHA512-SUMS.txt` file before anything is extracted.
|
- Editor and template downloads come from the [official Godot stable-release assets](https://github.com/godotengine/godot/releases) and are checked against that release's `SHA512-SUMS.txt` before anything is extracted. If a release does not provide an editor for the requested runner architecture, the action fails before downloading either archive.
|
||||||
|
- Linux ARM downloads require Godot 4.2 or newer; Windows ARM64 downloads require Godot 4.3 or newer. macOS uses the universal editor archive on both supported architectures.
|
||||||
- On Linux, make sure the runner has `curl`, `unzip`, and `sha512sum`. macOS needs `curl`, `unzip`, and `shasum`. Windows uses the archive and hashing tools built into PowerShell.
|
- On Linux, make sure the runner has `curl`, `unzip`, and `sha512sum`. macOS needs `curl`, `unzip`, and `shasum`. Windows uses the archive and hashing tools built into PowerShell.
|
||||||
- The cache includes the editor and the full export-template package. Gitea keeps that cache on each runner by default; an administrator can configure shared storage if several runners should reuse it.
|
- The cache includes the editor and the full export-template package. Gitea keeps that cache on each runner by default; an administrator can configure shared storage if several runners should reuse it.
|
||||||
- This action installs Godot, not every SDK around it. Android, iOS, console, and other platform-specific presets may still need their own SDKs, credentials, or signing setup on the runner.
|
- This action installs Godot, not every SDK around it. Android, iOS, console, and other platform-specific presets may still need their own SDKs, credentials, or signing setup on the runner.
|
||||||
|
|||||||
+5
-5
@@ -3,7 +3,7 @@ description: Download and cache Godot 4, install export templates, and export a
|
|||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
godot-version:
|
godot-version:
|
||||||
description: Exact Godot 4 release tag without a leading v (for example, 4.6.1-stable).
|
description: Exact stable Godot 4 release tag without a leading v (for example, 4.6.1-stable). Prerelease tags are unsupported.
|
||||||
required: true
|
required: true
|
||||||
host-os:
|
host-os:
|
||||||
description: "Runner operating system: linux, macos, or windows."
|
description: "Runner operating system: linux, macos, or windows."
|
||||||
@@ -25,7 +25,7 @@ inputs:
|
|||||||
export-mode:
|
export-mode:
|
||||||
description: "Export mode: release or debug."
|
description: "Export mode: release or debug."
|
||||||
required: false
|
required: false
|
||||||
default: release
|
default: debug
|
||||||
export-file-name:
|
export-file-name:
|
||||||
description: Output filename only, including its platform-appropriate extension.
|
description: Output filename only, including its platform-appropriate extension.
|
||||||
required: true
|
required: true
|
||||||
@@ -51,7 +51,7 @@ runs:
|
|||||||
|
|
||||||
- name: Export Godot project on Linux
|
- name: Export Godot project on Linux
|
||||||
id: export-linux
|
id: export-linux
|
||||||
if: ${{ runner.os == 'Linux' }}
|
if: ${{ runner.os == 'linux' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GODOT_VERSION: "${{ inputs.godot-version }}"
|
GODOT_VERSION: "${{ inputs.godot-version }}"
|
||||||
@@ -67,7 +67,7 @@ runs:
|
|||||||
|
|
||||||
- name: Export Godot project on macOS
|
- name: Export Godot project on macOS
|
||||||
id: export-macos
|
id: export-macos
|
||||||
if: ${{ runner.os == 'macOS' }}
|
if: ${{ runner.os == 'macos' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GODOT_VERSION: "${{ inputs.godot-version }}"
|
GODOT_VERSION: "${{ inputs.godot-version }}"
|
||||||
@@ -83,7 +83,7 @@ runs:
|
|||||||
|
|
||||||
- name: Export Godot project on Windows
|
- name: Export Godot project on Windows
|
||||||
id: export-windows
|
id: export-windows
|
||||||
if: ${{ runner.os == 'Windows' }}
|
if: ${{ runner.os == 'windows' }}
|
||||||
shell: powershell
|
shell: powershell
|
||||||
env:
|
env:
|
||||||
GODOT_VERSION: "${{ inputs.godot-version }}"
|
GODOT_VERSION: "${{ inputs.godot-version }}"
|
||||||
|
|||||||
+40
-11
@@ -16,7 +16,7 @@ require_environment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate_common_inputs() {
|
validate_common_inputs() {
|
||||||
[[ "$GODOT_VERSION" =~ ^4(\.[0-9]+){1,2}(-[0-9A-Za-z][0-9A-Za-z._-]*)?$ ]] || fail "godot-version must be a Godot 4 release tag such as 4.7.2-stable."
|
[[ "$GODOT_VERSION" =~ ^4(\.[0-9]+){1,2}-stable$ ]] || fail "godot-version must be a stable Godot 4 tag such as 4.7.2-stable. Alpha, beta, RC, and dev tags are not supported."
|
||||||
[[ "$GODOT_HOST_OS" == "linux" ]] || fail "host-os must be 'linux' when this action runs on Linux."
|
[[ "$GODOT_HOST_OS" == "linux" ]] || fail "host-os must be 'linux' when this action runs on Linux."
|
||||||
[[ "$GODOT_DOTNET" == "true" || "$GODOT_DOTNET" == "false" ]] || fail "dotnet must be 'true' or 'false'."
|
[[ "$GODOT_DOTNET" == "true" || "$GODOT_DOTNET" == "false" ]] || fail "dotnet must be 'true' or 'false'."
|
||||||
[[ "$GODOT_EXPORT_MODE" == "release" || "$GODOT_EXPORT_MODE" == "debug" ]] || fail "export-mode must be 'release' or 'debug'."
|
[[ "$GODOT_EXPORT_MODE" == "release" || "$GODOT_EXPORT_MODE" == "debug" ]] || fail "export-mode must be 'release' or 'debug'."
|
||||||
@@ -35,16 +35,23 @@ actual_architecture() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
release_asset_checksum() {
|
||||||
|
local asset="$1"
|
||||||
|
local sum_file="$2"
|
||||||
|
local expected
|
||||||
|
|
||||||
|
expected="$(awk -v asset="$asset" '$2 == asset || $2 == "*" asset { print $1; exit }' "$sum_file")"
|
||||||
|
[[ -n "$expected" ]] || fail "Godot $GODOT_VERSION does not publish required $EDITION asset '$asset' for Linux/$GODOT_HOST_ARCH at $BASE_URL. Choose a supported stable release and architecture."
|
||||||
|
printf '%s\n' "$expected"
|
||||||
|
}
|
||||||
|
|
||||||
download_and_verify() {
|
download_and_verify() {
|
||||||
local asset="$1"
|
local asset="$1"
|
||||||
local destination="$2"
|
local destination="$2"
|
||||||
local sum_file="$3"
|
local expected="$3"
|
||||||
local expected
|
|
||||||
local actual
|
local actual
|
||||||
|
|
||||||
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/$asset" --output "$destination"
|
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/$asset" --output "$destination"
|
||||||
expected="$(awk -v asset="$asset" '$2 == asset || $2 == "*" asset { print $1; exit }' "$sum_file")"
|
|
||||||
[[ -n "$expected" ]] || fail "Release checksum manifest does not contain $asset."
|
|
||||||
actual="$(sha512sum "$destination" | awk '{ print $1 }')"
|
actual="$(sha512sum "$destination" | awk '{ print $1 }')"
|
||||||
[[ "$actual" == "$expected" ]] || fail "SHA-512 verification failed for $asset."
|
[[ "$actual" == "$expected" ]] || fail "SHA-512 verification failed for $asset."
|
||||||
}
|
}
|
||||||
@@ -53,18 +60,39 @@ find_editor() {
|
|||||||
find "$EDITOR_DIR" -maxdepth 3 -type f -name 'Godot*' -print -quit
|
find "$EDITOR_DIR" -maxdepth 3 -type f -name 'Godot*' -print -quit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_export_templates() {
|
||||||
|
local staging_directory="$1"
|
||||||
|
local staged_templates="$staging_directory/templates"
|
||||||
|
local staged_version="$staged_templates/version.txt"
|
||||||
|
local actual_template_version
|
||||||
|
|
||||||
|
[[ -f "$staged_version" ]] || fail "The export-template archive '$TEMPLATES_ASSET' did not contain templates/version.txt."
|
||||||
|
actual_template_version="$(tr -d '\r\n' < "$staged_version")"
|
||||||
|
[[ "$actual_template_version" == "$TEMPLATE_VERSION" ]] || fail "The export-template archive '$TEMPLATES_ASSET' reports template version '$actual_template_version', expected '$TEMPLATE_VERSION'."
|
||||||
|
mkdir -p "$TEMPLATE_DIR"
|
||||||
|
cp -R "$staged_templates/." "$TEMPLATE_DIR/"
|
||||||
|
rm -rf "$staging_directory"
|
||||||
|
[[ -f "$TEMPLATE_DIR/version.txt" ]] || fail "The export-template archive '$TEMPLATES_ASSET' could not be installed to '$TEMPLATE_DIR'."
|
||||||
|
}
|
||||||
|
|
||||||
install_godot() {
|
install_godot() {
|
||||||
local sum_file="$CACHE_DIR/SHA512-SUMS.txt"
|
local sum_file="$CACHE_DIR/SHA512-SUMS.txt"
|
||||||
local editor_archive="$CACHE_DIR/$EDITOR_ASSET"
|
local editor_archive="$CACHE_DIR/$EDITOR_ASSET"
|
||||||
local templates_archive="$CACHE_DIR/$TEMPLATES_ASSET"
|
local templates_archive="$CACHE_DIR/$TEMPLATES_ASSET"
|
||||||
|
local templates_staging_directory="$CACHE_DIR/templates-staging"
|
||||||
|
local editor_checksum
|
||||||
|
local templates_checksum
|
||||||
|
|
||||||
rm -rf "$CACHE_DIR"
|
rm -rf "$CACHE_DIR"
|
||||||
mkdir -p "$EDITOR_DIR" "$TEMPLATE_DIR"
|
mkdir -p "$EDITOR_DIR"
|
||||||
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/SHA512-SUMS.txt" --output "$sum_file"
|
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/SHA512-SUMS.txt" --output "$sum_file"
|
||||||
download_and_verify "$EDITOR_ASSET" "$editor_archive" "$sum_file"
|
editor_checksum="$(release_asset_checksum "$EDITOR_ASSET" "$sum_file")"
|
||||||
download_and_verify "$TEMPLATES_ASSET" "$templates_archive" "$sum_file"
|
templates_checksum="$(release_asset_checksum "$TEMPLATES_ASSET" "$sum_file")"
|
||||||
|
download_and_verify "$EDITOR_ASSET" "$editor_archive" "$editor_checksum"
|
||||||
|
download_and_verify "$TEMPLATES_ASSET" "$templates_archive" "$templates_checksum"
|
||||||
unzip -q "$editor_archive" -d "$EDITOR_DIR"
|
unzip -q "$editor_archive" -d "$EDITOR_DIR"
|
||||||
unzip -q "$templates_archive" -d "$TEMPLATE_DIR"
|
unzip -q "$templates_archive" -d "$templates_staging_directory"
|
||||||
|
install_export_templates "$templates_staging_directory"
|
||||||
EDITOR_EXECUTABLE="$(find_editor)"
|
EDITOR_EXECUTABLE="$(find_editor)"
|
||||||
[[ -n "$EDITOR_EXECUTABLE" ]] || fail "The Godot editor archive did not contain an executable."
|
[[ -n "$EDITOR_EXECUTABLE" ]] || fail "The Godot editor archive did not contain an executable."
|
||||||
[[ -f "$TEMPLATE_DIR/version.txt" ]] || fail "The export-template archive did not contain version.txt."
|
[[ -f "$TEMPLATE_DIR/version.txt" ]] || fail "The export-template archive did not contain version.txt."
|
||||||
@@ -107,14 +135,15 @@ if [[ "$GODOT_DOTNET" == "true" ]]; then
|
|||||||
EDITION=dotnet
|
EDITION=dotnet
|
||||||
EDITOR_ASSET="Godot_v${GODOT_VERSION}_mono_linux_${GODOT_HOST_ARCH}.zip"
|
EDITOR_ASSET="Godot_v${GODOT_VERSION}_mono_linux_${GODOT_HOST_ARCH}.zip"
|
||||||
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_mono_export_templates.tpz"
|
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_mono_export_templates.tpz"
|
||||||
|
TEMPLATE_VERSION="${GODOT_VERSION//-/.}.mono"
|
||||||
else
|
else
|
||||||
EDITION=standard
|
EDITION=standard
|
||||||
EDITOR_ASSET="Godot_v${GODOT_VERSION}_linux.${GODOT_HOST_ARCH}.zip"
|
EDITOR_ASSET="Godot_v${GODOT_VERSION}_linux.${GODOT_HOST_ARCH}.zip"
|
||||||
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_export_templates.tpz"
|
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_export_templates.tpz"
|
||||||
|
TEMPLATE_VERSION="${GODOT_VERSION//-/.}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BASE_URL="https://github.com/godotengine/godot-builds/releases/download/$GODOT_VERSION"
|
BASE_URL="https://github.com/godotengine/godot/releases/download/$GODOT_VERSION"
|
||||||
TEMPLATE_VERSION="${GODOT_VERSION//-/.}"
|
|
||||||
CACHE_DIR="$GODOT_ACTION_ROOT/cache/$GODOT_VERSION/$EDITION/linux-$GODOT_HOST_ARCH"
|
CACHE_DIR="$GODOT_ACTION_ROOT/cache/$GODOT_VERSION/$EDITION/linux-$GODOT_HOST_ARCH"
|
||||||
EDITOR_DIR="$CACHE_DIR/editor"
|
EDITOR_DIR="$CACHE_DIR/editor"
|
||||||
USER_DATA_DIR="$CACHE_DIR/user-data"
|
USER_DATA_DIR="$CACHE_DIR/user-data"
|
||||||
|
|||||||
+40
-11
@@ -16,7 +16,7 @@ require_environment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate_common_inputs() {
|
validate_common_inputs() {
|
||||||
[[ "$GODOT_VERSION" =~ ^4(\.[0-9]+){1,2}(-[0-9A-Za-z][0-9A-Za-z._-]*)?$ ]] || fail "godot-version must be a Godot 4 release tag such as 4.7.2-stable."
|
[[ "$GODOT_VERSION" =~ ^4(\.[0-9]+){1,2}-stable$ ]] || fail "godot-version must be a stable Godot 4 tag such as 4.7.2-stable. Alpha, beta, RC, and dev tags are not supported."
|
||||||
[[ "$GODOT_HOST_OS" == "macos" ]] || fail "host-os must be 'macos' when this action runs on macOS."
|
[[ "$GODOT_HOST_OS" == "macos" ]] || fail "host-os must be 'macos' when this action runs on macOS."
|
||||||
[[ "$GODOT_DOTNET" == "true" || "$GODOT_DOTNET" == "false" ]] || fail "dotnet must be 'true' or 'false'."
|
[[ "$GODOT_DOTNET" == "true" || "$GODOT_DOTNET" == "false" ]] || fail "dotnet must be 'true' or 'false'."
|
||||||
[[ "$GODOT_EXPORT_MODE" == "release" || "$GODOT_EXPORT_MODE" == "debug" ]] || fail "export-mode must be 'release' or 'debug'."
|
[[ "$GODOT_EXPORT_MODE" == "release" || "$GODOT_EXPORT_MODE" == "debug" ]] || fail "export-mode must be 'release' or 'debug'."
|
||||||
@@ -33,16 +33,23 @@ actual_architecture() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
release_asset_checksum() {
|
||||||
|
local asset="$1"
|
||||||
|
local sum_file="$2"
|
||||||
|
local expected
|
||||||
|
|
||||||
|
expected="$(awk -v asset="$asset" '$2 == asset || $2 == "*" asset { print $1; exit }' "$sum_file")"
|
||||||
|
[[ -n "$expected" ]] || fail "Godot $GODOT_VERSION does not publish required $EDITION asset '$asset' for macOS/$GODOT_HOST_ARCH at $BASE_URL. Choose a supported stable release and architecture."
|
||||||
|
printf '%s\n' "$expected"
|
||||||
|
}
|
||||||
|
|
||||||
download_and_verify() {
|
download_and_verify() {
|
||||||
local asset="$1"
|
local asset="$1"
|
||||||
local destination="$2"
|
local destination="$2"
|
||||||
local sum_file="$3"
|
local expected="$3"
|
||||||
local expected
|
|
||||||
local actual
|
local actual
|
||||||
|
|
||||||
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/$asset" --output "$destination"
|
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/$asset" --output "$destination"
|
||||||
expected="$(awk -v asset="$asset" '$2 == asset || $2 == "*" asset { print $1; exit }' "$sum_file")"
|
|
||||||
[[ -n "$expected" ]] || fail "Release checksum manifest does not contain $asset."
|
|
||||||
actual="$(shasum -a 512 "$destination" | awk '{ print $1 }')"
|
actual="$(shasum -a 512 "$destination" | awk '{ print $1 }')"
|
||||||
[[ "$actual" == "$expected" ]] || fail "SHA-512 verification failed for $asset."
|
[[ "$actual" == "$expected" ]] || fail "SHA-512 verification failed for $asset."
|
||||||
}
|
}
|
||||||
@@ -51,18 +58,39 @@ find_editor() {
|
|||||||
find "$EDITOR_DIR" -type f -path '*.app/Contents/MacOS/*' -name 'Godot*' -print -quit
|
find "$EDITOR_DIR" -type f -path '*.app/Contents/MacOS/*' -name 'Godot*' -print -quit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_export_templates() {
|
||||||
|
local staging_directory="$1"
|
||||||
|
local staged_templates="$staging_directory/templates"
|
||||||
|
local staged_version="$staged_templates/version.txt"
|
||||||
|
local actual_template_version
|
||||||
|
|
||||||
|
[[ -f "$staged_version" ]] || fail "The export-template archive '$TEMPLATES_ASSET' did not contain templates/version.txt."
|
||||||
|
actual_template_version="$(tr -d '\r\n' < "$staged_version")"
|
||||||
|
[[ "$actual_template_version" == "$TEMPLATE_VERSION" ]] || fail "The export-template archive '$TEMPLATES_ASSET' reports template version '$actual_template_version', expected '$TEMPLATE_VERSION'."
|
||||||
|
mkdir -p "$TEMPLATE_DIR"
|
||||||
|
cp -R "$staged_templates/." "$TEMPLATE_DIR/"
|
||||||
|
rm -rf "$staging_directory"
|
||||||
|
[[ -f "$TEMPLATE_DIR/version.txt" ]] || fail "The export-template archive '$TEMPLATES_ASSET' could not be installed to '$TEMPLATE_DIR'."
|
||||||
|
}
|
||||||
|
|
||||||
install_godot() {
|
install_godot() {
|
||||||
local sum_file="$CACHE_DIR/SHA512-SUMS.txt"
|
local sum_file="$CACHE_DIR/SHA512-SUMS.txt"
|
||||||
local editor_archive="$CACHE_DIR/$EDITOR_ASSET"
|
local editor_archive="$CACHE_DIR/$EDITOR_ASSET"
|
||||||
local templates_archive="$CACHE_DIR/$TEMPLATES_ASSET"
|
local templates_archive="$CACHE_DIR/$TEMPLATES_ASSET"
|
||||||
|
local templates_staging_directory="$CACHE_DIR/templates-staging"
|
||||||
|
local editor_checksum
|
||||||
|
local templates_checksum
|
||||||
|
|
||||||
rm -rf "$CACHE_DIR"
|
rm -rf "$CACHE_DIR"
|
||||||
mkdir -p "$EDITOR_DIR" "$TEMPLATE_DIR"
|
mkdir -p "$EDITOR_DIR"
|
||||||
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/SHA512-SUMS.txt" --output "$sum_file"
|
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/SHA512-SUMS.txt" --output "$sum_file"
|
||||||
download_and_verify "$EDITOR_ASSET" "$editor_archive" "$sum_file"
|
editor_checksum="$(release_asset_checksum "$EDITOR_ASSET" "$sum_file")"
|
||||||
download_and_verify "$TEMPLATES_ASSET" "$templates_archive" "$sum_file"
|
templates_checksum="$(release_asset_checksum "$TEMPLATES_ASSET" "$sum_file")"
|
||||||
|
download_and_verify "$EDITOR_ASSET" "$editor_archive" "$editor_checksum"
|
||||||
|
download_and_verify "$TEMPLATES_ASSET" "$templates_archive" "$templates_checksum"
|
||||||
unzip -q "$editor_archive" -d "$EDITOR_DIR"
|
unzip -q "$editor_archive" -d "$EDITOR_DIR"
|
||||||
unzip -q "$templates_archive" -d "$TEMPLATE_DIR"
|
unzip -q "$templates_archive" -d "$templates_staging_directory"
|
||||||
|
install_export_templates "$templates_staging_directory"
|
||||||
EDITOR_EXECUTABLE="$(find_editor)"
|
EDITOR_EXECUTABLE="$(find_editor)"
|
||||||
[[ -n "$EDITOR_EXECUTABLE" ]] || fail "The Godot editor archive did not contain a macOS app executable."
|
[[ -n "$EDITOR_EXECUTABLE" ]] || fail "The Godot editor archive did not contain a macOS app executable."
|
||||||
[[ -f "$TEMPLATE_DIR/version.txt" ]] || fail "The export-template archive did not contain version.txt."
|
[[ -f "$TEMPLATE_DIR/version.txt" ]] || fail "The export-template archive did not contain version.txt."
|
||||||
@@ -105,14 +133,15 @@ if [[ "$GODOT_DOTNET" == "true" ]]; then
|
|||||||
EDITION=dotnet
|
EDITION=dotnet
|
||||||
EDITOR_ASSET="Godot_v${GODOT_VERSION}_mono_macos.universal.zip"
|
EDITOR_ASSET="Godot_v${GODOT_VERSION}_mono_macos.universal.zip"
|
||||||
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_mono_export_templates.tpz"
|
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_mono_export_templates.tpz"
|
||||||
|
TEMPLATE_VERSION="${GODOT_VERSION//-/.}.mono"
|
||||||
else
|
else
|
||||||
EDITION=standard
|
EDITION=standard
|
||||||
EDITOR_ASSET="Godot_v${GODOT_VERSION}_macos.universal.zip"
|
EDITOR_ASSET="Godot_v${GODOT_VERSION}_macos.universal.zip"
|
||||||
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_export_templates.tpz"
|
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_export_templates.tpz"
|
||||||
|
TEMPLATE_VERSION="${GODOT_VERSION//-/.}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BASE_URL="https://github.com/godotengine/godot-builds/releases/download/$GODOT_VERSION"
|
BASE_URL="https://github.com/godotengine/godot/releases/download/$GODOT_VERSION"
|
||||||
TEMPLATE_VERSION="${GODOT_VERSION//-/.}"
|
|
||||||
CACHE_DIR="$GODOT_ACTION_ROOT/cache/$GODOT_VERSION/$EDITION/macos-$GODOT_HOST_ARCH"
|
CACHE_DIR="$GODOT_ACTION_ROOT/cache/$GODOT_VERSION/$EDITION/macos-$GODOT_HOST_ARCH"
|
||||||
EDITOR_DIR="$CACHE_DIR/editor"
|
EDITOR_DIR="$CACHE_DIR/editor"
|
||||||
USER_HOME="$CACHE_DIR/home"
|
USER_HOME="$CACHE_DIR/home"
|
||||||
|
|||||||
+273
-81
@@ -1,11 +1,16 @@
|
|||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param()
|
param(
|
||||||
|
[switch]$SkipExecution
|
||||||
|
)
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
Set-StrictMode -Version Latest
|
||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
function Fail([string]$Message) {
|
function Fail([string]$Message) {
|
||||||
Write-Error "::error::$Message"
|
Write-Host "::error::$Message"
|
||||||
|
if ($SkipExecution) {
|
||||||
|
throw $Message
|
||||||
|
}
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,11 +22,28 @@ function Require-Environment([string]$Name) {
|
|||||||
return $value
|
return $value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Test-PathIsWithinDirectory([string]$ParentDirectory, [string]$CandidateDirectory) {
|
||||||
|
$parentPath = [IO.Path]::GetFullPath($ParentDirectory)
|
||||||
|
$candidatePath = [IO.Path]::GetFullPath($CandidateDirectory)
|
||||||
|
$separator = [IO.Path]::DirectorySeparatorChar.ToString()
|
||||||
|
|
||||||
|
if ($candidatePath.Equals($parentPath, [StringComparison]::OrdinalIgnoreCase)) {
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $parentPath.EndsWith($separator)) {
|
||||||
|
$parentPath += $separator
|
||||||
|
}
|
||||||
|
|
||||||
|
return $candidatePath.StartsWith($parentPath, [StringComparison]::OrdinalIgnoreCase)
|
||||||
|
}
|
||||||
|
|
||||||
function Get-ActualArchitecture {
|
function Get-ActualArchitecture {
|
||||||
$architecture = $env:PROCESSOR_ARCHITEW6432
|
$architecture = $env:PROCESSOR_ARCHITEW6432
|
||||||
if ([string]::IsNullOrWhiteSpace($architecture)) {
|
if ([string]::IsNullOrWhiteSpace($architecture)) {
|
||||||
$architecture = $env:PROCESSOR_ARCHITECTURE
|
$architecture = $env:PROCESSOR_ARCHITECTURE
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($architecture.ToUpperInvariant()) {
|
switch ($architecture.ToUpperInvariant()) {
|
||||||
'AMD64' { return 'x86_64' }
|
'AMD64' { return 'x86_64' }
|
||||||
'X86' { return 'x86_32' }
|
'X86' { return 'x86_32' }
|
||||||
@@ -30,33 +52,227 @@ function Get-ActualArchitecture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-Checksum([string]$ManifestPath, [string]$Asset) {
|
function Get-GodotAssets([string]$Version, [string]$Dotnet, [string]$Architecture) {
|
||||||
$line = Get-Content -LiteralPath $ManifestPath | Where-Object {
|
if ($Dotnet -eq 'true') {
|
||||||
$_ -match '^([0-9A-Fa-f]{128})\s+\*?(.+)$' -and $Matches[2] -eq $Asset
|
$edition = 'dotnet'
|
||||||
} | Select-Object -First 1
|
$editorBaseName = switch ($Architecture) {
|
||||||
if (-not $line) {
|
'x86_32' { "Godot_v${Version}_mono_win32" }
|
||||||
Fail "Release checksum manifest does not contain $Asset."
|
'x86_64' { "Godot_v${Version}_mono_win64" }
|
||||||
}
|
'arm64' { "Godot_v${Version}_mono_windows_arm64" }
|
||||||
return ($line -split '\s+')[0].ToLowerInvariant()
|
default { Fail "Unsupported Windows host-arch '$Architecture'." }
|
||||||
}
|
}
|
||||||
|
|
||||||
function Download-AndVerify([string]$Asset, [string]$Destination, [string]$ManifestPath) {
|
return [PSCustomObject]@{
|
||||||
Invoke-WebRequest -Uri "$script:BaseUrl/$Asset" -OutFile $Destination
|
Edition = $edition
|
||||||
$expected = Get-Checksum $ManifestPath $Asset
|
EditorAsset = "$editorBaseName.zip"
|
||||||
$actual = (Get-FileHash -LiteralPath $Destination -Algorithm SHA512).Hash.ToLowerInvariant()
|
EditorFileName = "${editorBaseName}_console.exe"
|
||||||
if ($actual -ne $expected) {
|
TemplatesAsset = "Godot_v${Version}_mono_export_templates.tpz"
|
||||||
Fail "SHA-512 verification failed for $Asset."
|
TemplateVersion = ($Version -replace '-', '.') + '.mono'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$edition = 'standard'
|
||||||
|
$editorBaseName = switch ($Architecture) {
|
||||||
|
'x86_32' { "Godot_v${Version}_win32" }
|
||||||
|
'x86_64' { "Godot_v${Version}_win64" }
|
||||||
|
'arm64' { "Godot_v${Version}_windows_arm64" }
|
||||||
|
default { Fail "Unsupported Windows host-arch '$Architecture'." }
|
||||||
|
}
|
||||||
|
|
||||||
|
return [PSCustomObject]@{
|
||||||
|
Edition = $edition
|
||||||
|
EditorAsset = "${editorBaseName}.exe.zip"
|
||||||
|
EditorFileName = "${editorBaseName}_console.exe"
|
||||||
|
TemplatesAsset = "Godot_v${Version}_export_templates.tpz"
|
||||||
|
TemplateVersion = $Version -replace '-', '.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Find-Editor([string]$Directory) {
|
function Get-ExpectedPeMachine([string]$Architecture) {
|
||||||
$console = Get-ChildItem -LiteralPath $Directory -Recurse -File -Filter 'Godot*console.exe' -ErrorAction SilentlyContinue | Select-Object -First 1
|
switch ($Architecture) {
|
||||||
if ($console) { return $console.FullName }
|
'x86_32' { return [uint16]0x014c }
|
||||||
$editor = Get-ChildItem -LiteralPath $Directory -Recurse -File -Filter 'Godot*.exe' -ErrorAction SilentlyContinue | Select-Object -First 1
|
'x86_64' { return [uint16]0x8664 }
|
||||||
if ($editor) { return $editor.FullName }
|
'arm64' { return [uint16]0xaa64 }
|
||||||
|
default { Fail "Unsupported Windows host-arch '$Architecture'." }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-Checksum([string]$ManifestPath, [string]$Asset, [string]$Version, [string]$Edition, [string]$Architecture, [string]$BaseUrl) {
|
||||||
|
foreach ($line in Get-Content -LiteralPath $ManifestPath) {
|
||||||
|
if ($line -match '^([0-9A-Fa-f]{128})\s+\*?(.+)$' -and $Matches[2] -eq $Asset) {
|
||||||
|
return $Matches[1].ToLowerInvariant()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Fail "Godot $Version does not publish required $Edition asset '$Asset' for Windows/$Architecture at $BaseUrl. Choose a supported stable release and architecture."
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Download([string]$Uri, [string]$Destination) {
|
||||||
|
$lastError = $null
|
||||||
|
for ($attempt = 1; $attempt -le 3; $attempt++) {
|
||||||
|
try {
|
||||||
|
Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $Destination
|
||||||
|
$lastError = $null
|
||||||
|
break
|
||||||
|
} catch {
|
||||||
|
$lastError = $_
|
||||||
|
if (Test-Path -LiteralPath $Destination) {
|
||||||
|
Remove-Item -LiteralPath $Destination -Force
|
||||||
|
}
|
||||||
|
if ($attempt -lt 3) {
|
||||||
|
Start-Sleep -Seconds $attempt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($null -ne $lastError) {
|
||||||
|
Fail "Failed to download '$Uri' after 3 attempts: $($lastError.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-VerifiedDownload([string]$Uri, [string]$Destination, [string]$ExpectedChecksum) {
|
||||||
|
Invoke-Download $Uri $Destination
|
||||||
|
$actualChecksum = (Get-FileHash -LiteralPath $Destination -Algorithm SHA512).Hash.ToLowerInvariant()
|
||||||
|
if ($actualChecksum -ne $ExpectedChecksum) {
|
||||||
|
Fail "SHA-512 verification failed for $(Split-Path -Leaf $Destination)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-CachePaths([string]$Root, [string]$TemplateVersion) {
|
||||||
|
$editorDirectory = Join-Path $Root 'editor'
|
||||||
|
$userHome = Join-Path $Root 'home'
|
||||||
|
return [PSCustomObject]@{
|
||||||
|
Root = $Root
|
||||||
|
EditorDirectory = $editorDirectory
|
||||||
|
UserHome = $userHome
|
||||||
|
TemplateDirectory = Join-Path $userHome "AppData\Roaming\Godot\export_templates\$TemplateVersion"
|
||||||
|
Marker = Join-Path $Root '.complete'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-EditorExecutable([string]$EditorDirectory, [string]$ExpectedFileName) {
|
||||||
|
$matches = @(Get-ChildItem -LiteralPath $EditorDirectory -Recurse -File -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.Name -eq $ExpectedFileName })
|
||||||
|
if ($matches.Count -eq 1) {
|
||||||
|
return $matches[0].FullName
|
||||||
|
}
|
||||||
return $null
|
return $null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Get-PeMachine([string]$Path) {
|
||||||
|
try {
|
||||||
|
$stream = [IO.File]::Open($Path, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::Read)
|
||||||
|
try {
|
||||||
|
if ($stream.Length -lt 64) { return $null }
|
||||||
|
$header = New-Object byte[] 64
|
||||||
|
if ($stream.Read($header, 0, $header.Length) -ne $header.Length -or $header[0] -ne 0x4d -or $header[1] -ne 0x5a) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$peOffset = [BitConverter]::ToInt32($header, 0x3c)
|
||||||
|
if ($peOffset -lt 0 -or ($peOffset + 6) -gt $stream.Length) { return $null }
|
||||||
|
$stream.Position = $peOffset
|
||||||
|
$signature = New-Object byte[] 6
|
||||||
|
if ($stream.Read($signature, 0, $signature.Length) -ne $signature.Length) { return $null }
|
||||||
|
if ($signature[0] -ne 0x50 -or $signature[1] -ne 0x45 -or $signature[2] -ne 0 -or $signature[3] -ne 0) { return $null }
|
||||||
|
return [BitConverter]::ToUInt16($signature, 4)
|
||||||
|
} finally {
|
||||||
|
$stream.Dispose()
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-ExpectedEditor([string]$EditorDirectory, [string]$ExpectedFileName, [uint16]$ExpectedMachine) {
|
||||||
|
$editorExecutable = Get-EditorExecutable $EditorDirectory $ExpectedFileName
|
||||||
|
return $null -ne $editorExecutable -and (Get-PeMachine $editorExecutable) -eq $ExpectedMachine
|
||||||
|
}
|
||||||
|
|
||||||
|
function Assert-ExpectedEditor([string]$EditorDirectory, [string]$ExpectedFileName, [uint16]$ExpectedMachine, [string]$Architecture) {
|
||||||
|
$editorExecutable = Get-EditorExecutable $EditorDirectory $ExpectedFileName
|
||||||
|
if ($null -eq $editorExecutable) {
|
||||||
|
Fail "The Godot editor archive did not contain the expected console executable '$ExpectedFileName'."
|
||||||
|
}
|
||||||
|
if ((Get-PeMachine $editorExecutable) -ne $ExpectedMachine) {
|
||||||
|
Fail "The expected Godot console executable '$ExpectedFileName' is not a valid $Architecture Windows executable."
|
||||||
|
}
|
||||||
|
return $editorExecutable
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-ValidCache($Paths, [string]$TemplateVersion, [string]$ExpectedFileName, [uint16]$ExpectedMachine) {
|
||||||
|
if (-not (Test-Path -LiteralPath $Paths.Marker -PathType Leaf)) { return $false }
|
||||||
|
$installedVersion = Join-Path $Paths.TemplateDirectory 'version.txt'
|
||||||
|
if (-not (Test-Path -LiteralPath $installedVersion -PathType Leaf)) { return $false }
|
||||||
|
if ((Get-Content -LiteralPath $installedVersion -Raw).Trim() -ne $TemplateVersion) { return $false }
|
||||||
|
return Test-ExpectedEditor $Paths.EditorDirectory $ExpectedFileName $ExpectedMachine
|
||||||
|
}
|
||||||
|
|
||||||
|
function Install-ExportTemplates($Paths, [string]$StagingDirectory, [string]$TemplateAsset, [string]$TemplateVersion) {
|
||||||
|
$stagedTemplates = Join-Path $StagingDirectory 'templates'
|
||||||
|
$stagedVersion = Join-Path $stagedTemplates 'version.txt'
|
||||||
|
if (-not (Test-Path -LiteralPath $stagedVersion -PathType Leaf)) {
|
||||||
|
Fail "The export-template archive '$TemplateAsset' did not contain templates/version.txt."
|
||||||
|
}
|
||||||
|
if ((Get-Content -LiteralPath $stagedVersion -Raw).Trim() -ne $TemplateVersion) {
|
||||||
|
Fail "The export-template archive '$TemplateAsset' reports template version '$((Get-Content -LiteralPath $stagedVersion -Raw).Trim())', expected '$TemplateVersion'."
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Force -Path $Paths.TemplateDirectory | Out-Null
|
||||||
|
Get-ChildItem -LiteralPath $stagedTemplates -Force | Copy-Item -Destination $Paths.TemplateDirectory -Recurse -Force
|
||||||
|
if (-not (Test-Path -LiteralPath (Join-Path $Paths.TemplateDirectory 'version.txt') -PathType Leaf)) {
|
||||||
|
Fail "The export-template archive '$TemplateAsset' could not be installed to '$($Paths.TemplateDirectory)'."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Install-GodotCache($Paths, $Assets, [uint16]$ExpectedMachine, [string]$Architecture, [string]$Version, [string]$BaseUrl) {
|
||||||
|
New-Item -ItemType Directory -Force -Path $Paths.EditorDirectory | Out-Null
|
||||||
|
$manifestPath = Join-Path $Paths.Root 'SHA512-SUMS.txt'
|
||||||
|
$editorArchive = Join-Path $Paths.Root $Assets.EditorAsset
|
||||||
|
$templatesArchive = Join-Path $Paths.Root $Assets.TemplatesAsset
|
||||||
|
$templatesZipArchive = Join-Path $Paths.Root 'export-templates.zip'
|
||||||
|
$templatesStagingDirectory = Join-Path $Paths.Root 'templates-staging'
|
||||||
|
|
||||||
|
Invoke-Download "$BaseUrl/SHA512-SUMS.txt" $manifestPath
|
||||||
|
$editorChecksum = Get-Checksum $manifestPath $Assets.EditorAsset $Version $Assets.Edition $Architecture $BaseUrl
|
||||||
|
$templatesChecksum = Get-Checksum $manifestPath $Assets.TemplatesAsset $Version $Assets.Edition $Architecture $BaseUrl
|
||||||
|
Invoke-VerifiedDownload "$BaseUrl/$($Assets.EditorAsset)" $editorArchive $editorChecksum
|
||||||
|
Invoke-VerifiedDownload "$BaseUrl/$($Assets.TemplatesAsset)" $templatesArchive $templatesChecksum
|
||||||
|
|
||||||
|
Expand-Archive -LiteralPath $editorArchive -DestinationPath $Paths.EditorDirectory -Force
|
||||||
|
Assert-ExpectedEditor $Paths.EditorDirectory $Assets.EditorFileName $ExpectedMachine $Architecture | Out-Null
|
||||||
|
|
||||||
|
# Expand-Archive recognizes .zip only; Godot's verified .tpz payload is a ZIP archive.
|
||||||
|
Copy-Item -LiteralPath $templatesArchive -Destination $templatesZipArchive -Force
|
||||||
|
Expand-Archive -LiteralPath $templatesZipArchive -DestinationPath $templatesStagingDirectory -Force
|
||||||
|
Install-ExportTemplates $Paths $templatesStagingDirectory $Assets.TemplatesAsset $Assets.TemplateVersion
|
||||||
|
Remove-Item -LiteralPath $templatesStagingDirectory -Recurse -Force
|
||||||
|
|
||||||
|
@("release=$Version", "editor=$($Assets.EditorAsset)", "templates=$($Assets.TemplatesAsset)") |
|
||||||
|
Set-Content -LiteralPath $Paths.Marker -NoNewline -Encoding ASCII
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-GodotExport([string]$EditorExecutable, [string]$ProjectDirectory, [string]$ExportMode, [string]$ExportPreset, [string]$OutputFile, [scriptblock]$EditorRunner) {
|
||||||
|
try {
|
||||||
|
if ($null -ne $EditorRunner) {
|
||||||
|
& $EditorRunner $EditorExecutable $ProjectDirectory $ExportMode $ExportPreset $OutputFile
|
||||||
|
} else {
|
||||||
|
& $EditorExecutable --headless --path $ProjectDirectory "--export-$ExportMode" $ExportPreset $OutputFile
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Fail "Godot could not start '$EditorExecutable': $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Fail "Godot export failed with exit code $LASTEXITCODE."
|
||||||
|
}
|
||||||
|
if (-not (Test-Path -LiteralPath $OutputFile -PathType Leaf)) {
|
||||||
|
Fail "Godot completed without creating the expected output '$(Split-Path -Leaf $OutputFile)'."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($SkipExecution) { return }
|
||||||
|
|
||||||
$GodotVersion = Require-Environment 'GODOT_VERSION'
|
$GodotVersion = Require-Environment 'GODOT_VERSION'
|
||||||
$HostOs = Require-Environment 'GODOT_HOST_OS'
|
$HostOs = Require-Environment 'GODOT_HOST_OS'
|
||||||
$HostArch = Require-Environment 'GODOT_HOST_ARCH'
|
$HostArch = Require-Environment 'GODOT_HOST_ARCH'
|
||||||
@@ -69,84 +285,60 @@ $ActionRoot = Require-Environment 'GODOT_ACTION_ROOT'
|
|||||||
$Workspace = Require-Environment 'GITHUB_WORKSPACE'
|
$Workspace = Require-Environment 'GITHUB_WORKSPACE'
|
||||||
$GithubOutput = Require-Environment 'GITHUB_OUTPUT'
|
$GithubOutput = Require-Environment 'GITHUB_OUTPUT'
|
||||||
|
|
||||||
if ($GodotVersion -notmatch '^4(\.[0-9]+){1,2}(-[0-9A-Za-z][0-9A-Za-z._-]*)?$') { Fail 'godot-version must be a Godot 4 release tag such as 4.7.2-stable.' }
|
if ($GodotVersion -notmatch '^4(\.[0-9]+){1,2}-stable$') { Fail 'godot-version must be a stable Godot 4 tag such as 4.7.2-stable. Alpha, beta, RC, and dev tags are not supported.' }
|
||||||
if ($HostOs -ne 'windows') { Fail "host-os must be 'windows' when this action runs on Windows." }
|
if ($HostOs -ne 'windows') { Fail "host-os must be 'windows' when this action runs on Windows." }
|
||||||
if ($Dotnet -notin @('true', 'false')) { Fail "dotnet must be 'true' or 'false'." }
|
if ($Dotnet -notin @('true', 'false')) { Fail "dotnet must be 'true' or 'false'." }
|
||||||
if ($ExportMode -notin @('release', 'debug')) { Fail "export-mode must be 'release' or 'debug'." }
|
if ($ExportMode -notin @('release', 'debug')) { Fail "export-mode must be 'release' or 'debug'." }
|
||||||
if ([string]::IsNullOrWhiteSpace($ExportPreset)) { Fail 'export-preset must not be empty.' }
|
if ([string]::IsNullOrWhiteSpace($ExportPreset)) { Fail 'export-preset must not be empty.' }
|
||||||
if ([string]::IsNullOrWhiteSpace($ExportFileName) -or $ExportFileName -in @('.', '..') -or $ExportFileName.IndexOfAny([IO.Path]::GetInvalidFileNameChars()) -ge 0 -or $ExportFileName.Contains('/') -or $ExportFileName.Contains('\')) { Fail 'export-file-name must be a filename without path separators.' }
|
if ([string]::IsNullOrWhiteSpace($ExportFileName) -or $ExportFileName -in @('.', '..') -or $ExportFileName.IndexOfAny([IO.Path]::GetInvalidFileNameChars()) -ge 0 -or $ExportFileName.Contains('/') -or $ExportFileName.Contains('\')) { Fail 'export-file-name must be a filename without path separators.' }
|
||||||
if ($HostArch -notin @('x86_32', 'x86_64', 'arm64')) { Fail "Unsupported Windows host-arch '$HostArch'." }
|
if ($HostArch -notin @('x86_32', 'x86_64', 'arm64')) { Fail "Unsupported Windows host-arch '$HostArch'." }
|
||||||
if ($HostArch -ne (Get-ActualArchitecture)) { Fail "host-arch '$HostArch' does not match this Windows runner ($(Get-ActualArchitecture))." }
|
|
||||||
|
$actualArchitecture = Get-ActualArchitecture
|
||||||
|
if ($HostArch -ne $actualArchitecture) { Fail "host-arch '$HostArch' does not match this Windows runner ($actualArchitecture)." }
|
||||||
|
|
||||||
$workspaceDirectory = [IO.Path]::GetFullPath($Workspace)
|
$workspaceDirectory = [IO.Path]::GetFullPath($Workspace)
|
||||||
if ([IO.Path]::IsPathRooted($ProjectPath)) { Fail 'project-path must be relative to the checked-out workspace.' }
|
if ([IO.Path]::IsPathRooted($ProjectPath)) { Fail 'project-path must be relative to the checked-out workspace.' }
|
||||||
$ProjectDirectory = [IO.Path]::GetFullPath((Join-Path $workspaceDirectory $ProjectPath))
|
$ProjectDirectory = [IO.Path]::GetFullPath((Join-Path $workspaceDirectory $ProjectPath))
|
||||||
$projectRelativePath = [IO.Path]::GetRelativePath($workspaceDirectory, $ProjectDirectory)
|
if (-not (Test-PathIsWithinDirectory $workspaceDirectory $ProjectDirectory)) { Fail 'project-path must remain inside the checked-out workspace.' }
|
||||||
if ($projectRelativePath -eq '..' -or $projectRelativePath.StartsWith("..$([IO.Path]::DirectorySeparatorChar)") -or [IO.Path]::IsPathRooted($projectRelativePath)) { Fail 'project-path must remain inside the checked-out workspace.' }
|
if (-not (Test-Path -LiteralPath $ProjectDirectory -PathType Container)) { Fail "project-path '$ProjectPath' does not exist." }
|
||||||
if (-not (Test-Path -LiteralPath (Join-Path $ProjectDirectory 'project.godot') -PathType Leaf)) { Fail "No project.godot was found in project-path '$ProjectPath'." }
|
if (-not (Test-Path -LiteralPath (Join-Path $ProjectDirectory 'project.godot') -PathType Leaf)) { Fail "No project.godot was found in project-path '$ProjectPath'." }
|
||||||
$PresetFile = Join-Path $ProjectDirectory 'export_presets.cfg'
|
$presetFile = Join-Path $ProjectDirectory 'export_presets.cfg'
|
||||||
if (-not (Test-Path -LiteralPath $PresetFile -PathType Leaf)) { Fail "No export_presets.cfg was found in project-path '$ProjectPath'." }
|
if (-not (Test-Path -LiteralPath $presetFile -PathType Leaf)) { Fail "No export_presets.cfg was found in project-path '$ProjectPath'." }
|
||||||
if (-not (Select-String -LiteralPath $PresetFile -SimpleMatch "name=`"$ExportPreset`"" -Quiet)) { Fail "Export preset '$ExportPreset' was not found in export_presets.cfg." }
|
if (-not (Select-String -LiteralPath $presetFile -SimpleMatch "name=`"$ExportPreset`"" -Quiet)) { Fail "Export preset '$ExportPreset' was not found in export_presets.cfg." }
|
||||||
|
|
||||||
if ($Dotnet -eq 'true') {
|
$assets = Get-GodotAssets $GodotVersion $Dotnet $HostArch
|
||||||
$edition = 'dotnet'
|
$expectedMachine = Get-ExpectedPeMachine $HostArch
|
||||||
$editorAsset = switch ($HostArch) {
|
$baseUrl = "https://github.com/godotengine/godot/releases/download/$GodotVersion"
|
||||||
'x86_32' { "Godot_v${GodotVersion}_mono_win32.zip" }
|
$cacheDirectory = Join-Path $ActionRoot "cache\$GodotVersion\$($assets.Edition)\windows-$HostArch"
|
||||||
'x86_64' { "Godot_v${GodotVersion}_mono_win64.zip" }
|
$cachePaths = Get-CachePaths $cacheDirectory $assets.TemplateVersion
|
||||||
'arm64' { "Godot_v${GodotVersion}_mono_windows_arm64.zip" }
|
|
||||||
|
if (-not (Test-ValidCache $cachePaths $assets.TemplateVersion $assets.EditorFileName $expectedMachine)) {
|
||||||
|
$cacheParent = Split-Path -Parent $cacheDirectory
|
||||||
|
$stagingDirectory = Join-Path $cacheParent ((Split-Path -Leaf $cacheDirectory) + ".staging-$PID")
|
||||||
|
if (Test-Path -LiteralPath $stagingDirectory) { Remove-Item -LiteralPath $stagingDirectory -Recurse -Force }
|
||||||
|
New-Item -ItemType Directory -Force -Path $cacheParent | Out-Null
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stagingPaths = Get-CachePaths $stagingDirectory $assets.TemplateVersion
|
||||||
|
Install-GodotCache $stagingPaths $assets $expectedMachine $HostArch $GodotVersion $baseUrl
|
||||||
|
if (-not (Test-ValidCache $stagingPaths $assets.TemplateVersion $assets.EditorFileName $expectedMachine)) { Fail 'Godot cache installation did not pass validation.' }
|
||||||
|
if (Test-Path -LiteralPath $cacheDirectory) { Remove-Item -LiteralPath $cacheDirectory -Recurse -Force }
|
||||||
|
Move-Item -LiteralPath $stagingDirectory -Destination $cacheDirectory
|
||||||
|
} finally {
|
||||||
|
if (Test-Path -LiteralPath $stagingDirectory) { Remove-Item -LiteralPath $stagingDirectory -Recurse -Force }
|
||||||
}
|
}
|
||||||
$templatesAsset = "Godot_v${GodotVersion}_mono_export_templates.tpz"
|
|
||||||
} else {
|
|
||||||
$edition = 'standard'
|
|
||||||
$editorAsset = switch ($HostArch) {
|
|
||||||
'x86_32' { "Godot_v${GodotVersion}_win32.exe.zip" }
|
|
||||||
'x86_64' { "Godot_v${GodotVersion}_win64.exe.zip" }
|
|
||||||
'arm64' { "Godot_v${GodotVersion}_windows_arm64.exe.zip" }
|
|
||||||
}
|
|
||||||
$templatesAsset = "Godot_v${GodotVersion}_export_templates.tpz"
|
|
||||||
}
|
|
||||||
|
|
||||||
$script:BaseUrl = "https://github.com/godotengine/godot-builds/releases/download/$GodotVersion"
|
|
||||||
$templateVersion = $GodotVersion -replace '-', '.'
|
|
||||||
$cacheDirectory = Join-Path $ActionRoot "cache\$GodotVersion\$edition\windows-$HostArch"
|
|
||||||
$editorDirectory = Join-Path $cacheDirectory 'editor'
|
|
||||||
$userHome = Join-Path $cacheDirectory 'home'
|
|
||||||
$templateDirectory = Join-Path $userHome "AppData\Roaming\Godot\export_templates\$templateVersion"
|
|
||||||
$marker = Join-Path $cacheDirectory '.complete'
|
|
||||||
|
|
||||||
$editorExecutable = $null
|
|
||||||
if ((Test-Path -LiteralPath $marker -PathType Leaf) -and (Test-Path -LiteralPath (Join-Path $templateDirectory 'version.txt') -PathType Leaf)) {
|
|
||||||
$editorExecutable = Find-Editor $editorDirectory
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-not $editorExecutable) {
|
|
||||||
if (Test-Path -LiteralPath $cacheDirectory) { Remove-Item -LiteralPath $cacheDirectory -Recurse -Force }
|
|
||||||
New-Item -ItemType Directory -Force -Path $editorDirectory, $templateDirectory | Out-Null
|
|
||||||
$manifestPath = Join-Path $cacheDirectory 'SHA512-SUMS.txt'
|
|
||||||
$editorArchive = Join-Path $cacheDirectory $editorAsset
|
|
||||||
$templatesArchive = Join-Path $cacheDirectory $templatesAsset
|
|
||||||
Invoke-WebRequest -Uri "$script:BaseUrl/SHA512-SUMS.txt" -OutFile $manifestPath
|
|
||||||
Download-AndVerify $editorAsset $editorArchive $manifestPath
|
|
||||||
Download-AndVerify $templatesAsset $templatesArchive $manifestPath
|
|
||||||
Expand-Archive -LiteralPath $editorArchive -DestinationPath $editorDirectory -Force
|
|
||||||
Expand-Archive -LiteralPath $templatesArchive -DestinationPath $templateDirectory -Force
|
|
||||||
$editorExecutable = Find-Editor $editorDirectory
|
|
||||||
if (-not $editorExecutable) { Fail 'The Godot editor archive did not contain an executable.' }
|
|
||||||
if (-not (Test-Path -LiteralPath (Join-Path $templateDirectory 'version.txt') -PathType Leaf)) { Fail 'The export-template archive did not contain version.txt.' }
|
|
||||||
@("release=$GodotVersion", "editor=$editorAsset", "templates=$templatesAsset") | Set-Content -LiteralPath $marker -NoNewline
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$editorExecutable = Assert-ExpectedEditor $cachePaths.EditorDirectory $assets.EditorFileName $expectedMachine $HostArch
|
||||||
$safePreset = ($ExportPreset -replace '[^A-Za-z0-9_.-]', '_').Trim('_')
|
$safePreset = ($ExportPreset -replace '[^A-Za-z0-9_.-]', '_').Trim('_')
|
||||||
if ([string]::IsNullOrWhiteSpace($safePreset)) { $safePreset = 'export' }
|
if ([string]::IsNullOrWhiteSpace($safePreset)) { $safePreset = 'export' }
|
||||||
$buildDirectory = Join-Path $ActionRoot "builds\$safePreset-$ExportMode-$PID"
|
$buildDirectory = Join-Path $ActionRoot "builds\$safePreset-$ExportMode-$PID"
|
||||||
$outputFile = Join-Path $buildDirectory $ExportFileName
|
$outputFile = Join-Path $buildDirectory $ExportFileName
|
||||||
New-Item -ItemType Directory -Force -Path $buildDirectory | Out-Null
|
New-Item -ItemType Directory -Force -Path $buildDirectory | Out-Null
|
||||||
|
|
||||||
$env:USERPROFILE = $userHome
|
$env:USERPROFILE = $cachePaths.UserHome
|
||||||
$env:APPDATA = Join-Path $userHome 'AppData\Roaming'
|
$env:APPDATA = Join-Path $cachePaths.UserHome 'AppData\Roaming'
|
||||||
$env:LOCALAPPDATA = Join-Path $userHome 'AppData\Local'
|
$env:LOCALAPPDATA = Join-Path $cachePaths.UserHome 'AppData\Local'
|
||||||
& $editorExecutable --headless --path $ProjectDirectory "--export-$ExportMode" $ExportPreset $outputFile
|
Invoke-GodotExport $editorExecutable $ProjectDirectory $ExportMode $ExportPreset $outputFile $null
|
||||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
||||||
if (-not (Test-Path -LiteralPath $outputFile)) { Fail "Godot completed without creating the expected output '$ExportFileName'." }
|
|
||||||
|
|
||||||
"build-directory=$buildDirectory" | Add-Content -LiteralPath $GithubOutput
|
"build-directory=$buildDirectory" | Add-Content -LiteralPath $GithubOutput -Encoding ASCII
|
||||||
|
|||||||
Reference in New Issue
Block a user