Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef2f78ff91 | ||
|
|
159e12c79a | ||
|
|
dae0123a17 | ||
|
|
391127c5b9 | ||
|
|
ffba9651c4 | ||
|
|
100a5cebd8 | ||
|
|
415a3886b0 | ||
|
|
992b2184f6 | ||
|
|
4e2ccd975b |
@@ -0,0 +1,8 @@
|
|||||||
|
Copyright 2026 Alexander Loren (omgitsalexl)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Godot 4 export action for Gitea
|
||||||
|
|
||||||
|
This action takes care of the repetitive part of exporting a Godot game in Gitea: getting the right Godot editor, installing its matching export templates, and running one of the presets already in your project.
|
||||||
|
|
||||||
|
It runs directly on the runner you already have. No Docker image is involved, which makes it a good fit for host-based runners on Linux, macOS, and Windows. Once the first build has finished, Godot and its templates are cached so later builds can get straight to exporting.
|
||||||
|
|
||||||
|
## What it builds
|
||||||
|
|
||||||
|
You choose the Godot preset, the build type, and the output filename. The action then puts that build in its own temporary folder and exposes the folder as `build-directory`, ready for an upload or release step.
|
||||||
|
|
||||||
|
The runner's operating system and architecture determine which Godot editor is downloaded. The export preset determines what you are building, so a Linux runner can still export a Windows game when the preset is set up for it.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Add the action after checking out your project. In this example, the Godot project lives in `games/my-game` and exports the `Windows Desktop` preset:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Export game
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
export:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: godot-export
|
||||||
|
uses: https://git.omgitsalexl.me/omgitsalexl/godot-export-action@v1
|
||||||
|
with:
|
||||||
|
godot-version: 4.7.2-stable
|
||||||
|
host-os: linux
|
||||||
|
host-arch: x86_64
|
||||||
|
project-path: games/my-game
|
||||||
|
export-preset: Windows Desktop
|
||||||
|
export-mode: release
|
||||||
|
export-file-name: my-game.exe
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: my-game
|
||||||
|
path: ${{ steps.godot-export.outputs.build-directory }}
|
||||||
|
```
|
||||||
|
|
||||||
|
The uploaded artifact is the whole build folder, so companion files such as a `.pck` file are kept together with the executable.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| Input | Required | Default | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `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-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. |
|
||||||
|
| `project-path` | No | `.` | Where your Godot project sits inside the checked-out repository. |
|
||||||
|
| `export-mode` | No | `debug` | Choose `release` for a shipping build or `debug` for a debug build. |
|
||||||
|
| `cache` | No | `true` | Set to `false` if you need a completely fresh Godot download for a run. |
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
| Output | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `build-directory` | The absolute path to this export's own folder in the runner's temporary directory. |
|
||||||
|
|
||||||
|
## A few helpful notes
|
||||||
|
|
||||||
|
- Your project needs both `project.godot` and `export_presets.cfg`. Preset names with spaces, such as `Windows Desktop`, are fine.
|
||||||
|
- 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.
|
||||||
|
- 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.
|
||||||
|
- The cache step uses `actions/cache@v4.1.0` so it works with Gitea Runner 2.x. That runner generation also needs the Gitea artifact fork instead of the stock artifact action.
|
||||||
+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"
|
||||||
|
|||||||
+210
-56
@@ -17,11 +17,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' }
|
||||||
@@ -31,32 +48,159 @@ function Get-ActualArchitecture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Get-Checksum([string]$ManifestPath, [string]$Asset) {
|
function Get-Checksum([string]$ManifestPath, [string]$Asset) {
|
||||||
$line = Get-Content -LiteralPath $ManifestPath | Where-Object {
|
foreach ($line in Get-Content -LiteralPath $ManifestPath) {
|
||||||
$_ -match '^([0-9A-Fa-f]{128})\s+\*?(.+)$' -and $Matches[2] -eq $Asset
|
if ($line -match '^([0-9A-Fa-f]{128})\s+\*?(.+)$' -and $Matches[2] -eq $Asset) {
|
||||||
} | Select-Object -First 1
|
return $Matches[1].ToLowerInvariant()
|
||||||
if (-not $line) {
|
|
||||||
Fail "Release checksum manifest does not contain $Asset."
|
|
||||||
}
|
}
|
||||||
return ($line -split '\s+')[0].ToLowerInvariant()
|
}
|
||||||
|
|
||||||
|
Fail "Godot $GodotVersion does not publish required $edition asset '$Asset' for Windows/$HostArch at $script:BaseUrl. Choose a supported stable release and architecture."
|
||||||
}
|
}
|
||||||
|
|
||||||
function Download-AndVerify([string]$Asset, [string]$Destination, [string]$ManifestPath) {
|
function Download-AndVerify([string]$Asset, [string]$Destination, [string]$ExpectedChecksum) {
|
||||||
Invoke-WebRequest -Uri "$script:BaseUrl/$Asset" -OutFile $Destination
|
Invoke-WebRequest -UseBasicParsing -Uri "$script:BaseUrl/$Asset" -OutFile $Destination
|
||||||
$expected = Get-Checksum $ManifestPath $Asset
|
$actualChecksum = (Get-FileHash -LiteralPath $Destination -Algorithm SHA512).Hash.ToLowerInvariant()
|
||||||
$actual = (Get-FileHash -LiteralPath $Destination -Algorithm SHA512).Hash.ToLowerInvariant()
|
if ($actualChecksum -ne $ExpectedChecksum) {
|
||||||
if ($actual -ne $expected) {
|
|
||||||
Fail "SHA-512 verification failed for $Asset."
|
Fail "SHA-512 verification failed for $Asset."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Find-Editor([string]$Directory) {
|
function Get-CachePaths([string]$Root) {
|
||||||
$console = Get-ChildItem -LiteralPath $Directory -Recurse -File -Filter 'Godot*console.exe' -ErrorAction SilentlyContinue | Select-Object -First 1
|
$editorDirectory = Join-Path $Root 'editor'
|
||||||
if ($console) { return $console.FullName }
|
$userHome = Join-Path $Root 'home'
|
||||||
$editor = Get-ChildItem -LiteralPath $Directory -Recurse -File -Filter 'Godot*.exe' -ErrorAction SilentlyContinue | Select-Object -First 1
|
$templateDirectory = Join-Path $userHome "AppData\Roaming\Godot\export_templates\$templateVersion"
|
||||||
if ($editor) { return $editor.FullName }
|
|
||||||
|
return [PSCustomObject]@{
|
||||||
|
Root = $Root
|
||||||
|
EditorDirectory = $editorDirectory
|
||||||
|
UserHome = $userHome
|
||||||
|
TemplateDirectory = $templateDirectory
|
||||||
|
Marker = Join-Path $Root '.complete'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-EditorExecutable([string]$EditorDirectory) {
|
||||||
|
$matches = @(Get-ChildItem -LiteralPath $EditorDirectory -Recurse -File -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.Name -eq $expectedEditorFileName })
|
||||||
|
|
||||||
|
if ($matches.Count -eq 1) {
|
||||||
|
return $matches[0].FullName
|
||||||
|
}
|
||||||
|
|
||||||
return $null
|
return $null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Get-PeMachine([string]$Path) {
|
||||||
|
try {
|
||||||
|
$bytes = [IO.File]::ReadAllBytes($Path)
|
||||||
|
} catch {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bytes.Length -lt 64 -or $bytes[0] -ne 0x4d -or $bytes[1] -ne 0x5a) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$peOffset = [BitConverter]::ToInt32($bytes, 0x3c)
|
||||||
|
if ($peOffset -lt 0 -or $peOffset -gt ($bytes.Length - 6)) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bytes[$peOffset] -ne 0x50 -or $bytes[$peOffset + 1] -ne 0x45 -or $bytes[$peOffset + 2] -ne 0 -or $bytes[$peOffset + 3] -ne 0) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
return [BitConverter]::ToUInt16($bytes, $peOffset + 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-ExpectedEditor([string]$EditorDirectory) {
|
||||||
|
$editorExecutable = Get-EditorExecutable $EditorDirectory
|
||||||
|
if (-not $editorExecutable) {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Get-PeMachine $editorExecutable) -eq $expectedPeMachine
|
||||||
|
}
|
||||||
|
|
||||||
|
function Assert-ExpectedEditor([string]$EditorDirectory) {
|
||||||
|
$editorExecutable = Get-EditorExecutable $EditorDirectory
|
||||||
|
if (-not $editorExecutable) {
|
||||||
|
Fail "The Godot editor archive did not contain the expected console executable '$expectedEditorFileName'."
|
||||||
|
}
|
||||||
|
|
||||||
|
$machine = Get-PeMachine $editorExecutable
|
||||||
|
if ($machine -ne $expectedPeMachine) {
|
||||||
|
Fail "The expected Godot console executable '$expectedEditorFileName' is not a valid $HostArch Windows executable."
|
||||||
|
}
|
||||||
|
|
||||||
|
return $editorExecutable
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-ValidCache($Paths) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
function Install-ExportTemplates($Paths, [string]$StagingDirectory, [string]$TemplateAsset) {
|
||||||
|
$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."
|
||||||
|
}
|
||||||
|
|
||||||
|
$actualVersion = (Get-Content -LiteralPath $stagedVersion -Raw).Trim()
|
||||||
|
if ($actualVersion -ne $templateVersion) {
|
||||||
|
Fail "The export-template archive '$TemplateAsset' reports template version '$actualVersion', 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-Cache($Paths) {
|
||||||
|
New-Item -ItemType Directory -Force -Path $Paths.EditorDirectory | Out-Null
|
||||||
|
|
||||||
|
$manifestPath = Join-Path $Paths.Root 'SHA512-SUMS.txt'
|
||||||
|
$editorArchive = Join-Path $Paths.Root $editorAsset
|
||||||
|
$templatesArchive = Join-Path $Paths.Root $templatesAsset
|
||||||
|
$templatesZipArchive = Join-Path $Paths.Root 'export-templates.zip'
|
||||||
|
$templatesStagingDirectory = Join-Path $Paths.Root 'templates-staging'
|
||||||
|
|
||||||
|
Invoke-WebRequest -UseBasicParsing -Uri "$script:BaseUrl/SHA512-SUMS.txt" -OutFile $manifestPath
|
||||||
|
$editorChecksum = Get-Checksum $manifestPath $editorAsset
|
||||||
|
$templatesChecksum = Get-Checksum $manifestPath $templatesAsset
|
||||||
|
Download-AndVerify $editorAsset $editorArchive $editorChecksum
|
||||||
|
Download-AndVerify $templatesAsset $templatesArchive $templatesChecksum
|
||||||
|
|
||||||
|
Expand-Archive -LiteralPath $editorArchive -DestinationPath $Paths.EditorDirectory -Force
|
||||||
|
Assert-ExpectedEditor $Paths.EditorDirectory | Out-Null
|
||||||
|
|
||||||
|
# Expand-Archive only recognizes .zip files. The verified .tpz payload is a ZIP archive.
|
||||||
|
Move-Item -LiteralPath $templatesArchive -Destination $templatesZipArchive
|
||||||
|
Expand-Archive -LiteralPath $templatesZipArchive -DestinationPath $templatesStagingDirectory -Force
|
||||||
|
Install-ExportTemplates $Paths $templatesStagingDirectory $templatesAsset
|
||||||
|
Remove-Item -LiteralPath $templatesStagingDirectory -Recurse -Force
|
||||||
|
|
||||||
|
@("release=$GodotVersion", "editor=$editorAsset", "templates=$templatesAsset") |
|
||||||
|
Set-Content -LiteralPath $Paths.Marker -NoNewline
|
||||||
|
}
|
||||||
|
|
||||||
$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,20 +213,21 @@ $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 (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'." }
|
||||||
@@ -90,62 +235,71 @@ if (-not (Select-String -LiteralPath $PresetFile -SimpleMatch "name=`"$ExportPre
|
|||||||
|
|
||||||
if ($Dotnet -eq 'true') {
|
if ($Dotnet -eq 'true') {
|
||||||
$edition = 'dotnet'
|
$edition = 'dotnet'
|
||||||
$editorAsset = switch ($HostArch) {
|
$editorBaseName = switch ($HostArch) {
|
||||||
'x86_32' { "Godot_v${GodotVersion}_mono_win32.zip" }
|
'x86_32' { "Godot_v${GodotVersion}_mono_win32" }
|
||||||
'x86_64' { "Godot_v${GodotVersion}_mono_win64.zip" }
|
'x86_64' { "Godot_v${GodotVersion}_mono_win64" }
|
||||||
'arm64' { "Godot_v${GodotVersion}_mono_windows_arm64.zip" }
|
'arm64' { "Godot_v${GodotVersion}_mono_windows_arm64" }
|
||||||
}
|
}
|
||||||
|
$editorAsset = "$editorBaseName.zip"
|
||||||
$templatesAsset = "Godot_v${GodotVersion}_mono_export_templates.tpz"
|
$templatesAsset = "Godot_v${GodotVersion}_mono_export_templates.tpz"
|
||||||
|
$templateVersion = ($GodotVersion -replace '-', '.') + '.mono'
|
||||||
} else {
|
} else {
|
||||||
$edition = 'standard'
|
$edition = 'standard'
|
||||||
$editorAsset = switch ($HostArch) {
|
$editorBaseName = switch ($HostArch) {
|
||||||
'x86_32' { "Godot_v${GodotVersion}_win32.exe.zip" }
|
'x86_32' { "Godot_v${GodotVersion}_win32" }
|
||||||
'x86_64' { "Godot_v${GodotVersion}_win64.exe.zip" }
|
'x86_64' { "Godot_v${GodotVersion}_win64" }
|
||||||
'arm64' { "Godot_v${GodotVersion}_windows_arm64.exe.zip" }
|
'arm64' { "Godot_v${GodotVersion}_windows_arm64" }
|
||||||
}
|
}
|
||||||
|
$editorAsset = "$editorBaseName.exe.zip"
|
||||||
$templatesAsset = "Godot_v${GodotVersion}_export_templates.tpz"
|
$templatesAsset = "Godot_v${GodotVersion}_export_templates.tpz"
|
||||||
|
$templateVersion = $GodotVersion -replace '-', '.'
|
||||||
}
|
}
|
||||||
|
|
||||||
$script:BaseUrl = "https://github.com/godotengine/godot-builds/releases/download/$GodotVersion"
|
$expectedEditorFileName = "${editorBaseName}_console.exe"
|
||||||
$templateVersion = $GodotVersion -replace '-', '.'
|
$expectedPeMachine = switch ($HostArch) {
|
||||||
|
'x86_32' { [uint16]0x014c }
|
||||||
|
'x86_64' { [uint16]0x8664 }
|
||||||
|
'arm64' { [uint16]0xaa64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
$script:BaseUrl = "https://github.com/godotengine/godot/releases/download/$GodotVersion"
|
||||||
$cacheDirectory = Join-Path $ActionRoot "cache\$GodotVersion\$edition\windows-$HostArch"
|
$cacheDirectory = Join-Path $ActionRoot "cache\$GodotVersion\$edition\windows-$HostArch"
|
||||||
$editorDirectory = Join-Path $cacheDirectory 'editor'
|
$cachePaths = Get-CachePaths $cacheDirectory
|
||||||
$userHome = Join-Path $cacheDirectory 'home'
|
|
||||||
$templateDirectory = Join-Path $userHome "AppData\Roaming\Godot\export_templates\$templateVersion"
|
|
||||||
$marker = Join-Path $cacheDirectory '.complete'
|
|
||||||
|
|
||||||
$editorExecutable = $null
|
if (-not (Test-ValidCache $cachePaths)) {
|
||||||
if ((Test-Path -LiteralPath $marker -PathType Leaf) -and (Test-Path -LiteralPath (Join-Path $templateDirectory 'version.txt') -PathType Leaf)) {
|
$cacheParent = Split-Path -Parent $cacheDirectory
|
||||||
$editorExecutable = Find-Editor $editorDirectory
|
$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
|
||||||
|
|
||||||
if (-not $editorExecutable) {
|
try {
|
||||||
|
$stagingPaths = Get-CachePaths $stagingDirectory
|
||||||
|
Install-Cache $stagingPaths
|
||||||
|
if (-not (Test-ValidCache $stagingPaths)) { Fail 'Godot cache installation did not pass validation.' }
|
||||||
if (Test-Path -LiteralPath $cacheDirectory) { Remove-Item -LiteralPath $cacheDirectory -Recurse -Force }
|
if (Test-Path -LiteralPath $cacheDirectory) { Remove-Item -LiteralPath $cacheDirectory -Recurse -Force }
|
||||||
New-Item -ItemType Directory -Force -Path $editorDirectory, $templateDirectory | Out-Null
|
Move-Item -LiteralPath $stagingDirectory -Destination $cacheDirectory
|
||||||
$manifestPath = Join-Path $cacheDirectory 'SHA512-SUMS.txt'
|
} finally {
|
||||||
$editorArchive = Join-Path $cacheDirectory $editorAsset
|
if (Test-Path -LiteralPath $stagingDirectory) { Remove-Item -LiteralPath $stagingDirectory -Recurse -Force }
|
||||||
$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
|
||||||
$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
|
|
||||||
|
try {
|
||||||
|
& $editorExecutable --headless --path $ProjectDirectory "--export-$ExportMode" $ExportPreset $outputFile
|
||||||
|
} catch {
|
||||||
|
Fail "Godot could not start '$editorExecutable': $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||||
if (-not (Test-Path -LiteralPath $outputFile)) { Fail "Godot completed without creating the expected output '$ExportFileName'." }
|
if (-not (Test-Path -LiteralPath $outputFile)) { Fail "Godot completed without creating the expected output '$ExportFileName'." }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user