feat: add reusable Flutter build actions for android, ios, macos, windows, and linux
Update README Actions Table / update-readme (push) Successful in 7s
Update README Actions Table / update-readme (push) Successful in 7s
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
name: 'Flutter Build Windows'
|
||||
description: 'Builds Windows Flutter desktop apps, compiles Inno Setup (.exe) and MSIX (.msix) installers, signs updates for WinSparkle (DSA), and generates release metadata.'
|
||||
inputs:
|
||||
working_directory:
|
||||
description: 'Path to the Flutter app package directory (e.g., packages/sfw_desktop)'
|
||||
required: false
|
||||
default: '.'
|
||||
arch:
|
||||
description: 'Target Windows architecture (x64 or arm64)'
|
||||
required: false
|
||||
default: 'x64'
|
||||
build_args:
|
||||
description: 'Extra arguments passed to flutter build windows (e.g., --dart-define=...)'
|
||||
required: false
|
||||
default: ''
|
||||
build_inno_setup:
|
||||
description: 'Whether to compile an Inno Setup installer (.exe)'
|
||||
required: false
|
||||
default: 'true'
|
||||
inno_setup_script:
|
||||
description: 'Path to Inno Setup .iss script relative to working_directory'
|
||||
required: false
|
||||
default: 'windows/installer/inno_setup.iss'
|
||||
output_dir:
|
||||
description: 'Output directory for compiled Inno Setup installer'
|
||||
required: false
|
||||
default: 'dist'
|
||||
exe_filename:
|
||||
description: 'Expected installer filename for metadata JSON (e.g., slides-for-worship-windows-x64-setup.exe)'
|
||||
required: false
|
||||
default: ''
|
||||
build_msix:
|
||||
description: 'Whether to build an MSIX package using msix:create'
|
||||
required: false
|
||||
default: 'true'
|
||||
msix_output_name:
|
||||
description: 'Output base name for the MSIX package (e.g., slides_for_worship_x64)'
|
||||
required: false
|
||||
default: ''
|
||||
pfx_base64:
|
||||
description: 'Base64-encoded Windows Authenticode .pfx certificate'
|
||||
required: false
|
||||
default: ''
|
||||
pfx_password:
|
||||
description: 'Password for the Windows .pfx certificate'
|
||||
required: false
|
||||
default: ''
|
||||
sparkle_dsa_private_key:
|
||||
description: 'WinSparkle DSA private key content (PEM) for signing installer'
|
||||
required: false
|
||||
default: ''
|
||||
sparkle_dsa_key_file:
|
||||
description: 'Fallback path to WinSparkle DSA private key file in repository'
|
||||
required: false
|
||||
default: 'signing/sparkle/dsa_priv.pem'
|
||||
generate_metadata_json:
|
||||
description: 'Whether to generate windows_<arch>_metadata.json and windows_signature.txt'
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
outputs:
|
||||
version:
|
||||
description: 'Resolved package version from pubspec.yaml'
|
||||
value: ${{ steps.build.outputs.version }}
|
||||
exe_path:
|
||||
description: 'Path to compiled Inno Setup .exe installer'
|
||||
value: ${{ steps.package_meta.outputs.exe_path }}
|
||||
msix_path:
|
||||
description: 'Path to generated .msix installer'
|
||||
value: ${{ steps.package_meta.outputs.msix_path }}
|
||||
signature:
|
||||
description: 'WinSparkle DSA signature if generated'
|
||||
value: ${{ steps.package_meta.outputs.signature }}
|
||||
metadata_path:
|
||||
description: 'Path to generated windows_<arch>_metadata.json'
|
||||
value: ${{ steps.package_meta.outputs.metadata_path }}
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Configure Windows Tooling PATH
|
||||
shell: powershell
|
||||
run: |
|
||||
$toolPaths = @(
|
||||
"C:\Program Files\Git\bin",
|
||||
"C:\Program Files\Git\usr\bin",
|
||||
"C:\Git\bin",
|
||||
"C:\Git\usr\bin",
|
||||
"C:\Users\rodyd\AppData\Local\Programs\Inno Setup 6",
|
||||
"C:\Program Files (x86)\Inno Setup 6",
|
||||
"C:\Program Files\Inno Setup 6",
|
||||
"C:\flutter\bin"
|
||||
)
|
||||
foreach ($p in $toolPaths) {
|
||||
if (Test-Path $p) {
|
||||
$env:PATH = "$p;$env:PATH"
|
||||
if (Test-Path env:GITHUB_PATH) {
|
||||
[System.IO.File]::AppendAllText($env:GITHUB_PATH, "$p`r`n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- name: Decode Windows PFX Certificate
|
||||
if: inputs.pfx_base64 != ''
|
||||
shell: powershell
|
||||
env:
|
||||
WINDOWS_PFX_BASE64: ${{ inputs.pfx_base64 }}
|
||||
run: |
|
||||
if ($env:WINDOWS_PFX_BASE64) {
|
||||
$pfx_cert_byte = [System.Convert]::FromBase64String($env:WINDOWS_PFX_BASE64)
|
||||
[IO.File]::WriteAllBytes("cert.pfx", $pfx_cert_byte)
|
||||
Write-Output "Decoded cert.pfx"
|
||||
}
|
||||
|
||||
- name: Build Windows Release
|
||||
id: build
|
||||
shell: bash
|
||||
env:
|
||||
WORK_DIR: ${{ inputs.working_directory }}
|
||||
ARCH: ${{ inputs.arch }}
|
||||
BUILD_ARGS: ${{ inputs.build_args }}
|
||||
run: |
|
||||
ROOT_DIR="$(pwd)"
|
||||
VERSION=$(grep '^version: ' "$WORK_DIR/pubspec.yaml" | head -n 1 | cut -d ' ' -f 2 | tr -d '\r')
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
cd "$WORK_DIR"
|
||||
if [ "$ARCH" = "arm64" ]; then
|
||||
# shellcheck disable=SC2086
|
||||
flutter build windows --release --target-platform=windows-arm64 $BUILD_ARGS
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
flutter build windows --release $BUILD_ARGS
|
||||
fi
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
- name: Compile Inno Setup Installer
|
||||
if: inputs.build_inno_setup == 'true'
|
||||
shell: powershell
|
||||
env:
|
||||
WORK_DIR: ${{ inputs.working_directory }}
|
||||
ARCH: ${{ inputs.arch }}
|
||||
ISS_REL: ${{ inputs.inno_setup_script }}
|
||||
OUT_DIR: ${{ inputs.output_dir }}
|
||||
VERSION: ${{ steps.build.outputs.version }}
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force -Path $env:OUT_DIR | Out-Null
|
||||
$sourceRel = Join-Path $env:WORK_DIR "build\windows\$($env:ARCH)\runner\Release"
|
||||
if (-not (Test-Path $sourceRel)) {
|
||||
$sourceRel = Join-Path $env:WORK_DIR "build\windows\x64\runner\Release"
|
||||
}
|
||||
$sourceDir = (Resolve-Path $sourceRel).Path
|
||||
$outputDir = (Resolve-Path $env:OUT_DIR).Path
|
||||
$issScript = Join-Path $env:WORK_DIR $env:ISS_REL
|
||||
|
||||
if (-not (Test-Path $issScript)) {
|
||||
Write-Warning "Inno Setup script not found at $issScript; skipping Inno Setup compilation."
|
||||
exit 0
|
||||
}
|
||||
|
||||
$iscc = (Get-Command iscc.exe -ErrorAction SilentlyContinue).Source
|
||||
if (-not $iscc -and (Test-Path "C:\Users\rodyd\AppData\Local\Programs\Inno Setup 6\ISCC.exe")) {
|
||||
$iscc = "C:\Users\rodyd\AppData\Local\Programs\Inno Setup 6\ISCC.exe"
|
||||
}
|
||||
if ($iscc) {
|
||||
& $iscc /DMyAppVersion="$($env:VERSION)" /DAppArch="$($env:ARCH)" /DSourceDir="$sourceDir" /DOutputDir="$outputDir" "$issScript"
|
||||
} else {
|
||||
Write-Warning "ISCC.exe not found on runner; skipping Inno Setup installer."
|
||||
}
|
||||
|
||||
- name: Create MSIX Package
|
||||
if: inputs.build_msix == 'true'
|
||||
shell: bash
|
||||
env:
|
||||
WORK_DIR: ${{ inputs.working_directory }}
|
||||
ARCH: ${{ inputs.arch }}
|
||||
MSIX_NAME: ${{ inputs.msix_output_name }}
|
||||
PFX_PASS: ${{ inputs.pfx_password }}
|
||||
run: |
|
||||
ROOT_DIR="$(pwd)"
|
||||
OUT_NAME="${MSIX_NAME:-slides_for_worship_${ARCH}}"
|
||||
cd "$WORK_DIR"
|
||||
if [ -f "$ROOT_DIR/cert.pfx" ]; then
|
||||
flutter pub run msix:create --certificate-path "$ROOT_DIR/cert.pfx" --certificate-password "$PFX_PASS" --install-certificate false --output-name "$OUT_NAME"
|
||||
else
|
||||
flutter pub run msix:create --install-certificate false --output-name "$OUT_NAME"
|
||||
fi
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
- name: Sign for WinSparkle & Generate Metadata
|
||||
id: package_meta
|
||||
shell: bash
|
||||
env:
|
||||
WORK_DIR: ${{ inputs.working_directory }}
|
||||
ARCH: ${{ inputs.arch }}
|
||||
OUT_DIR: ${{ inputs.output_dir }}
|
||||
VERSION: ${{ steps.build.outputs.version }}
|
||||
EXE_FILENAME_INPUT: ${{ inputs.exe_filename }}
|
||||
SPARKLE_DSA_KEY: ${{ inputs.sparkle_dsa_private_key }}
|
||||
SPARKLE_DSA_FILE: ${{ inputs.sparkle_dsa_key_file }}
|
||||
GEN_META: ${{ inputs.generate_metadata_json }}
|
||||
run: |
|
||||
EXE_FILE=$(find "$OUT_DIR" -name "*.exe" 2>/dev/null | head -n 1 || true)
|
||||
MSIX_FILE=$(find "$WORK_DIR/build/windows" -name "*.msix" 2>/dev/null | head -n 1 || true)
|
||||
echo "exe_path=$EXE_FILE" >> "$GITHUB_OUTPUT"
|
||||
echo "msix_path=$MSIX_FILE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
SETUP_FILE="${EXE_FILE:-$MSIX_FILE}"
|
||||
if [ -z "$SPARKLE_DSA_KEY" ] && [ -n "$SPARKLE_DSA_FILE" ] && [ -f "$SPARKLE_DSA_FILE" ]; then
|
||||
SPARKLE_DSA_KEY=$(cat "$SPARKLE_DSA_FILE")
|
||||
fi
|
||||
|
||||
WIN_SIG=""
|
||||
if [ -n "$SPARKLE_DSA_KEY" ] && [ -n "$SETUP_FILE" ] && [ -f "$SETUP_FILE" ]; then
|
||||
echo "$SPARKLE_DSA_KEY" > dsa_priv.pem
|
||||
echo "Signing $SETUP_FILE with DSA key..."
|
||||
WIN_SIG=$(openssl dgst -sha1 -binary < "$SETUP_FILE" | openssl dgst -sha1 -sign dsa_priv.pem | openssl enc -base64 | tr -d '\n\r' || true)
|
||||
if [ -n "$WIN_SIG" ]; then
|
||||
echo "$WIN_SIG" > windows_signature.txt
|
||||
echo "signature=$WIN_SIG" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
rm -f dsa_priv.pem
|
||||
fi
|
||||
|
||||
if [ "$GEN_META" = "true" ]; then
|
||||
SIZE="0"
|
||||
if [ -n "$EXE_FILE" ] && [ -f "$EXE_FILE" ]; then
|
||||
SIZE=$(stat -c%s "$EXE_FILE" 2>/dev/null || stat -f%z "$EXE_FILE" 2>/dev/null || echo "0")
|
||||
fi
|
||||
if [ -n "$EXE_FILENAME_INPUT" ]; then
|
||||
FILENAME="$EXE_FILENAME_INPUT"
|
||||
elif [ -n "$EXE_FILE" ]; then
|
||||
FILENAME=$(basename "$EXE_FILE")
|
||||
else
|
||||
FILENAME="slides-for-worship-windows-${ARCH}-setup.exe"
|
||||
fi
|
||||
|
||||
META_FILE="windows_${ARCH}_metadata.json"
|
||||
cat <<EOF > "$META_FILE"
|
||||
{
|
||||
"version": "$VERSION",
|
||||
"platform": "windows",
|
||||
"arch": "$ARCH",
|
||||
"filename": "$FILENAME",
|
||||
"size": $SIZE,
|
||||
"signature": "$WIN_SIG",
|
||||
"signatureType": "dsaSignature"
|
||||
}
|
||||
EOF
|
||||
cat "$META_FILE"
|
||||
echo "metadata_path=$META_FILE" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Clean up PFX Certificate
|
||||
if: always()
|
||||
shell: powershell
|
||||
run: |
|
||||
if (Test-Path "cert.pfx") {
|
||||
Remove-Item -Force "cert.pfx" -ErrorAction SilentlyContinue
|
||||
}
|
||||
Reference in New Issue
Block a user