Action steps and export script files
This commit is contained in:
+98
@@ -0,0 +1,98 @@
|
||||
name: Export Godot project
|
||||
description: Download and cache Godot 4, install export templates, and export a named preset without Docker.
|
||||
|
||||
inputs:
|
||||
godot-version:
|
||||
description: Exact Godot 4 release tag without a leading v (for example, 4.6.1-stable).
|
||||
required: true
|
||||
host-os:
|
||||
description: "Runner operating system: linux, macos, or windows."
|
||||
required: true
|
||||
host-arch:
|
||||
description: Runner architecture. Supported values depend on host-os.
|
||||
required: true
|
||||
dotnet:
|
||||
description: Download the Godot .NET editor and export templates.
|
||||
required: false
|
||||
default: "false"
|
||||
project-path:
|
||||
description: Godot project directory, relative to the checked-out workspace.
|
||||
required: false
|
||||
default: .
|
||||
export-preset:
|
||||
description: Exact export preset name from export_presets.cfg.
|
||||
required: true
|
||||
export-mode:
|
||||
description: "Export mode: release or debug."
|
||||
required: false
|
||||
default: release
|
||||
export-file-name:
|
||||
description: Output filename only, including its platform-appropriate extension.
|
||||
required: true
|
||||
cache:
|
||||
description: Restore and save the downloaded Godot editor and export templates.
|
||||
required: false
|
||||
default: "true"
|
||||
|
||||
outputs:
|
||||
build-directory:
|
||||
description: Absolute directory containing this invocation's exported build.
|
||||
value: ${{ steps.export-linux.outputs.build-directory || steps.export-macos.outputs.build-directory || steps.export-windows.outputs.build-directory }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Restore Godot cache
|
||||
if: ${{ inputs.cache == 'true' }}
|
||||
uses: actions/cache@v4.1.0
|
||||
with:
|
||||
path: "${{ runner.temp }}/godot-export-action/cache"
|
||||
key: "godot-export-action-v1-${{ inputs.godot-version }}-${{ inputs.dotnet }}-${{ inputs.host-os }}-${{ inputs.host-arch }}"
|
||||
|
||||
- name: Export Godot project on Linux
|
||||
id: export-linux
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
shell: bash
|
||||
env:
|
||||
GODOT_VERSION: "${{ inputs.godot-version }}"
|
||||
GODOT_HOST_OS: "${{ inputs.host-os }}"
|
||||
GODOT_HOST_ARCH: "${{ inputs.host-arch }}"
|
||||
GODOT_DOTNET: "${{ inputs.dotnet }}"
|
||||
GODOT_PROJECT_PATH: "${{ inputs.project-path }}"
|
||||
GODOT_EXPORT_PRESET: "${{ inputs.export-preset }}"
|
||||
GODOT_EXPORT_MODE: "${{ inputs.export-mode }}"
|
||||
GODOT_EXPORT_FILE_NAME: "${{ inputs.export-file-name }}"
|
||||
GODOT_ACTION_ROOT: "${{ runner.temp }}/godot-export-action"
|
||||
run: bash "$GITHUB_ACTION_PATH/export-linux.sh"
|
||||
|
||||
- name: Export Godot project on macOS
|
||||
id: export-macos
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
shell: bash
|
||||
env:
|
||||
GODOT_VERSION: "${{ inputs.godot-version }}"
|
||||
GODOT_HOST_OS: "${{ inputs.host-os }}"
|
||||
GODOT_HOST_ARCH: "${{ inputs.host-arch }}"
|
||||
GODOT_DOTNET: "${{ inputs.dotnet }}"
|
||||
GODOT_PROJECT_PATH: "${{ inputs.project-path }}"
|
||||
GODOT_EXPORT_PRESET: "${{ inputs.export-preset }}"
|
||||
GODOT_EXPORT_MODE: "${{ inputs.export-mode }}"
|
||||
GODOT_EXPORT_FILE_NAME: "${{ inputs.export-file-name }}"
|
||||
GODOT_ACTION_ROOT: "${{ runner.temp }}/godot-export-action"
|
||||
run: bash "$GITHUB_ACTION_PATH/export-macos.sh"
|
||||
|
||||
- name: Export Godot project on Windows
|
||||
id: export-windows
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
shell: powershell
|
||||
env:
|
||||
GODOT_VERSION: "${{ inputs.godot-version }}"
|
||||
GODOT_HOST_OS: "${{ inputs.host-os }}"
|
||||
GODOT_HOST_ARCH: "${{ inputs.host-arch }}"
|
||||
GODOT_DOTNET: "${{ inputs.dotnet }}"
|
||||
GODOT_PROJECT_PATH: "${{ inputs.project-path }}"
|
||||
GODOT_EXPORT_PRESET: "${{ inputs.export-preset }}"
|
||||
GODOT_EXPORT_MODE: "${{ inputs.export-mode }}"
|
||||
GODOT_EXPORT_FILE_NAME: "${{ inputs.export-file-name }}"
|
||||
GODOT_ACTION_ROOT: "${{ runner.temp }}/godot-export-action"
|
||||
run: "& \"$env:GITHUB_ACTION_PATH\\export-windows.ps1\""
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
fail() {
|
||||
echo "::error::$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_command() {
|
||||
command -v "$1" >/dev/null 2>&1 || fail "Required command '$1' was not found on the runner."
|
||||
}
|
||||
|
||||
require_environment() {
|
||||
[[ -n "${!1:-}" ]] || fail "Required environment variable '$1' is not set."
|
||||
}
|
||||
|
||||
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_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_EXPORT_MODE" == "release" || "$GODOT_EXPORT_MODE" == "debug" ]] || fail "export-mode must be 'release' or 'debug'."
|
||||
[[ -n "$GODOT_EXPORT_PRESET" ]] || fail "export-preset must not be empty."
|
||||
[[ -n "$GODOT_EXPORT_FILE_NAME" && "$GODOT_EXPORT_FILE_NAME" != "." && "$GODOT_EXPORT_FILE_NAME" != ".." ]] || fail "export-file-name must be a filename."
|
||||
[[ "$GODOT_EXPORT_FILE_NAME" != */* && "$GODOT_EXPORT_FILE_NAME" != *\\* ]] || fail "export-file-name must not contain a path separator."
|
||||
}
|
||||
|
||||
actual_architecture() {
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64) echo x86_64 ;;
|
||||
i?86) echo x86_32 ;;
|
||||
aarch64|arm64) echo arm64 ;;
|
||||
armv7l|armv6l) echo arm32 ;;
|
||||
*) fail "Unsupported Linux runner architecture: $(uname -m)." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
download_and_verify() {
|
||||
local asset="$1"
|
||||
local destination="$2"
|
||||
local sum_file="$3"
|
||||
local expected
|
||||
local actual
|
||||
|
||||
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" == "$expected" ]] || fail "SHA-512 verification failed for $asset."
|
||||
}
|
||||
|
||||
find_editor() {
|
||||
find "$EDITOR_DIR" -maxdepth 3 -type f -name 'Godot*' -print -quit
|
||||
}
|
||||
|
||||
install_godot() {
|
||||
local sum_file="$CACHE_DIR/SHA512-SUMS.txt"
|
||||
local editor_archive="$CACHE_DIR/$EDITOR_ASSET"
|
||||
local templates_archive="$CACHE_DIR/$TEMPLATES_ASSET"
|
||||
|
||||
rm -rf "$CACHE_DIR"
|
||||
mkdir -p "$EDITOR_DIR" "$TEMPLATE_DIR"
|
||||
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"
|
||||
download_and_verify "$TEMPLATES_ASSET" "$templates_archive" "$sum_file"
|
||||
unzip -q "$editor_archive" -d "$EDITOR_DIR"
|
||||
unzip -q "$templates_archive" -d "$TEMPLATE_DIR"
|
||||
EDITOR_EXECUTABLE="$(find_editor)"
|
||||
[[ -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."
|
||||
printf 'release=%s\neditor=%s\ntemplates=%s\n' "$GODOT_VERSION" "$EDITOR_ASSET" "$TEMPLATES_ASSET" > "$CACHE_DIR/.complete"
|
||||
}
|
||||
|
||||
require_environment GODOT_VERSION
|
||||
require_environment GODOT_HOST_OS
|
||||
require_environment GODOT_HOST_ARCH
|
||||
require_environment GODOT_DOTNET
|
||||
require_environment GODOT_PROJECT_PATH
|
||||
require_environment GODOT_EXPORT_PRESET
|
||||
require_environment GODOT_EXPORT_MODE
|
||||
require_environment GODOT_EXPORT_FILE_NAME
|
||||
require_environment GODOT_ACTION_ROOT
|
||||
require_environment GITHUB_WORKSPACE
|
||||
require_environment GITHUB_OUTPUT
|
||||
|
||||
require_command curl
|
||||
require_command unzip
|
||||
require_command sha512sum
|
||||
validate_common_inputs
|
||||
|
||||
[[ "$(uname -s)" == "Linux" ]] || fail "The Linux script was selected on a non-Linux runner."
|
||||
[[ "$GODOT_HOST_ARCH" == "x86_32" || "$GODOT_HOST_ARCH" == "x86_64" || "$GODOT_HOST_ARCH" == "arm32" || "$GODOT_HOST_ARCH" == "arm64" ]] || fail "Unsupported Linux host-arch '$GODOT_HOST_ARCH'."
|
||||
[[ "$GODOT_HOST_ARCH" == "$(actual_architecture)" ]] || fail "host-arch '$GODOT_HOST_ARCH' does not match this Linux runner ($(actual_architecture))."
|
||||
|
||||
[[ "$GODOT_PROJECT_PATH" != /* && "$GODOT_PROJECT_PATH" != \\* ]] || fail "project-path must be relative to the checked-out workspace."
|
||||
WORKSPACE_DIR="$(cd "$GITHUB_WORKSPACE" && pwd -P)"
|
||||
PROJECT_DIR="$(cd "$WORKSPACE_DIR/$GODOT_PROJECT_PATH" 2>/dev/null && pwd -P)" || fail "project-path '$GODOT_PROJECT_PATH' does not exist."
|
||||
case "$PROJECT_DIR/" in
|
||||
"$WORKSPACE_DIR/"*) ;;
|
||||
*) fail "project-path must remain inside the checked-out workspace." ;;
|
||||
esac
|
||||
[[ -f "$PROJECT_DIR/project.godot" ]] || fail "No project.godot was found in project-path '$GODOT_PROJECT_PATH'."
|
||||
[[ -f "$PROJECT_DIR/export_presets.cfg" ]] || fail "No export_presets.cfg was found in project-path '$GODOT_PROJECT_PATH'."
|
||||
grep -Fq "name=\"$GODOT_EXPORT_PRESET\"" "$PROJECT_DIR/export_presets.cfg" || fail "Export preset '$GODOT_EXPORT_PRESET' was not found in export_presets.cfg."
|
||||
|
||||
if [[ "$GODOT_DOTNET" == "true" ]]; then
|
||||
EDITION=dotnet
|
||||
EDITOR_ASSET="Godot_v${GODOT_VERSION}_mono_linux_${GODOT_HOST_ARCH}.zip"
|
||||
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_mono_export_templates.tpz"
|
||||
else
|
||||
EDITION=standard
|
||||
EDITOR_ASSET="Godot_v${GODOT_VERSION}_linux.${GODOT_HOST_ARCH}.zip"
|
||||
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_export_templates.tpz"
|
||||
fi
|
||||
|
||||
BASE_URL="https://github.com/godotengine/godot-builds/releases/download/$GODOT_VERSION"
|
||||
TEMPLATE_VERSION="${GODOT_VERSION//-/.}"
|
||||
CACHE_DIR="$GODOT_ACTION_ROOT/cache/$GODOT_VERSION/$EDITION/linux-$GODOT_HOST_ARCH"
|
||||
EDITOR_DIR="$CACHE_DIR/editor"
|
||||
USER_DATA_DIR="$CACHE_DIR/user-data"
|
||||
TEMPLATE_DIR="$USER_DATA_DIR/godot/export_templates/$TEMPLATE_VERSION"
|
||||
|
||||
if [[ -f "$CACHE_DIR/.complete" && -f "$TEMPLATE_DIR/version.txt" ]]; then
|
||||
EDITOR_EXECUTABLE="$(find_editor || true)"
|
||||
else
|
||||
EDITOR_EXECUTABLE=""
|
||||
fi
|
||||
if [[ -z "$EDITOR_EXECUTABLE" ]]; then
|
||||
install_godot
|
||||
fi
|
||||
|
||||
chmod +x "$EDITOR_EXECUTABLE"
|
||||
SAFE_PRESET="$(printf '%s' "$GODOT_EXPORT_PRESET" | tr -cs '[:alnum:]_.-' '_')"
|
||||
BUILD_DIR="$GODOT_ACTION_ROOT/builds/${SAFE_PRESET:-export}-$GODOT_EXPORT_MODE-$$"
|
||||
OUTPUT_FILE="$BUILD_DIR/$GODOT_EXPORT_FILE_NAME"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
export XDG_DATA_HOME="$USER_DATA_DIR"
|
||||
export XDG_CONFIG_HOME="$CACHE_DIR/config"
|
||||
"$EDITOR_EXECUTABLE" --headless --path "$PROJECT_DIR" "--export-$GODOT_EXPORT_MODE" "$GODOT_EXPORT_PRESET" "$OUTPUT_FILE"
|
||||
[[ -e "$OUTPUT_FILE" ]] || fail "Godot completed without creating the expected output '$GODOT_EXPORT_FILE_NAME'."
|
||||
|
||||
printf 'build-directory=%s\n' "$BUILD_DIR" >> "$GITHUB_OUTPUT"
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
fail() {
|
||||
echo "::error::$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
require_command() {
|
||||
command -v "$1" >/dev/null 2>&1 || fail "Required command '$1' was not found on the runner."
|
||||
}
|
||||
|
||||
require_environment() {
|
||||
[[ -n "${!1:-}" ]] || fail "Required environment variable '$1' is not set."
|
||||
}
|
||||
|
||||
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_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_EXPORT_MODE" == "release" || "$GODOT_EXPORT_MODE" == "debug" ]] || fail "export-mode must be 'release' or 'debug'."
|
||||
[[ -n "$GODOT_EXPORT_PRESET" ]] || fail "export-preset must not be empty."
|
||||
[[ -n "$GODOT_EXPORT_FILE_NAME" && "$GODOT_EXPORT_FILE_NAME" != "." && "$GODOT_EXPORT_FILE_NAME" != ".." ]] || fail "export-file-name must be a filename."
|
||||
[[ "$GODOT_EXPORT_FILE_NAME" != */* && "$GODOT_EXPORT_FILE_NAME" != *\\* ]] || fail "export-file-name must not contain a path separator."
|
||||
}
|
||||
|
||||
actual_architecture() {
|
||||
case "$(uname -m)" in
|
||||
x86_64) echo x86_64 ;;
|
||||
arm64) echo arm64 ;;
|
||||
*) fail "Unsupported macOS runner architecture: $(uname -m)." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
download_and_verify() {
|
||||
local asset="$1"
|
||||
local destination="$2"
|
||||
local sum_file="$3"
|
||||
local expected
|
||||
local actual
|
||||
|
||||
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" == "$expected" ]] || fail "SHA-512 verification failed for $asset."
|
||||
}
|
||||
|
||||
find_editor() {
|
||||
find "$EDITOR_DIR" -type f -path '*.app/Contents/MacOS/*' -name 'Godot*' -print -quit
|
||||
}
|
||||
|
||||
install_godot() {
|
||||
local sum_file="$CACHE_DIR/SHA512-SUMS.txt"
|
||||
local editor_archive="$CACHE_DIR/$EDITOR_ASSET"
|
||||
local templates_archive="$CACHE_DIR/$TEMPLATES_ASSET"
|
||||
|
||||
rm -rf "$CACHE_DIR"
|
||||
mkdir -p "$EDITOR_DIR" "$TEMPLATE_DIR"
|
||||
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"
|
||||
download_and_verify "$TEMPLATES_ASSET" "$templates_archive" "$sum_file"
|
||||
unzip -q "$editor_archive" -d "$EDITOR_DIR"
|
||||
unzip -q "$templates_archive" -d "$TEMPLATE_DIR"
|
||||
EDITOR_EXECUTABLE="$(find_editor)"
|
||||
[[ -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."
|
||||
printf 'release=%s\neditor=%s\ntemplates=%s\n' "$GODOT_VERSION" "$EDITOR_ASSET" "$TEMPLATES_ASSET" > "$CACHE_DIR/.complete"
|
||||
}
|
||||
|
||||
require_environment GODOT_VERSION
|
||||
require_environment GODOT_HOST_OS
|
||||
require_environment GODOT_HOST_ARCH
|
||||
require_environment GODOT_DOTNET
|
||||
require_environment GODOT_PROJECT_PATH
|
||||
require_environment GODOT_EXPORT_PRESET
|
||||
require_environment GODOT_EXPORT_MODE
|
||||
require_environment GODOT_EXPORT_FILE_NAME
|
||||
require_environment GODOT_ACTION_ROOT
|
||||
require_environment GITHUB_WORKSPACE
|
||||
require_environment GITHUB_OUTPUT
|
||||
|
||||
require_command curl
|
||||
require_command unzip
|
||||
require_command shasum
|
||||
validate_common_inputs
|
||||
|
||||
[[ "$(uname -s)" == "Darwin" ]] || fail "The macOS script was selected on a non-macOS runner."
|
||||
[[ "$GODOT_HOST_ARCH" == "x86_64" || "$GODOT_HOST_ARCH" == "arm64" ]] || fail "Unsupported macOS host-arch '$GODOT_HOST_ARCH'."
|
||||
[[ "$GODOT_HOST_ARCH" == "$(actual_architecture)" ]] || fail "host-arch '$GODOT_HOST_ARCH' does not match this macOS runner ($(actual_architecture))."
|
||||
|
||||
[[ "$GODOT_PROJECT_PATH" != /* && "$GODOT_PROJECT_PATH" != \\* ]] || fail "project-path must be relative to the checked-out workspace."
|
||||
WORKSPACE_DIR="$(cd "$GITHUB_WORKSPACE" && pwd -P)"
|
||||
PROJECT_DIR="$(cd "$WORKSPACE_DIR/$GODOT_PROJECT_PATH" 2>/dev/null && pwd -P)" || fail "project-path '$GODOT_PROJECT_PATH' does not exist."
|
||||
case "$PROJECT_DIR/" in
|
||||
"$WORKSPACE_DIR/"*) ;;
|
||||
*) fail "project-path must remain inside the checked-out workspace." ;;
|
||||
esac
|
||||
[[ -f "$PROJECT_DIR/project.godot" ]] || fail "No project.godot was found in project-path '$GODOT_PROJECT_PATH'."
|
||||
[[ -f "$PROJECT_DIR/export_presets.cfg" ]] || fail "No export_presets.cfg was found in project-path '$GODOT_PROJECT_PATH'."
|
||||
grep -Fq "name=\"$GODOT_EXPORT_PRESET\"" "$PROJECT_DIR/export_presets.cfg" || fail "Export preset '$GODOT_EXPORT_PRESET' was not found in export_presets.cfg."
|
||||
|
||||
if [[ "$GODOT_DOTNET" == "true" ]]; then
|
||||
EDITION=dotnet
|
||||
EDITOR_ASSET="Godot_v${GODOT_VERSION}_mono_macos.universal.zip"
|
||||
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_mono_export_templates.tpz"
|
||||
else
|
||||
EDITION=standard
|
||||
EDITOR_ASSET="Godot_v${GODOT_VERSION}_macos.universal.zip"
|
||||
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_export_templates.tpz"
|
||||
fi
|
||||
|
||||
BASE_URL="https://github.com/godotengine/godot-builds/releases/download/$GODOT_VERSION"
|
||||
TEMPLATE_VERSION="${GODOT_VERSION//-/.}"
|
||||
CACHE_DIR="$GODOT_ACTION_ROOT/cache/$GODOT_VERSION/$EDITION/macos-$GODOT_HOST_ARCH"
|
||||
EDITOR_DIR="$CACHE_DIR/editor"
|
||||
USER_HOME="$CACHE_DIR/home"
|
||||
TEMPLATE_DIR="$USER_HOME/Library/Application Support/Godot/export_templates/$TEMPLATE_VERSION"
|
||||
|
||||
if [[ -f "$CACHE_DIR/.complete" && -f "$TEMPLATE_DIR/version.txt" ]]; then
|
||||
EDITOR_EXECUTABLE="$(find_editor || true)"
|
||||
else
|
||||
EDITOR_EXECUTABLE=""
|
||||
fi
|
||||
if [[ -z "$EDITOR_EXECUTABLE" ]]; then
|
||||
install_godot
|
||||
fi
|
||||
|
||||
chmod +x "$EDITOR_EXECUTABLE"
|
||||
SAFE_PRESET="$(printf '%s' "$GODOT_EXPORT_PRESET" | tr -cs '[:alnum:]_.-' '_')"
|
||||
BUILD_DIR="$GODOT_ACTION_ROOT/builds/${SAFE_PRESET:-export}-$GODOT_EXPORT_MODE-$$"
|
||||
OUTPUT_FILE="$BUILD_DIR/$GODOT_EXPORT_FILE_NAME"
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
export HOME="$USER_HOME"
|
||||
"$EDITOR_EXECUTABLE" --headless --path "$PROJECT_DIR" "--export-$GODOT_EXPORT_MODE" "$GODOT_EXPORT_PRESET" "$OUTPUT_FILE"
|
||||
[[ -e "$OUTPUT_FILE" ]] || fail "Godot completed without creating the expected output '$GODOT_EXPORT_FILE_NAME'."
|
||||
|
||||
printf 'build-directory=%s\n' "$BUILD_DIR" >> "$GITHUB_OUTPUT"
|
||||
@@ -0,0 +1,152 @@
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Fail([string]$Message) {
|
||||
Write-Error "::error::$Message"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function Require-Environment([string]$Name) {
|
||||
$value = [Environment]::GetEnvironmentVariable($Name)
|
||||
if ([string]::IsNullOrWhiteSpace($value)) {
|
||||
Fail "Required environment variable '$Name' is not set."
|
||||
}
|
||||
return $value
|
||||
}
|
||||
|
||||
function Get-ActualArchitecture {
|
||||
$architecture = $env:PROCESSOR_ARCHITEW6432
|
||||
if ([string]::IsNullOrWhiteSpace($architecture)) {
|
||||
$architecture = $env:PROCESSOR_ARCHITECTURE
|
||||
}
|
||||
switch ($architecture.ToUpperInvariant()) {
|
||||
'AMD64' { return 'x86_64' }
|
||||
'X86' { return 'x86_32' }
|
||||
'ARM64' { return 'arm64' }
|
||||
default { Fail "Unsupported Windows runner architecture: $architecture." }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-Checksum([string]$ManifestPath, [string]$Asset) {
|
||||
$line = Get-Content -LiteralPath $ManifestPath | Where-Object {
|
||||
$_ -match '^([0-9A-Fa-f]{128})\s+\*?(.+)$' -and $Matches[2] -eq $Asset
|
||||
} | Select-Object -First 1
|
||||
if (-not $line) {
|
||||
Fail "Release checksum manifest does not contain $Asset."
|
||||
}
|
||||
return ($line -split '\s+')[0].ToLowerInvariant()
|
||||
}
|
||||
|
||||
function Download-AndVerify([string]$Asset, [string]$Destination, [string]$ManifestPath) {
|
||||
Invoke-WebRequest -Uri "$script:BaseUrl/$Asset" -OutFile $Destination
|
||||
$expected = Get-Checksum $ManifestPath $Asset
|
||||
$actual = (Get-FileHash -LiteralPath $Destination -Algorithm SHA512).Hash.ToLowerInvariant()
|
||||
if ($actual -ne $expected) {
|
||||
Fail "SHA-512 verification failed for $Asset."
|
||||
}
|
||||
}
|
||||
|
||||
function Find-Editor([string]$Directory) {
|
||||
$console = Get-ChildItem -LiteralPath $Directory -Recurse -File -Filter 'Godot*console.exe' -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if ($console) { return $console.FullName }
|
||||
$editor = Get-ChildItem -LiteralPath $Directory -Recurse -File -Filter 'Godot*.exe' -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if ($editor) { return $editor.FullName }
|
||||
return $null
|
||||
}
|
||||
|
||||
$GodotVersion = Require-Environment 'GODOT_VERSION'
|
||||
$HostOs = Require-Environment 'GODOT_HOST_OS'
|
||||
$HostArch = Require-Environment 'GODOT_HOST_ARCH'
|
||||
$Dotnet = Require-Environment 'GODOT_DOTNET'
|
||||
$ProjectPath = Require-Environment 'GODOT_PROJECT_PATH'
|
||||
$ExportPreset = Require-Environment 'GODOT_EXPORT_PRESET'
|
||||
$ExportMode = Require-Environment 'GODOT_EXPORT_MODE'
|
||||
$ExportFileName = Require-Environment 'GODOT_EXPORT_FILE_NAME'
|
||||
$ActionRoot = Require-Environment 'GODOT_ACTION_ROOT'
|
||||
$Workspace = Require-Environment 'GITHUB_WORKSPACE'
|
||||
$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 ($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 ($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($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 -ne (Get-ActualArchitecture)) { Fail "host-arch '$HostArch' does not match this Windows runner ($(Get-ActualArchitecture))." }
|
||||
|
||||
$workspaceDirectory = [IO.Path]::GetFullPath($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))
|
||||
$projectRelativePath = [IO.Path]::GetRelativePath($workspaceDirectory, $ProjectDirectory)
|
||||
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'." }
|
||||
$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 (Select-String -LiteralPath $PresetFile -SimpleMatch "name=`"$ExportPreset`"" -Quiet)) { Fail "Export preset '$ExportPreset' was not found in export_presets.cfg." }
|
||||
|
||||
if ($Dotnet -eq 'true') {
|
||||
$edition = 'dotnet'
|
||||
$editorAsset = switch ($HostArch) {
|
||||
'x86_32' { "Godot_v${GodotVersion}_mono_win32.zip" }
|
||||
'x86_64' { "Godot_v${GodotVersion}_mono_win64.zip" }
|
||||
'arm64' { "Godot_v${GodotVersion}_mono_windows_arm64.zip" }
|
||||
}
|
||||
$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
|
||||
}
|
||||
|
||||
$safePreset = ($ExportPreset -replace '[^A-Za-z0-9_.-]', '_').Trim('_')
|
||||
if ([string]::IsNullOrWhiteSpace($safePreset)) { $safePreset = 'export' }
|
||||
$buildDirectory = Join-Path $ActionRoot "builds\$safePreset-$ExportMode-$PID"
|
||||
$outputFile = Join-Path $buildDirectory $ExportFileName
|
||||
New-Item -ItemType Directory -Force -Path $buildDirectory | Out-Null
|
||||
|
||||
$env:USERPROFILE = $userHome
|
||||
$env:APPDATA = Join-Path $userHome 'AppData\Roaming'
|
||||
$env:LOCALAPPDATA = Join-Path $userHome 'AppData\Local'
|
||||
& $editorExecutable --headless --path $ProjectDirectory "--export-$ExportMode" $ExportPreset $outputFile
|
||||
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
|
||||
Reference in New Issue
Block a user