mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
Replace UI DispatcherTimer polling with a StudySnapshotRenderGate across multiple widgets to queue and apply only the latest analytics snapshot; components updated include StudyDeductionReasonsWidget, StudyEnvironmentWidget, StudyInterruptDensityWidget, StudyNoiseCurveWidget. Add StudySnapshotRenderGate implementation to coordinate rendering and monitoring leases and update subscription/lease lifecycle handling (subscribe/unsubscribe, Acquire/Dispose leases, Clear/Dispose gate). Rewrite chart controls (StudyNoiseCurveChartControl and StudyNoiseDistributionScatterChartControl) to use stable logical-time origins, split series into static vs dynamic tails, add geometry/sample caching, stable jitter/coordinate mapping helpers, and expose internal helpers & counts for testing. Add unit tests (StudyComponentRenderingTests) covering the render gate and chart behaviors (layer counts, logical X mapping, stable jitter, cache rebuild). These changes improve rendering correctness and performance by avoiding redundant renders and enabling deterministic chart layout.
274 lines
10 KiB
YAML
274 lines
10 KiB
YAML
name: PLONDS
|
|
|
|
on:
|
|
release:
|
|
types:
|
|
- published
|
|
- prereleased
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: 'Release tag'
|
|
required: true
|
|
type: string
|
|
baseline_tag:
|
|
description: 'Optional baseline tag'
|
|
required: false
|
|
type: string
|
|
channel:
|
|
description: 'Update channel'
|
|
required: false
|
|
type: choice
|
|
default: stable
|
|
options:
|
|
- stable
|
|
- preview
|
|
|
|
env:
|
|
DOTNET_VERSION: '10.0.x'
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
submodules: recursive
|
|
|
|
- name: Resolve release context
|
|
shell: bash
|
|
run: |
|
|
if [[ "${{ github.event_name }}" == "release" ]]; then
|
|
TAG="${{ github.event.release.tag_name }}"
|
|
if [[ "${{ github.event.release.prerelease }}" == "true" ]]; then
|
|
CHANNEL="preview"
|
|
else
|
|
CHANNEL="stable"
|
|
fi
|
|
BASELINE_TAG=""
|
|
else
|
|
RAW_TAG="${{ github.event.inputs.tag }}"
|
|
if [[ "${RAW_TAG}" == v* ]]; then
|
|
TAG="${RAW_TAG}"
|
|
else
|
|
TAG="v${RAW_TAG}"
|
|
fi
|
|
CHANNEL="${{ github.event.inputs.channel }}"
|
|
BASELINE_TAG="${{ github.event.inputs.baseline_tag }}"
|
|
fi
|
|
|
|
echo "RELEASE_TAG=${TAG}" >> "$GITHUB_ENV"
|
|
echo "RELEASE_VERSION=${TAG#v}" >> "$GITHUB_ENV"
|
|
echo "RELEASE_CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
|
|
echo "BASELINE_TAG_INPUT=${BASELINE_TAG}" >> "$GITHUB_ENV"
|
|
PUBLIC_BASE="${{ vars.S3_PUBLIC_BASE_URL }}"
|
|
if [[ -z "$PUBLIC_BASE" ]]; then
|
|
PUBLIC_BASE="https://cn-nb1.rains3.com/lmdesktop/lanmountain/update"
|
|
fi
|
|
echo "S3_PUBLIC_BASE_URL=${PUBLIC_BASE%/}" >> "$GITHUB_ENV"
|
|
|
|
- name: Setup .NET
|
|
uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: ${{ env.DOTNET_VERSION }}
|
|
dotnet-quality: preview
|
|
|
|
- name: Prepare signing key
|
|
env:
|
|
UPDATE_PRIVATE_KEY_PEM: ${{ secrets.UPDATE_PRIVATE_KEY_PEM }}
|
|
PLONDS_SIGNING_KEY: ${{ secrets.PLONDS_SIGNING_KEY }}
|
|
PDC_SIGNING_KEY: ${{ secrets.PDC_SIGNING_KEY }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
KEY="${PLONDS_SIGNING_KEY:-}"
|
|
if [[ -z "$KEY" ]]; then KEY="${UPDATE_PRIVATE_KEY_PEM:-}"; fi
|
|
if [[ -z "$KEY" ]]; then KEY="${PDC_SIGNING_KEY:-}"; fi
|
|
if [[ -z "$KEY" ]]; then
|
|
echo "No signing key is configured."
|
|
exit 1
|
|
fi
|
|
printf '%s' "$KEY" > update-private-key.pem
|
|
echo "UPDATE_PRIVATE_KEY_PATH=$PWD/update-private-key.pem" >> "$GITHUB_ENV"
|
|
|
|
- name: Build PLONDS tool
|
|
run: dotnet build PenguinLogisticsOnlineNetworkDistributionSystem/src/Plonds.Tool/Plonds.Tool.csproj -c Release
|
|
|
|
- name: Resolve baseline plan
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$repo = '${{ github.repository }}'
|
|
$tag = $env:RELEASE_TAG
|
|
$baselineInput = $env:BASELINE_TAG_INPUT
|
|
$currentRelease = gh release view $tag --repo $repo --json tagName,isPrerelease,assets,publishedAt | ConvertFrom-Json
|
|
$allReleases = gh api "repos/$repo/releases?per_page=100" | ConvertFrom-Json
|
|
$platforms = @('windows-x64', 'windows-x86', 'linux-x64')
|
|
|
|
$entries = foreach ($platform in $platforms) {
|
|
$assetName = "files-$platform.zip"
|
|
$currentAsset = $currentRelease.assets | Where-Object { $_.name -eq $assetName } | Select-Object -First 1
|
|
if (-not $currentAsset) {
|
|
throw "Current release $tag does not contain required asset $assetName"
|
|
}
|
|
|
|
$baselineRelease = $null
|
|
if (-not [string]::IsNullOrWhiteSpace($baselineInput)) {
|
|
$normalizedBaseline = if ($baselineInput.StartsWith('v')) { $baselineInput } else { "v$baselineInput" }
|
|
$baselineRelease = $allReleases | Where-Object { $_.tag_name -eq $normalizedBaseline } | Select-Object -First 1
|
|
if (-not $baselineRelease) {
|
|
throw "Specified baseline tag not found: $normalizedBaseline"
|
|
}
|
|
}
|
|
else {
|
|
$baselineRelease = $allReleases |
|
|
Where-Object {
|
|
$_.tag_name -ne $tag -and
|
|
-not $_.draft -and
|
|
[bool]$_.prerelease -eq [bool]$currentRelease.isPrerelease -and
|
|
($_.assets | Where-Object { $_.name -eq $assetName } | Measure-Object).Count -gt 0
|
|
} |
|
|
Select-Object -First 1
|
|
}
|
|
|
|
[pscustomobject]@{
|
|
platform = $platform
|
|
assetName = $assetName
|
|
baselineTag = if ($baselineRelease) { $baselineRelease.tag_name } else { $null }
|
|
baselineVersion = if ($baselineRelease) { ($baselineRelease.tag_name -replace '^v', '') } else { $null }
|
|
isFullPayload = -not $baselineRelease
|
|
}
|
|
}
|
|
|
|
$plan = [pscustomobject]@{
|
|
tag = $tag
|
|
version = $env:RELEASE_VERSION
|
|
channel = $env:RELEASE_CHANNEL
|
|
platforms = $entries
|
|
}
|
|
|
|
$plan | ConvertTo-Json -Depth 8 | Set-Content plonds-plan.json -Encoding utf8
|
|
Get-Content plonds-plan.json
|
|
|
|
- name: Download payload zips
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$repo = '${{ github.repository }}'
|
|
$plan = Get-Content plonds-plan.json | ConvertFrom-Json
|
|
|
|
foreach ($entry in $plan.platforms) {
|
|
$currentDir = Join-Path $PWD "plonds-input/current/$($entry.platform)"
|
|
New-Item -ItemType Directory -Path $currentDir -Force | Out-Null
|
|
gh release download $plan.tag --repo $repo -p $entry.assetName -D $currentDir
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($entry.baselineTag)) {
|
|
$baselineDir = Join-Path $PWD "plonds-input/baseline/$($entry.platform)"
|
|
New-Item -ItemType Directory -Path $baselineDir -Force | Out-Null
|
|
gh release download $entry.baselineTag --repo $repo -p $entry.assetName -D $baselineDir
|
|
}
|
|
}
|
|
|
|
- name: Build delta assets
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$plan = Get-Content plonds-plan.json | ConvertFrom-Json
|
|
foreach ($entry in $plan.platforms) {
|
|
$currentZip = Join-Path $PWD "plonds-input/current/$($entry.platform)/$($entry.assetName)"
|
|
$args = @(
|
|
'run', '--project', 'PenguinLogisticsOnlineNetworkDistributionSystem/src/Plonds.Tool/Plonds.Tool.csproj', '--configuration', 'Release', '--',
|
|
'build-delta',
|
|
'--platform', $entry.platform,
|
|
'--current-version', $plan.version,
|
|
'--current-tag', $plan.tag,
|
|
'--current-zip', $currentZip,
|
|
'--output-dir', 'plonds-output',
|
|
'--private-key', $env:UPDATE_PRIVATE_KEY_PATH,
|
|
'--channel', $plan.channel,
|
|
'--static-output-dir', 'plonds-output/static',
|
|
'--update-base-url', $env:S3_PUBLIC_BASE_URL
|
|
)
|
|
|
|
if ([bool]$entry.isFullPayload) {
|
|
$args += @('--is-full-payload', 'true')
|
|
}
|
|
else {
|
|
$baselineZip = Join-Path $PWD "plonds-input/baseline/$($entry.platform)/$($entry.assetName)"
|
|
$args += @('--baseline-tag', $entry.baselineTag, '--baseline-version', $entry.baselineVersion, '--baseline-zip', $baselineZip)
|
|
}
|
|
|
|
dotnet @args
|
|
}
|
|
|
|
dotnet run --project PenguinLogisticsOnlineNetworkDistributionSystem/src/Plonds.Tool/Plonds.Tool.csproj --configuration Release -- `
|
|
build-index `
|
|
--release-tag $plan.tag `
|
|
--version $plan.version `
|
|
--channel $plan.channel `
|
|
--platform-summaries-dir plonds-output/platform-summaries `
|
|
--output-dir plonds-output `
|
|
--private-key $env:UPDATE_PRIVATE_KEY_PATH
|
|
|
|
foreach ($entry in $plan.platforms) {
|
|
$summary = Get-Content "plonds-output/platform-summaries/platform-summary-$($entry.platform).json" | ConvertFrom-Json
|
|
$required = @(
|
|
"plonds-output/static/meta/channels/$($plan.channel)/$($entry.platform)/latest.json",
|
|
"plonds-output/static/meta/distributions/$($summary.distributionId).json",
|
|
"plonds-output/static/manifests/$($summary.distributionId)/plonds-filemap.json",
|
|
"plonds-output/static/manifests/$($summary.distributionId)/plonds-filemap.json.sig"
|
|
)
|
|
|
|
foreach ($path in $required) {
|
|
if (-not (Test-Path $path)) {
|
|
throw "Missing PLONDS static output: $path"
|
|
}
|
|
}
|
|
}
|
|
|
|
$objects = Get-ChildItem -Path "plonds-output/static/repo/sha256" -File -Recurse -ErrorAction SilentlyContinue
|
|
if (-not $objects -or $objects.Count -eq 0) {
|
|
throw "PLONDS static object repository is empty."
|
|
}
|
|
|
|
Compress-Archive -Path "plonds-output/static/*" -DestinationPath "plonds-output/release-assets/plonds-static.zip" -Force
|
|
|
|
- name: Upload PLONDS assets to release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
gh release upload "$RELEASE_TAG" plonds-output/release-assets/* --clobber
|
|
|
|
- name: Persist run metadata
|
|
shell: bash
|
|
run: |
|
|
mkdir -p plonds-run-metadata
|
|
printf '%s' "$RELEASE_TAG" > plonds-run-metadata/tag.txt
|
|
|
|
- name: Upload run metadata artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: plonds-run-metadata
|
|
path: plonds-run-metadata/tag.txt
|
|
if-no-files-found: error
|
|
retention-days: 7
|
|
|
|
- name: Upload PLONDS static artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: plonds-static
|
|
path: plonds-output/static/**
|
|
if-no-files-found: error
|
|
retention-days: 7
|