Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc78c8775d | ||
|
|
c453e1686f | ||
|
|
b8ccd4acc0 | ||
|
|
afff9f9833 | ||
|
|
9e47ca801d | ||
|
|
2fc99a5c09 | ||
|
|
cabf4363f2 | ||
|
|
05652b6d1d | ||
|
|
1bb62e3da1 | ||
|
|
7c18ae44c2 | ||
|
|
3f7c30ec29 | ||
|
|
17a593b65f | ||
|
|
f0cdd65937 | ||
|
|
719b384b38 | ||
|
|
ef96db63b8 |
No files matched your search
@@ -1,93 +0,0 @@
|
||||
name: daily-avalonia-native
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '17 3 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
force_build:
|
||||
description: Rebuild even if matching successful Actions artifacts exist
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
concurrency:
|
||||
group: daily-avalonia-native
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
major: [11, 12]
|
||||
steps:
|
||||
- name: Check latest stable Avalonia and dispatch Native build
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
AVALONIA_MAJOR: ${{ matrix.major }}
|
||||
FORCE_BUILD: ${{ inputs.force_build }}
|
||||
NATIVE_BRANCH: avalonia-native
|
||||
PACKAGE_REVISION: '2'
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
repository = os.environ['GITHUB_REPOSITORY']
|
||||
branch = os.environ['NATIVE_BRANCH']
|
||||
major = int(os.environ['AVALONIA_MAJOR'])
|
||||
|
||||
def api(endpoint):
|
||||
return json.loads(subprocess.check_output(['gh', 'api', endpoint], text=True))
|
||||
|
||||
def summary(message):
|
||||
print(message, flush=True)
|
||||
with open(os.environ['GITHUB_STEP_SUMMARY'], 'a', encoding='utf-8') as output:
|
||||
output.write(message + '\n')
|
||||
|
||||
upstream = json.loads(subprocess.check_output([
|
||||
'curl', '--fail', '--silent', '--show-error', '--location', '--retry', '3',
|
||||
'https://api.nuget.org/v3-flatcontainer/avalonia/index.json',
|
||||
], text=True))
|
||||
candidates = [version for version in upstream['versions']
|
||||
if re.fullmatch(r'\d+\.\d+\.\d+', version)
|
||||
and int(version.split('.')[0]) == major]
|
||||
if not candidates:
|
||||
raise SystemExit(f'No stable Avalonia {major} version found')
|
||||
version = max(candidates, key=lambda value: tuple(map(int, value.split('.'))))
|
||||
package_version = version + '.' + os.environ['PACKAGE_REVISION']
|
||||
artifact_name = 'staticlink-avalonia-native-' + package_version
|
||||
head_sha = api(f'repos/{repository}/branches/{branch}')['commit']['sha']
|
||||
if os.environ['FORCE_BUILD'] != 'true':
|
||||
already_validated = False
|
||||
runs = api(f'repos/{repository}/actions/workflows/nuget-avalonia-native.yml/runs'
|
||||
f'?branch={branch}&status=success&per_page=100')['workflow_runs']
|
||||
for run in runs:
|
||||
if run['head_sha'] != head_sha or run['conclusion'] != 'success':
|
||||
continue
|
||||
artifacts = api(f"repos/{repository}/actions/runs/{run['id']}/artifacts?per_page=100")['artifacts']
|
||||
if any(artifact['name'] == artifact_name and not artifact['expired']
|
||||
for artifact in artifacts):
|
||||
summary(f"Already validated {package_version}: {run['html_url']}")
|
||||
already_validated = True
|
||||
break
|
||||
if already_validated:
|
||||
raise SystemExit(0)
|
||||
|
||||
payload = json.dumps({'ref': branch, 'inputs': {
|
||||
'avalonia_version': version, 'force_build': True, 'publish_to_nuget': False,
|
||||
}})
|
||||
subprocess.run([
|
||||
'gh', 'api', '--method', 'POST',
|
||||
f'repos/{repository}/actions/workflows/nuget-avalonia-native.yml/dispatches',
|
||||
'--input', '-',
|
||||
], input=payload, text=True, check=True)
|
||||
summary(f'Dispatched {package_version} on {branch}; Actions artifacts only, no NuGet publication.')
|
||||
PY
|
||||
@@ -1,76 +0,0 @@
|
||||
name: daily-native-release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
force_build:
|
||||
description: Build current stable versions even if already published
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
concurrency:
|
||||
group: daily-native-release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
dispatch:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: [skia3, skia4, avalonia-native]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ matrix.branch }}
|
||||
- name: Check and dispatch this branch
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TRACK_BRANCH: ${{ matrix.branch }}
|
||||
FORCE_BUILD: ${{ inputs.force_build }}
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
branch = os.environ["TRACK_BRANCH"]
|
||||
force = os.environ["FORCE_BUILD"] == "true"
|
||||
|
||||
def dispatch(workflow, inputs):
|
||||
payload = json.dumps({"ref": branch, "inputs": inputs})
|
||||
subprocess.run(
|
||||
["gh", "api", "--method", "POST",
|
||||
f"repos/{os.environ['GITHUB_REPOSITORY']}/actions/workflows/{workflow}/dispatches",
|
||||
"--input", "-"],
|
||||
input=payload, text=True, check=True,
|
||||
)
|
||||
|
||||
if branch == "avalonia-native":
|
||||
dispatch("nuget-avalonia-native.yml", {
|
||||
"force_build": force, "publish_to_nuget": False,
|
||||
})
|
||||
else:
|
||||
command = ["python3", "scripts/check-upstream-releases.py"]
|
||||
if force:
|
||||
command.append("--force")
|
||||
subprocess.run(command, check=True)
|
||||
for release in json.load(open("release-plan.json")):
|
||||
if release["ref"] != branch:
|
||||
raise SystemExit("Release track does not match the checked-out branch")
|
||||
dispatch("nuget-static-graphics.yml", {
|
||||
"skiasharp_version": release["skiasharp_version"],
|
||||
"publish_to_nuget": False, "publish_to_release": False,
|
||||
})
|
||||
print(f"Dispatched {release['package_version']} on {branch}")
|
||||
PY
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ always() && matrix.branch != 'avalonia-native' }}
|
||||
with:
|
||||
name: daily-release-plan-${{ matrix.branch }}
|
||||
path: release-plan.json
|
||||
if-no-files-found: warn
|
||||
@@ -1,10 +1,12 @@
|
||||
name: staticlink-avalonia-native
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "17 3 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
avalonia_version:
|
||||
description: Avalonia version to build; empty checks the latest stable 11.x and 12.x versions
|
||||
description: Avalonia version to build; empty uses the latest stable NuGet version
|
||||
required: false
|
||||
type: string
|
||||
force_build:
|
||||
@@ -15,16 +17,21 @@ on:
|
||||
publish_to_nuget:
|
||||
description: Publish with NuGet Trusted Publishing after smoke tests
|
||||
required: true
|
||||
default: false
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
concurrency:
|
||||
group: staticlink-avalonia-native
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
detect:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
versions: ${{ steps.version.outputs.versions }}
|
||||
avalonia_version: ${{ steps.version.outputs.avalonia_version }}
|
||||
package_version: ${{ steps.version.outputs.package_version }}
|
||||
should_build: ${{ steps.version.outputs.should_build }}
|
||||
steps:
|
||||
- name: Detect unpublished Avalonia version
|
||||
@@ -36,55 +43,38 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ -n "$REQUESTED_VERSION" ]; then
|
||||
candidate_versions=("$REQUESTED_VERSION")
|
||||
else
|
||||
nuget_versions="$(curl --fail --silent --show-error --location \
|
||||
https://api.nuget.org/v3-flatcontainer/avalonia/index.json)"
|
||||
candidate_versions=()
|
||||
for major in 11 12; do
|
||||
candidate_versions+=("$(jq -r --arg major "$major" \
|
||||
'[.versions[] | select(startswith($major + ".") and (contains("-") | not))] | last' \
|
||||
<<< "$nuget_versions")")
|
||||
done
|
||||
avalonia_version="$REQUESTED_VERSION"
|
||||
if [ -z "$avalonia_version" ]; then
|
||||
avalonia_version="$(curl --fail --silent --show-error --location \
|
||||
https://api.nuget.org/v3-flatcontainer/avalonia/index.json \
|
||||
| jq -r '[.versions[] | select(contains("-") | not)] | last')"
|
||||
fi
|
||||
|
||||
versions='[]'
|
||||
for avalonia_version in "${candidate_versions[@]}"; do
|
||||
if [ -z "$avalonia_version" ] || [ "$avalonia_version" = "null" ]; then
|
||||
echo "Could not determine a stable Avalonia version." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
package_version="$avalonia_version.1"
|
||||
package_url="https://api.nuget.org/v3-flatcontainer/staticlink.avalonia.native/$package_version/staticlink.avalonia.native.$package_version.nupkg"
|
||||
if [ "$FORCE_BUILD" != "true" ] && curl --fail --silent --location --output /dev/null "$package_url"; then
|
||||
echo "Already published: $package_version"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Build required: $package_version"
|
||||
versions="$(jq -cn --argjson versions "$versions" \
|
||||
--arg avalonia_version "$avalonia_version" \
|
||||
--arg package_version "$package_version" \
|
||||
'$versions + [{avalonia_version: $avalonia_version, package_version: $package_version}]')"
|
||||
done
|
||||
|
||||
echo "versions=$versions" >> "$GITHUB_OUTPUT"
|
||||
if [ "$versions" = '[]' ]; then
|
||||
echo 'should_build=false' >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo 'should_build=true' >> "$GITHUB_OUTPUT"
|
||||
if [ -z "$avalonia_version" ] || [ "$avalonia_version" = "null" ]; then
|
||||
echo "Could not determine the latest stable Avalonia version." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
package_version="$avalonia_version.1"
|
||||
package_url="https://api.nuget.org/v3-flatcontainer/staticlink.avalonia.native/$package_version/staticlink.avalonia.native.$package_version.nupkg"
|
||||
should_build=true
|
||||
if [ "$FORCE_BUILD" != "true" ] && curl --fail --silent --location --output /dev/null "$package_url"; then
|
||||
should_build=false
|
||||
fi
|
||||
|
||||
echo "Avalonia version: $avalonia_version"
|
||||
echo "StaticLink.Avalonia.Native version: $package_version"
|
||||
echo "Build required: $should_build"
|
||||
echo "avalonia_version=$avalonia_version" >> "$GITHUB_OUTPUT"
|
||||
echo "package_version=$package_version" >> "$GITHUB_OUTPUT"
|
||||
echo "should_build=$should_build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
build:
|
||||
needs: detect
|
||||
if: ${{ needs.detect.outputs.should_build == 'true' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: ${{ fromJSON(needs.detect.outputs.versions) }}
|
||||
rid: [osx-x64, osx-arm64]
|
||||
include:
|
||||
- rid: osx-x64
|
||||
runner: macos-14
|
||||
@@ -95,7 +85,7 @@ jobs:
|
||||
contents: read
|
||||
env:
|
||||
RID: ${{ matrix.rid }}
|
||||
AVALONIA_VERSION: ${{ matrix.version.avalonia_version }}
|
||||
AVALONIA_VERSION: ${{ needs.detect.outputs.avalonia_version }}
|
||||
WORK_DIR: ${{ github.workspace }}/External/AvaloniaNative/.work
|
||||
OUTPUT_DIR: ${{ github.workspace }}/External/AvaloniaNative/${{ matrix.rid }}/native
|
||||
steps:
|
||||
@@ -117,7 +107,7 @@ jobs:
|
||||
- name: Upload static AvaloniaNative
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: native-avalonia-${{ matrix.version.avalonia_version }}-${{ matrix.rid }}
|
||||
name: native-avalonia-${{ matrix.rid }}
|
||||
path: |
|
||||
External/AvaloniaNative/${{ matrix.rid }}/native/libAvaloniaNative.a
|
||||
External/AvaloniaNative/${{ matrix.rid }}/native/macos_font_preinit.o
|
||||
@@ -128,9 +118,6 @@ jobs:
|
||||
- detect
|
||||
- build
|
||||
if: ${{ needs.detect.outputs.should_build == 'true' }}
|
||||
strategy:
|
||||
matrix:
|
||||
version: ${{ fromJSON(needs.detect.outputs.versions) }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -145,7 +132,7 @@ jobs:
|
||||
- name: Download static AvaloniaNative archives
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: native-avalonia-${{ matrix.version.avalonia_version }}-*
|
||||
pattern: native-avalonia-*
|
||||
path: artifacts/native
|
||||
merge-multiple: false
|
||||
|
||||
@@ -155,8 +142,8 @@ jobs:
|
||||
set -euo pipefail
|
||||
for rid in osx-x64 osx-arm64; do
|
||||
mkdir -p "External/AvaloniaNative/$rid/native"
|
||||
cp "artifacts/native/native-avalonia-${{ matrix.version.avalonia_version }}-$rid/libAvaloniaNative.a" "External/AvaloniaNative/$rid/native/"
|
||||
cp "artifacts/native/native-avalonia-${{ matrix.version.avalonia_version }}-$rid/macos_font_preinit.o" "External/AvaloniaNative/$rid/native/"
|
||||
cp "artifacts/native/native-avalonia-$rid/libAvaloniaNative.a" "External/AvaloniaNative/$rid/native/"
|
||||
cp "artifacts/native/native-avalonia-$rid/macos_font_preinit.o" "External/AvaloniaNative/$rid/native/"
|
||||
done
|
||||
|
||||
- name: Pack StaticLink.Avalonia.Native
|
||||
@@ -164,13 +151,13 @@ jobs:
|
||||
dotnet pack NuGet/AvaloniaNative/StaticLink.Avalonia.Native.csproj \
|
||||
-c Release \
|
||||
-o artifacts/nuget \
|
||||
/p:PackageVersion=${{ matrix.version.package_version }} \
|
||||
/p:Version=${{ matrix.version.package_version }}
|
||||
/p:PackageVersion=${{ needs.detect.outputs.package_version }} \
|
||||
/p:Version=${{ needs.detect.outputs.package_version }}
|
||||
|
||||
- name: Upload NuGet package
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: staticlink-avalonia-native-${{ matrix.version.package_version }}
|
||||
name: staticlink-avalonia-native-${{ needs.detect.outputs.package_version }}
|
||||
path: artifacts/nuget/*.nupkg
|
||||
if-no-files-found: error
|
||||
|
||||
@@ -182,8 +169,6 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: ${{ fromJSON(needs.detect.outputs.versions) }}
|
||||
rid: [osx-x64, osx-arm64]
|
||||
include:
|
||||
- rid: osx-x64
|
||||
runner: macos-14
|
||||
@@ -203,7 +188,7 @@ jobs:
|
||||
- name: Download NuGet package
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: staticlink-avalonia-native-${{ matrix.version.package_version }}
|
||||
name: staticlink-avalonia-native-${{ needs.detect.outputs.package_version }}
|
||||
path: artifacts/nuget
|
||||
|
||||
- name: Publish Avalonia NativeAOT smoke app
|
||||
@@ -213,8 +198,8 @@ jobs:
|
||||
pwsh ./scripts/create-avalonia-smoke.ps1 `
|
||||
-ProjectDir $projectDir `
|
||||
-NuGetSource (Resolve-Path "artifacts/nuget") `
|
||||
-AvaloniaVersion "${{ matrix.version.avalonia_version }}" `
|
||||
-StaticLinkNativeVersion "${{ matrix.version.package_version }}"
|
||||
-AvaloniaVersion "${{ needs.detect.outputs.avalonia_version }}" `
|
||||
-StaticLinkNativeVersion "${{ needs.detect.outputs.package_version }}"
|
||||
dotnet publish (Join-Path $projectDir "AvaloniaStaticLinkSmoke.csproj") `
|
||||
-c Release `
|
||||
-r "${{ matrix.rid }}" `
|
||||
@@ -263,9 +248,6 @@ jobs:
|
||||
- detect
|
||||
- smoke
|
||||
if: ${{ needs.detect.outputs.should_build == 'true' && (github.event_name == 'schedule' || inputs.publish_to_nuget == true) }}
|
||||
strategy:
|
||||
matrix:
|
||||
version: ${{ fromJSON(needs.detect.outputs.versions) }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -274,7 +256,7 @@ jobs:
|
||||
- name: Download NuGet package
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: staticlink-avalonia-native-${{ matrix.version.package_version }}
|
||||
name: staticlink-avalonia-native-${{ needs.detect.outputs.package_version }}
|
||||
path: artifacts/nuget
|
||||
|
||||
- name: Validate Trusted Publishing configuration
|
||||
|
||||
@@ -360,103 +360,11 @@ jobs:
|
||||
path: artifacts/smoke-${{ matrix.rid }}/**
|
||||
if-no-files-found: error
|
||||
|
||||
smoke-macos-metal:
|
||||
runs-on: macos-15
|
||||
needs: pack
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: "10.0.302"
|
||||
|
||||
- name: Download NuGet package
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: staticlink-avalonia-nuget
|
||||
path: artifacts/nuget
|
||||
|
||||
- name: Publish Avalonia 12 macOS arm64 smoke app
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
$package = Get-ChildItem -Path "artifacts/nuget" -Filter "StaticLink.Avalonia.*.nupkg" | Where-Object { $_.Name -notlike "StaticLink.Avalonia.Native.*" } | Select-Object -First 1
|
||||
if (-not $package) { throw "StaticLink NuGet package was not downloaded." }
|
||||
if ($package.BaseName -notmatch '^StaticLink\.Avalonia\.(.+)$') { throw "Unexpected package name: $($package.Name)" }
|
||||
$projectDir = Join-Path $PWD "artifacts/avalonia-metal-smoke-src"
|
||||
pwsh ./scripts/create-avalonia-smoke.ps1 `
|
||||
-ProjectDir $projectDir `
|
||||
-NuGetSource (Resolve-Path "artifacts/nuget") `
|
||||
-StaticLinkVersion $Matches[1] `
|
||||
-AvaloniaVersion "12.1.0" `
|
||||
-StaticLinkNativeVersion "12.1.0.1"
|
||||
dotnet publish (Join-Path $projectDir "AvaloniaStaticLinkSmoke.csproj") `
|
||||
-c Release `
|
||||
-r osx-arm64 `
|
||||
--configfile (Join-Path $projectDir "NuGet.config") `
|
||||
/p:PublishAot=true `
|
||||
/p:SelfContained=true `
|
||||
/p:PublishSingleFile=true `
|
||||
/p:StripSymbols=true `
|
||||
/p:PublishDir="$PWD/artifacts/smoke-osx-arm64-metal/"
|
||||
|
||||
- name: Verify fully static third-party libraries
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
publish_dir="artifacts/smoke-osx-arm64-metal"
|
||||
test -x "$publish_dir/AvaloniaStaticLinkSmoke"
|
||||
for library in libAvaloniaNative.dylib libSkiaSharp.dylib libHarfBuzzSharp.dylib; do
|
||||
test ! -f "$publish_dir/$library"
|
||||
done
|
||||
|
||||
- name: Run default and Metal-only smoke tests
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd artifacts/smoke-osx-arm64-metal
|
||||
python3 - <<'PY'
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
|
||||
for renderer in ("default", "metal"):
|
||||
environment = os.environ.copy()
|
||||
environment["STATICLINK_MAC_RENDERER"] = renderer
|
||||
environment["STATICLINK_SMOKE_AUTOCLOSE"] = "1"
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["./AvaloniaStaticLinkSmoke"],
|
||||
env=environment,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
timeout=15,
|
||||
)
|
||||
except subprocess.TimeoutExpired as exception:
|
||||
output = exception.stdout or ""
|
||||
if isinstance(output, bytes):
|
||||
output = output.decode(errors="replace")
|
||||
pathlib.Path(f"avalonia-{renderer}.log").write_text(output)
|
||||
raise SystemExit(f"Avalonia {renderer} smoke app timed out.\n{output}")
|
||||
|
||||
output = result.stdout or ""
|
||||
pathlib.Path(f"avalonia-{renderer}.log").write_text(output)
|
||||
print(output, end="")
|
||||
marker = f"STATICLINK_SMOKE_READY={renderer}"
|
||||
if result.returncode != 0 or marker not in output.splitlines():
|
||||
raise SystemExit(f"Avalonia {renderer} smoke app failed with exit code {result.returncode}.")
|
||||
PY
|
||||
|
||||
publish-nuget:
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- pack
|
||||
- smoke-avalonia
|
||||
- smoke-macos-metal
|
||||
steps:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
@@ -492,7 +400,6 @@ jobs:
|
||||
- preflight
|
||||
- pack
|
||||
- smoke-avalonia
|
||||
- smoke-macos-metal
|
||||
- publish-nuget
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/staticlink-avalonia-v') || (github.event_name == 'workflow_dispatch' && inputs.publish_to_release == true) }}
|
||||
permissions:
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Manual artifact validation
|
||||
|
||||
Native daily checks are enabled by daily-avalonia-native.yml on main at 03:17
|
||||
UTC (11:17 Singapore time). Skia3/4 daily schedules remain disabled. No
|
||||
NuGet.org publication or GitHub Release is requested by either dispatcher.
|
||||
|
||||
The Native checker handles the latest stable Avalonia 11 and 12 independently.
|
||||
It skips versions with non-expired NuGet artifacts from a successful Native
|
||||
run at the current avalonia-native branch commit. New versions, changed Native
|
||||
code, expired artifacts, or failed builds trigger a new artifact-only build.
|
||||
Set force_build=true on the daily checker to bypass this successful-run check.
|
||||
|
||||
Before release builds, run nuget-static-graphics.yml on skia4 with
|
||||
environment_only=true. This checks the actual container's Python/depot_tools,
|
||||
.NET 8/10, SDKs, sysroots, and C/C++ compilation plus C executable linking for
|
||||
all nine RIDs. Download toolchain-environment-validation to inspect the report.
|
||||
The same environment gate runs before every graphics and native build and
|
||||
must pass before the toolchain image is published for release compilation.
|
||||
|
||||
- skia3: nuget-static-graphics.yml; latest stable SkiaSharp 3.
|
||||
- skia4: nuget-static-graphics.yml; latest stable SkiaSharp 4.
|
||||
- avalonia-native: nuget-avalonia-native.yml; latest stable Avalonia 11 and 12.
|
||||
|
||||
Download staticlink-avalonia-nuget and avalonia-smoke-<RID> from each graphics run.
|
||||
Download staticlink-avalonia-native-<version> and
|
||||
avalonia-native-smoke-<AvaloniaVersion>-<RID> from the native run.
|
||||
Native archives and source locks are also retained as Actions artifacts.
|
||||
|
||||
Graphics macOS smoke tests use the already published AvaloniaNative revision 1
|
||||
by default, so the graphics builds do not require the experimental native
|
||||
revision 2 to be published. The native branch validates its own local revision 2
|
||||
package separately. To test both experimental packages together, put both
|
||||
downloaded packages in a local NuGet feed and reference their exact versions.
|
||||
|
||||
Smoke executables are retained even if a later runtime validation fails.
|
||||
An artifact is not evidence that all validation gates passed; check job results.
|
||||
|
||||
The daily-native-release workflow on main currently supports manual dispatch
|
||||
only. Its three matrix jobs check out their own branch and dispatch independently.
|
||||
Use force_build=true to rebuild published versions for testing.
|
||||
After validation, enable the schedule on main only; non-default branches cannot
|
||||
run their own GitHub cron schedules. Publication remains an explicit opt-in.
|
||||
The manual graphics dispatcher still checks publication rather than successful
|
||||
Actions runs. Add the same successful-run tracking before enabling artifact-only
|
||||
daily graphics builds if avoiding repeated builds is required.
|
||||
@@ -4,48 +4,32 @@ Static native libraries for Avalonia single-file NativeAOT publishing.
|
||||
|
||||
## Install
|
||||
|
||||
Choose the static graphics package that matches the Avalonia and SkiaSharp major versions used by your application.
|
||||
|
||||
| Avalonia version | SkiaSharp version | `StaticLink.Avalonia` version |
|
||||
| --- | --- | --- |
|
||||
| 11 | 2.88.9 | `2.88.9-7151.10` |
|
||||
| 11 | 3.119.4 | `3.119.4-7922.1` |
|
||||
| 12 | 3.119.4 | `3.119.4-7922.1` |
|
||||
| 12 | 4.150.1 | `4.150.1-7922.1` |
|
||||
|
||||
Example:
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="12.1.0" />
|
||||
<PackageReference Include="StaticLink.Avalonia" Version="4.150.1-7922.1" />
|
||||
</ItemGroup>
|
||||
```bash
|
||||
dotnet add package StaticLink.Avalonia
|
||||
```
|
||||
|
||||
### macOS
|
||||
Or add it manually:
|
||||
|
||||
For macOS, also reference `StaticLink.Avalonia.Native`. This package contains `libAvaloniaNative.a`, so its version must match the Avalonia version used by the application.
|
||||
```xml
|
||||
<PackageReference Include="StaticLink.Avalonia" Version="4.150.1-7922.1" />
|
||||
```
|
||||
|
||||
For macOS, also reference `StaticLink.Avalonia.Native`. This package is macOS-only and must match your Avalonia version because it contains `libAvaloniaNative.a`.
|
||||
|
||||
```xml
|
||||
<!-- Avalonia 11.3.14 -->
|
||||
<PackageReference Include="StaticLink.Avalonia.Native" Version="11.3.14.1" />
|
||||
|
||||
<!-- Avalonia 12.1.0 -->
|
||||
<PackageReference Include="StaticLink.Avalonia.Native" Version="12.1.0.1" />
|
||||
```
|
||||
|
||||
Add only the `StaticLink.Avalonia.Native` reference matching your Avalonia version.
|
||||
|
||||
On macOS, only Avalonia 12 with skia3/4 supports Metal. Avalonia 11 fully static apps must use OpenGL or Software because its Metal path dynamically loads `libSkiaSharp`.
|
||||
|
||||
## Publish
|
||||
|
||||
```bash
|
||||
dotnet publish -c Release -r win-x64 -p:PublishAot=true
|
||||
dotnet publish -c Release -r win-x64 \
|
||||
-p:PublishAot=true \
|
||||
-p:SelfContained=true \
|
||||
-p:PublishSingleFile=true \
|
||||
-p:StripSymbols=true
|
||||
```
|
||||
|
||||
Use the RID you need, such as `win-x86`, `linux-x64`, `linux-arm64`, `osx-arm64`, or `osx-x64`.
|
||||
|
||||
|
||||
## Native Package Automation
|
||||
|
||||
`.github/workflows/nuget-avalonia-native.yml` runs daily and checks the latest stable `Avalonia` version on NuGet.org. If `StaticLink.Avalonia.Native.<AvaloniaVersion>.1` does not exist, it builds both macOS architectures from the matching Avalonia source tag, runs NativeAOT smoke tests, and publishes the package with NuGet Trusted Publishing.
|
||||
For macOS, avoid the Metal renderer for fully static output. Use OpenGL or Software.
|
||||
@@ -4,48 +4,59 @@ Static native libraries for Avalonia single-file NativeAOT publishing.
|
||||
|
||||
## Install
|
||||
|
||||
Choose the static graphics package that matches the Avalonia and SkiaSharp major versions used by your application.
|
||||
|
||||
| Avalonia version | SkiaSharp version | `StaticLink.Avalonia` version |
|
||||
| --- | --- | --- |
|
||||
| 11 | 2.88.9 | `2.88.9-7151.10` |
|
||||
| 11 | 3.119.4 | `3.119.4-7922.1` |
|
||||
| 12 | 3.119.4 | `3.119.4-7922.1` |
|
||||
| 12 | 4.150.1 | `4.150.1-7922.1` |
|
||||
|
||||
Example:
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="12.1.0" />
|
||||
<PackageReference Include="StaticLink.Avalonia" Version="4.150.1-7922.1" />
|
||||
</ItemGroup>
|
||||
```bash
|
||||
dotnet add package StaticLink.Avalonia
|
||||
```
|
||||
|
||||
### macOS
|
||||
Or add it manually:
|
||||
|
||||
For macOS, also reference `StaticLink.Avalonia.Native`. This package contains `libAvaloniaNative.a`, so its version must match the Avalonia version used by the application.
|
||||
```xml
|
||||
<PackageReference Include="StaticLink.Avalonia" Version="4.150.1-7922.1" />
|
||||
```
|
||||
|
||||
`4.150.1-7922.1` uses the latest stable SkiaSharp 4 release. If you need the SkiaSharp 2 line for an Avalonia 11 project, use this optional package variant:
|
||||
|
||||
```xml
|
||||
<PackageReference Include="StaticLink.Avalonia" Version="2.88.9-7151.10" />
|
||||
```
|
||||
|
||||
`2.88.9-7151.10` is only for Avalonia 11 projects that specifically want SkiaSharp 2.
|
||||
|
||||
For macOS, also reference `StaticLink.Avalonia.Native`. This package is macOS-only and must match your Avalonia version because it contains `libAvaloniaNative.a`.
|
||||
|
||||
```xml
|
||||
<!-- Avalonia 11.3.14 -->
|
||||
<PackageReference Include="StaticLink.Avalonia.Native" Version="11.3.14.1" />
|
||||
|
||||
<!-- Avalonia 12.1.0 -->
|
||||
<PackageReference Include="StaticLink.Avalonia.Native" Version="12.1.0.1" />
|
||||
```
|
||||
|
||||
Add only the `StaticLink.Avalonia.Native` reference matching your Avalonia version.
|
||||
|
||||
On macOS, only Avalonia 12 with skia3/4 supports Metal. Avalonia 11 fully static apps must use OpenGL or Software because its Metal path dynamically loads `libSkiaSharp`.
|
||||
|
||||
## Publish
|
||||
|
||||
```bash
|
||||
dotnet publish -c Release -r win-x64 -p:PublishAot=true
|
||||
dotnet publish -c Release -r win-x64 \
|
||||
-p:PublishAot=true \
|
||||
-p:SelfContained=true \
|
||||
-p:PublishSingleFile=true \
|
||||
-p:StripSymbols=true
|
||||
```
|
||||
|
||||
Use the RID you need, such as `win-x86`, `linux-x64`, `linux-arm64`, `osx-arm64`, or `osx-x64`.
|
||||
|
||||
For macOS, avoid the Metal renderer for fully static output. Use OpenGL or Software.
|
||||
|
||||
## Native Package Automation
|
||||
|
||||
`.github/workflows/nuget-avalonia-native.yml` runs daily and checks the latest stable `Avalonia` version on NuGet.org. If `StaticLink.Avalonia.Native.<AvaloniaVersion>.1` does not exist, it builds both macOS architectures from the matching Avalonia source tag, runs NativeAOT smoke tests, and publishes the package with NuGet Trusted Publishing.
|
||||
`.github/workflows/nuget-avalonia-native.yml` runs daily and checks the latest stable `Avalonia` version on NuGet.org. If `StaticLink.Avalonia.Native.<AvaloniaVersion>.1` does not exist, it builds both macOS architectures from the matching Avalonia source tag, runs NativeAOT smoke tests, and publishes the package with NuGet Trusted Publishing.
|
||||
|
||||
Configure NuGet.org Trusted Publishing for this repository and the `nuget-avalonia-native.yml` workflow, then add the NuGet.org account name as the repository variable `NUGET_USER`. No long-lived NuGet API key is used by this workflow.
|
||||
|
||||
## Static Graphics Automation
|
||||
|
||||
`.github/workflows/nuget-static-graphics.yml` runs a fast version, upstream-ref, patch, script, and smoke-project preflight before starting native builds. It then calls independent Windows, Linux, Linux musl, and macOS workflows, packs their artifacts, runs all NativeAOT smoke tests, and only then publishes NuGet and GitHub Release assets.
|
||||
|
||||
The platform workflows can also be dispatched independently when diagnosing a single platform:
|
||||
|
||||
- `static-graphics-windows.yml`
|
||||
- `static-graphics-linux.yml`
|
||||
- `static-graphics-musl.yml`
|
||||
- `static-graphics-macos.yml`
|
||||
|
||||
The release workflow derives the SkiaSharp version and ANGLE branch from `NuGet/StaticGraphics/StaticLink.Avalonia.csproj`. Native source and build directories are cached by platform, RID, version, patch, and build script.
|
||||
@@ -1,7 +1,6 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace AvaloniaStaticLinkSmoke;
|
||||
|
||||
@@ -16,28 +15,7 @@ public sealed partial class App : Application
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var renderer = Environment.GetEnvironmentVariable("STATICLINK_MAC_RENDERER") ?? "opengl";
|
||||
var autoClose = Environment.GetEnvironmentVariable("STATICLINK_SMOKE_AUTOCLOSE") == "1";
|
||||
desktop.MainWindow = new MainWindow(autoClose ? CompleteSmoke : null);
|
||||
|
||||
void CompleteSmoke(string backend)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (!renderer.Equals("metal", StringComparison.OrdinalIgnoreCase) ||
|
||||
backend.Equals("Metal", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Console.WriteLine($"STATICLINK_SMOKE_READY={renderer}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine($"Expected the Metal renderer, but the active Skia backend was {backend}.");
|
||||
Environment.ExitCode = 1;
|
||||
}
|
||||
|
||||
desktop.MainWindow?.Close();
|
||||
});
|
||||
}
|
||||
desktop.MainWindow = new MainWindow();
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
|
||||
@@ -1,60 +1,11 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Rendering.SceneGraph;
|
||||
using Avalonia.Skia;
|
||||
|
||||
namespace AvaloniaStaticLinkSmoke;
|
||||
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
private readonly Action<string>? _renderResult;
|
||||
private int _renderResultReported;
|
||||
|
||||
public MainWindow() : this(null)
|
||||
public MainWindow()
|
||||
{
|
||||
}
|
||||
|
||||
public MainWindow(Action<string>? renderResult)
|
||||
{
|
||||
_renderResult = renderResult;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
base.Render(context);
|
||||
if (_renderResult is not null)
|
||||
{
|
||||
context.Custom(new MetalBackendProbe(new Rect(Bounds.Size), ReportMetalResult));
|
||||
}
|
||||
}
|
||||
|
||||
private void ReportMetalResult(string backend)
|
||||
{
|
||||
if (Interlocked.Exchange(ref _renderResultReported, 1) == 0)
|
||||
{
|
||||
_renderResult?.Invoke(backend);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class MetalBackendProbe(Rect bounds, Action<string> report) : ICustomDrawOperation
|
||||
{
|
||||
public Rect Bounds { get; } = bounds;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(ICustomDrawOperation? other) => false;
|
||||
|
||||
public bool HitTest(Point point) => false;
|
||||
|
||||
public void Render(ImmediateDrawingContext context)
|
||||
{
|
||||
var feature = context.TryGetFeature(typeof(ISkiaSharpApiLeaseFeature)) as ISkiaSharpApiLeaseFeature;
|
||||
using var lease = feature?.Lease();
|
||||
report(lease?.GrContext?.Backend.ToString() ?? "Software");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,16 +39,14 @@ internal static class Program
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
var renderer = Environment.GetEnvironmentVariable("STATICLINK_MAC_RENDERER");
|
||||
if (!string.Equals(renderer, "default", StringComparison.OrdinalIgnoreCase))
|
||||
builder = builder.With(new AvaloniaNativePlatformOptions
|
||||
{
|
||||
builder = builder.With(new AvaloniaNativePlatformOptions
|
||||
{
|
||||
RenderingMode = string.Equals(renderer, "metal", StringComparison.OrdinalIgnoreCase)
|
||||
? [AvaloniaNativeRenderingMode.Metal]
|
||||
: [AvaloniaNativeRenderingMode.OpenGl, AvaloniaNativeRenderingMode.Software]
|
||||
});
|
||||
}
|
||||
RenderingMode =
|
||||
[
|
||||
AvaloniaNativeRenderingMode.OpenGl,
|
||||
AvaloniaNativeRenderingMode.Software
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
return builder;
|
||||
|
||||
@@ -26,12 +26,7 @@ if git -C "$src" config -f .gitmodules --get-regexp path | grep -q 'external/Num
|
||||
fi
|
||||
|
||||
if [[ ! -f "$src/native/Avalonia.Native/inc/avalonia-native.h" ]]; then
|
||||
header_project="$src/native/Avalonia.Native/Avalonia.Native.macOS.proj"
|
||||
if [[ -f "$header_project" ]]; then
|
||||
dotnet build "$header_project" -t:GenerateMicroComItems
|
||||
else
|
||||
bash "$src/native/Avalonia.Native/generate-headers.sh"
|
||||
fi
|
||||
bash "$src/native/Avalonia.Native/generate-headers.sh"
|
||||
fi
|
||||
|
||||
project="$src/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj"
|
||||
|
||||
Reference in new issue
Block a user