mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
changed.PLONDS启动
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
name: PLONDS
|
name: PLONDS Comparator
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: plonds-${{ github.event_name }}-${{ github.event.release.tag_name || github.event.inputs.tag || github.run_id }}
|
group: plonds-${{ github.event_name }}-${{ github.event.release.tag_name || github.event.inputs.tag || github.run_id }}
|
||||||
@@ -87,13 +87,11 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
UPDATE_PRIVATE_KEY_PEM: ${{ secrets.UPDATE_PRIVATE_KEY_PEM }}
|
UPDATE_PRIVATE_KEY_PEM: ${{ secrets.UPDATE_PRIVATE_KEY_PEM }}
|
||||||
PLONDS_SIGNING_KEY: ${{ secrets.PLONDS_SIGNING_KEY }}
|
PLONDS_SIGNING_KEY: ${{ secrets.PLONDS_SIGNING_KEY }}
|
||||||
PDC_SIGNING_KEY: ${{ secrets.PDC_SIGNING_KEY }}
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
KEY="${PLONDS_SIGNING_KEY:-}"
|
KEY="${PLONDS_SIGNING_KEY:-}"
|
||||||
if [[ -z "$KEY" ]]; then KEY="${UPDATE_PRIVATE_KEY_PEM:-}"; fi
|
if [[ -z "$KEY" ]]; then KEY="${UPDATE_PRIVATE_KEY_PEM:-}"; fi
|
||||||
if [[ -z "$KEY" ]]; then KEY="${PDC_SIGNING_KEY:-}"; fi
|
|
||||||
if [[ -z "$KEY" ]]; then
|
if [[ -z "$KEY" ]]; then
|
||||||
echo "No signing key is configured."
|
echo "No signing key is configured."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: DDSS Rollback
|
name: PLONDS Rollback
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ddss-rollback-${{ github.event.inputs.channel }}
|
group: plonds-rollback-${{ github.event.inputs.channel }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
echo "RELEASE_CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
|
echo "RELEASE_CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
|
||||||
echo "S3_PUBLIC_BASE_URL=${PUBLIC_BASE}" >> "$GITHUB_ENV"
|
echo "S3_PUBLIC_BASE_URL=${PUBLIC_BASE}" >> "$GITHUB_ENV"
|
||||||
echo "S3_BASE_URL=${PUBLIC_BASE}/releases/${TAG}/assets" >> "$GITHUB_ENV"
|
echo "S3_BASE_URL=${PUBLIC_BASE}/releases/${TAG}/assets" >> "$GITHUB_ENV"
|
||||||
echo "DDSS_CHANNEL_POINTER_KEY=lanmountain/update/meta/channels/${CHANNEL}/ddss-latest.json" >> "$GITHUB_ENV"
|
echo "PLONDS_CHANNEL_POINTER_KEY=lanmountain/update/meta/channels/${CHANNEL}/plonds-latest.json" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Validate rollback target assets
|
- name: Validate rollback target assets
|
||||||
env:
|
env:
|
||||||
@@ -77,7 +77,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
for name in ddss.json ddss.json.sig; do
|
for name in plonds.json plonds.json.sig; do
|
||||||
key="lanmountain/update/releases/${RELEASE_TAG}/assets/${name}"
|
key="lanmountain/update/releases/${RELEASE_TAG}/assets/${name}"
|
||||||
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api head-object \
|
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api head-object \
|
||||||
--bucket "$S3_BUCKET" \
|
--bucket "$S3_BUCKET" \
|
||||||
@@ -90,10 +90,10 @@ jobs:
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
mkdir -p rollback-output
|
mkdir -p rollback-output
|
||||||
pointer_file="rollback-output/ddss-latest.json"
|
pointer_file="rollback-output/plonds-latest.json"
|
||||||
|
|
||||||
manifest_url="${S3_BASE_URL}/ddss.json"
|
manifest_url="${S3_BASE_URL}/plonds.json"
|
||||||
sig_url="${S3_BASE_URL}/ddss.json.sig"
|
sig_url="${S3_BASE_URL}/plonds.json.sig"
|
||||||
version="${RELEASE_TAG#v}"
|
version="${RELEASE_TAG#v}"
|
||||||
updated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
updated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
|
||||||
@@ -125,22 +125,22 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
pointer_file="rollback-output/ddss-latest.json"
|
pointer_file="rollback-output/plonds-latest.json"
|
||||||
|
|
||||||
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api put-object \
|
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api put-object \
|
||||||
--bucket "$S3_BUCKET" \
|
--bucket "$S3_BUCKET" \
|
||||||
--key "$DDSS_CHANNEL_POINTER_KEY" \
|
--key "$PLONDS_CHANNEL_POINTER_KEY" \
|
||||||
--body "$pointer_file"
|
--body "$pointer_file"
|
||||||
|
|
||||||
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api head-object \
|
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api head-object \
|
||||||
--bucket "$S3_BUCKET" \
|
--bucket "$S3_BUCKET" \
|
||||||
--key "$DDSS_CHANNEL_POINTER_KEY" >/dev/null
|
--key "$PLONDS_CHANNEL_POINTER_KEY" >/dev/null
|
||||||
|
|
||||||
curl -fsSI "$S3_PUBLIC_BASE_URL/meta/channels/${RELEASE_CHANNEL}/ddss-latest.json" >/dev/null
|
curl -fsSI "$S3_PUBLIC_BASE_URL/meta/channels/${RELEASE_CHANNEL}/plonds-latest.json" >/dev/null
|
||||||
|
|
||||||
- name: Print rollback summary
|
- name: Print rollback summary
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
echo "Rolled back channel '${RELEASE_CHANNEL}' to '${RELEASE_TAG}'."
|
echo "Rolled back channel '${RELEASE_CHANNEL}' to '${RELEASE_TAG}'."
|
||||||
echo "Pointer: ${S3_PUBLIC_BASE_URL}/meta/channels/${RELEASE_CHANNEL}/ddss-latest.json"
|
echo "Pointer: ${S3_PUBLIC_BASE_URL}/meta/channels/${RELEASE_CHANNEL}/plonds-latest.json"
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
name: DDSS
|
name: PLONDS Publisher
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ddss-${{ github.event_name }}-${{ github.event.workflow_run.id || github.event.inputs.tag || github.run_id }}
|
group: plonds-${{ github.event_name }}-${{ github.event.workflow_run.id || github.event.inputs.tag || github.run_id }}
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows:
|
workflows:
|
||||||
- PLONDS
|
- PLONDS Comparator
|
||||||
types:
|
types:
|
||||||
- completed
|
- completed
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
CHANNEL="stable"
|
CHANNEL="stable"
|
||||||
fi
|
fi
|
||||||
echo "RELEASE_CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
|
echo "RELEASE_CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
|
||||||
echo "DDSS_CHANNEL_POINTER_KEY=lanmountain/update/meta/channels/${CHANNEL}/ddss-latest.json" >> "$GITHUB_ENV"
|
echo "PLONDS_CHANNEL_POINTER_KEY=lanmountain/update/meta/channels/${CHANNEL}/plonds-latest.json" >> "$GITHUB_ENV"
|
||||||
PUBLIC_BASE="${{ vars.S3_PUBLIC_BASE_URL }}"
|
PUBLIC_BASE="${{ vars.S3_PUBLIC_BASE_URL }}"
|
||||||
if [[ -z "$PUBLIC_BASE" ]]; then
|
if [[ -z "$PUBLIC_BASE" ]]; then
|
||||||
PUBLIC_BASE="https://cn-nb1.rains3.com/lmdesktop/lanmountain/update"
|
PUBLIC_BASE="https://cn-nb1.rains3.com/lmdesktop/lanmountain/update"
|
||||||
@@ -80,13 +80,11 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
UPDATE_PRIVATE_KEY_PEM: ${{ secrets.UPDATE_PRIVATE_KEY_PEM }}
|
UPDATE_PRIVATE_KEY_PEM: ${{ secrets.UPDATE_PRIVATE_KEY_PEM }}
|
||||||
PLONDS_SIGNING_KEY: ${{ secrets.PLONDS_SIGNING_KEY }}
|
PLONDS_SIGNING_KEY: ${{ secrets.PLONDS_SIGNING_KEY }}
|
||||||
PDC_SIGNING_KEY: ${{ secrets.PDC_SIGNING_KEY }}
|
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
KEY="${PLONDS_SIGNING_KEY:-}"
|
KEY="${PLONDS_SIGNING_KEY:-}"
|
||||||
if [[ -z "$KEY" ]]; then KEY="${UPDATE_PRIVATE_KEY_PEM:-}"; fi
|
if [[ -z "$KEY" ]]; then KEY="${UPDATE_PRIVATE_KEY_PEM:-}"; fi
|
||||||
if [[ -z "$KEY" ]]; then KEY="${PDC_SIGNING_KEY:-}"; fi
|
|
||||||
if [[ -z "$KEY" ]]; then
|
if [[ -z "$KEY" ]]; then
|
||||||
echo "No signing key is configured."
|
echo "No signing key is configured."
|
||||||
exit 1
|
exit 1
|
||||||
@@ -141,7 +139,7 @@ jobs:
|
|||||||
for file in release-assets/*; do
|
for file in release-assets/*; do
|
||||||
[[ -f "$file" ]] || continue
|
[[ -f "$file" ]] || continue
|
||||||
name="$(basename "$file")"
|
name="$(basename "$file")"
|
||||||
if [[ "$name" == "ddss.json" || "$name" == "ddss.json.sig" ]]; then
|
if [[ "$name" == "plonds.json" || "$name" == "plonds.json.sig" ]]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
key="lanmountain/update/releases/${RELEASE_TAG}/assets/${name}"
|
key="lanmountain/update/releases/${RELEASE_TAG}/assets/${name}"
|
||||||
@@ -211,21 +209,21 @@ jobs:
|
|||||||
--metadata "sha256=$sha256"
|
--metadata "sha256=$sha256"
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Build DDSS manifest
|
- name: Build PLONDS manifest
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
mkdir -p ddss-output
|
mkdir -p plonds-output
|
||||||
dotnet run --project PenguinLogisticsOnlineNetworkDistributionSystem/src/Plonds.Tool/Plonds.Tool.csproj --configuration Release -- \
|
dotnet run --project PenguinLogisticsOnlineNetworkDistributionSystem/src/Plonds.Tool/Plonds.Tool.csproj --configuration Release -- \
|
||||||
build-ddss \
|
build-plonds \
|
||||||
--release-tag "$RELEASE_TAG" \
|
--release-tag "$RELEASE_TAG" \
|
||||||
--assets-dir release-assets \
|
--assets-dir release-assets \
|
||||||
--output-dir ddss-output \
|
--output-dir plonds-output \
|
||||||
--private-key "$UPDATE_PRIVATE_KEY_PATH" \
|
--private-key "$UPDATE_PRIVATE_KEY_PATH" \
|
||||||
--repository "${{ github.repository }}" \
|
--repository "${{ github.repository }}" \
|
||||||
--s3-base-url "$S3_BASE_URL"
|
--s3-base-url "$S3_BASE_URL"
|
||||||
|
|
||||||
- name: Validate DDSS asset references in Rainyun S3
|
- name: Validate PLONDS asset references in Rainyun S3
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||||
@@ -236,12 +234,12 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
keys=$(jq -r '.assets[]?.mirrors[]?.url // empty' ddss-output/ddss.json \
|
keys=$(jq -r '.assets[]?.mirrors[]?.url // empty' plonds-output/plonds.json \
|
||||||
| sed -n 's#^.*/lanmountain/update/\(.*\)$#lanmountain/update/\1#p' \
|
| sed -n 's#^.*/lanmountain/update/\(.*\)$#lanmountain/update/\1#p' \
|
||||||
| sort -u)
|
| sort -u)
|
||||||
|
|
||||||
if [[ -z "$keys" ]]; then
|
if [[ -z "$keys" ]]; then
|
||||||
echo "No S3-backed asset URLs found in ddss.json"
|
echo "No S3-backed asset URLs found in plonds.json"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -252,15 +250,15 @@ jobs:
|
|||||||
--key "$key" >/dev/null
|
--key "$key" >/dev/null
|
||||||
done <<< "$keys"
|
done <<< "$keys"
|
||||||
|
|
||||||
- name: Upload DDSS manifest to release
|
- name: Upload PLONDS manifest to release
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
gh release upload "$RELEASE_TAG" ddss-output/ddss.json ddss-output/ddss.json.sig --clobber
|
gh release upload "$RELEASE_TAG" plonds-output/plonds.json plonds-output/plonds.json.sig --clobber
|
||||||
|
|
||||||
- name: Upload DDSS manifest to Rainyun S3 staging
|
- name: Upload PLONDS manifest to Rainyun S3 staging
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||||
@@ -271,7 +269,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
for file in ddss-output/ddss.json ddss-output/ddss.json.sig; do
|
for file in plonds-output/plonds.json plonds-output/plonds.json.sig; do
|
||||||
name="$(basename "$file")"
|
name="$(basename "$file")"
|
||||||
key="lanmountain/update/releases/${RELEASE_TAG}/assets/${name}"
|
key="lanmountain/update/releases/${RELEASE_TAG}/assets/${name}"
|
||||||
sha256="$(sha256sum "$file" | awk '{print $1}')"
|
sha256="$(sha256sum "$file" | awk '{print $1}')"
|
||||||
@@ -282,11 +280,11 @@ jobs:
|
|||||||
--metadata "sha256=$sha256"
|
--metadata "sha256=$sha256"
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Prepare DDSS channel pointer
|
- name: Prepare PLONDS channel pointer
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
pointer_file="ddss-output/ddss-latest.json"
|
pointer_file="plonds-output/plonds-latest.json"
|
||||||
cat > "$pointer_file" <<'JSON'
|
cat > "$pointer_file" <<'JSON'
|
||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
@@ -301,8 +299,8 @@ jobs:
|
|||||||
}
|
}
|
||||||
JSON
|
JSON
|
||||||
|
|
||||||
manifest_url="${S3_BASE_URL}/ddss.json"
|
manifest_url="${S3_BASE_URL}/plonds.json"
|
||||||
sig_url="${S3_BASE_URL}/ddss.json.sig"
|
sig_url="${S3_BASE_URL}/plonds.json.sig"
|
||||||
version="${RELEASE_TAG#v}"
|
version="${RELEASE_TAG#v}"
|
||||||
updated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
updated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
|
||||||
@@ -315,7 +313,7 @@ jobs:
|
|||||||
|
|
||||||
jq -e . "$pointer_file" >/dev/null
|
jq -e . "$pointer_file" >/dev/null
|
||||||
|
|
||||||
- name: Atomically publish DDSS channel pointer
|
- name: Atomically publish PLONDS channel pointer
|
||||||
env:
|
env:
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||||
@@ -326,8 +324,8 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
pointer_file="ddss-output/ddss-latest.json"
|
pointer_file="plonds-output/plonds-latest.json"
|
||||||
staging_key="lanmountain/update/releases/${RELEASE_TAG}/assets/ddss-latest.json"
|
staging_key="lanmountain/update/releases/${RELEASE_TAG}/assets/plonds-latest.json"
|
||||||
|
|
||||||
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api put-object \
|
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api put-object \
|
||||||
--bucket "$S3_BUCKET" \
|
--bucket "$S3_BUCKET" \
|
||||||
@@ -336,14 +334,14 @@ jobs:
|
|||||||
|
|
||||||
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api put-object \
|
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api put-object \
|
||||||
--bucket "$S3_BUCKET" \
|
--bucket "$S3_BUCKET" \
|
||||||
--key "$DDSS_CHANNEL_POINTER_KEY" \
|
--key "$PLONDS_CHANNEL_POINTER_KEY" \
|
||||||
--body "$pointer_file"
|
--body "$pointer_file"
|
||||||
|
|
||||||
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api head-object \
|
aws --endpoint-url "$S3_ENDPOINT" --region "$AWS_REGION" s3api head-object \
|
||||||
--bucket "$S3_BUCKET" \
|
--bucket "$S3_BUCKET" \
|
||||||
--key "$DDSS_CHANNEL_POINTER_KEY" >/dev/null
|
--key "$PLONDS_CHANNEL_POINTER_KEY" >/dev/null
|
||||||
|
|
||||||
curl -fsSI "$S3_PUBLIC_BASE_URL/meta/channels/${RELEASE_CHANNEL}/ddss-latest.json" >/dev/null
|
curl -fsSI "$S3_PUBLIC_BASE_URL/meta/channels/${RELEASE_CHANNEL}/plonds-latest.json" >/dev/null
|
||||||
|
|
||||||
- name: Verify Rainyun S3 PLONDS output
|
- name: Verify Rainyun S3 PLONDS output
|
||||||
env:
|
env:
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Checklist
|
|
||||||
|
|
||||||
- [x] `release.yml` does not invoke Velopack.
|
|
||||||
- [x] `plonds-build.yml` uploads app payload artifacts and generates PloNDS delta/static outputs.
|
|
||||||
- [x] S3 output path is rooted at `lanmountain/update/` (no system version prefix).
|
|
||||||
- [x] CI workflow expects `repo/`, `meta/`, `manifests/`, and `installers/` outputs after a release run.
|
|
||||||
- [x] Host update source keeps compatibility (`pdc`/`stcn` normalize to active PloNDS source).
|
|
||||||
- [x] Host can persist PloNDS payload into launcher incoming directory.
|
|
||||||
- [x] Launcher can apply PloNDS FileMap payload with signature/hash verification.
|
|
||||||
- [x] Legacy signed `files.json + update.zip` path still works as compatibility fallback.
|
|
||||||
- [x] Launcher keeps rollback-capable deployments after successful update.
|
|
||||||
- [x] Manual rollback returns a structured failure when the snapshot source directory is missing.
|
|
||||||
- [ ] CI run attached proving all release matrix jobs pass.
|
|
||||||
- [x] N-1 -> N incremental update verified locally on Windows x64.
|
|
||||||
- [ ] N-1 -> N incremental update verified on Windows x86 and Linux x64.
|
|
||||||
- [x] Rollback regression tests attached in `LanMountainDesktop.Tests`.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# PDC Incremental Update Migration
|
|
||||||
|
|
||||||
## Goal
|
|
||||||
|
|
||||||
Replace VeloPack-based incremental packaging with a unified PDC FileMap + object-repo pipeline, while keeping Launcher installation, rollback, and update orchestration ownership unchanged.
|
|
||||||
|
|
||||||
## Stage 1 (Completed)
|
|
||||||
|
|
||||||
- Release workflow removed VeloPack-based release packaging.
|
|
||||||
- Signed FileMap path was restored as an interim release mechanism.
|
|
||||||
- Host/Launcher fallback behavior stayed compatible with `files.json + files.json.sig + update.zip`.
|
|
||||||
|
|
||||||
## Stage 2 (Current Implementation Target)
|
|
||||||
|
|
||||||
- Use GitHub Actions PloNDS static publishing as the active incremental path.
|
|
||||||
- Keep `phainon.yml` for future PDCC parity, but do not rely on PDCC for the current release flow.
|
|
||||||
- Promote PloNDS-distributed FileMap/object-repo as the primary incremental path.
|
|
||||||
- Keep GitHub Release installers and metadata as parallel distribution.
|
|
||||||
- Keep Launcher state machine ownership (`.current/.partial/.destroy` + snapshots).
|
|
||||||
- Check updates in order: NS3/PloNDS static source, GitHub Release PloNDS assets, then GitHub full installer.
|
|
||||||
- S3 object root is fixed to `lanmountain/update/` with no update-system version prefix.
|
|
||||||
- Public object URLs come from `S3_PUBLIC_BASE_URL`; do not infer them from `S3_ENDPOINT` and `S3_BUCKET`.
|
|
||||||
|
|
||||||
Expected S3 layout:
|
|
||||||
- `lanmountain/update/repo/sha256/<hash-prefix>/<hash-object>`
|
|
||||||
- `lanmountain/update/meta/channels/<channel>/<platform>/latest.json`
|
|
||||||
- `lanmountain/update/meta/distributions/<distributionId>.json`
|
|
||||||
- `lanmountain/update/manifests/<distributionId>/plonds-filemap.json`
|
|
||||||
- `lanmountain/update/manifests/<distributionId>/plonds-filemap.json.sig`
|
|
||||||
- `lanmountain/update/installers/<platform>/<version>/*`
|
|
||||||
|
|
||||||
## Acceptance
|
|
||||||
|
|
||||||
- `release.yml` contains no Velopack steps; PloNDS static publishing is handled by `plonds-build.yml` and `ddss-publish.yml`.
|
|
||||||
- Release jobs keep building installers for Windows x64/x86, Linux x64, and macOS.
|
|
||||||
- PloNDS metadata + FileMap + object repo are published under `lanmountain/update/`.
|
|
||||||
- Host can consume the NS3/PloNDS static payload and fallback to GitHub when unavailable.
|
|
||||||
- Launcher can apply both:
|
|
||||||
- legacy signed `files.json + update.zip`
|
|
||||||
- PloNDS FileMap object-repo payload.
|
|
||||||
- Rollback semantics keep both automatic failure rollback and manual rollback after a successful update.
|
|
||||||
|
|
||||||
## Deprecated Notes
|
|
||||||
|
|
||||||
- The following interim outputs are compatibility-only (not the long-term primary path):
|
|
||||||
- `files-windows-x64.json` / `.sig` / `update-windows-x64.zip`
|
|
||||||
- `files-windows-x86.json` / `.sig` / `update-windows-x86.zip`
|
|
||||||
- `files-linux-x64.json` / `.sig` / `update-linux-x64.zip`
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Tasks
|
|
||||||
|
|
||||||
- [x] Remove VeloPack packaging from release workflow.
|
|
||||||
- [x] Keep signed FileMap path as interim compatibility fallback.
|
|
||||||
- [x] Remove launcher/runtime Velopack branching.
|
|
||||||
- [x] Add `phainon.yml` for PDCC publish configuration.
|
|
||||||
- [ ] Add PDCC installation + publish steps in `release.yml` (deferred; active path is GitHub Actions PloNDS static publish).
|
|
||||||
- [x] Upload app payload artifacts for PloNDS delta generation in release build jobs.
|
|
||||||
- [x] Publish PloNDS metadata + sha256 object repo to S3 path root `lanmountain/update/`.
|
|
||||||
- [x] Mirror installers to `lanmountain/update/installers/<platform>/<version>/`.
|
|
||||||
- [x] Keep update source compatibility (`pdc`/`stcn` normalize to active PloNDS source).
|
|
||||||
- [x] Add PloNDS static payload model into host update check result.
|
|
||||||
- [x] Add host download path for PloNDS payload (`plonds-filemap.json` + signature + object repo).
|
|
||||||
- [x] Add launcher PloNDS FileMap apply path with rollback-compatible semantics.
|
|
||||||
- [x] Keep old `files.json + update.zip` path behind compatibility fallback.
|
|
||||||
- [x] Keep rollback deployment directories after successful apply and prune by bounded retention.
|
|
||||||
- [x] Return structured failure when manual rollback snapshot source is missing.
|
|
||||||
- [x] Verify static S3 layout, filemap/signature, distribution, latest pointer, and at least one object in CI workflows.
|
|
||||||
- [x] Add regression tests for PloNDS success rollback, hash-failure auto rollback, missing rollback source, static NS3 manifest, and manifest field mapping.
|
|
||||||
- [ ] Attach live CI run proving the full release matrix passes.
|
|
||||||
- [ ] Verify N-1 -> N incremental update on Windows x86 and Linux x64 in release artifacts.
|
|
||||||
@@ -12,23 +12,23 @@ internal sealed class PendingUpdateDetector(
|
|||||||
{
|
{
|
||||||
if (File.Exists(paths.PlondsFileMapPath) && File.Exists(paths.PlondsSignaturePath))
|
if (File.Exists(paths.PlondsFileMapPath) && File.Exists(paths.PlondsSignaturePath))
|
||||||
{
|
{
|
||||||
var pdcFileMapText = File.ReadAllText(paths.PlondsFileMapPath);
|
var plondsFileMapText = File.ReadAllText(paths.PlondsFileMapPath);
|
||||||
var pdcFileMap = JsonSerializer.Deserialize(pdcFileMapText, AppJsonContext.Default.PlondsFileMap);
|
var plondsFileMap = JsonSerializer.Deserialize(plondsFileMapText, AppJsonContext.Default.PlondsFileMap);
|
||||||
if (pdcFileMap is null)
|
if (plondsFileMap is null)
|
||||||
{
|
{
|
||||||
return UpdateEngineResults.Failed("update.check", "invalid_manifest", "plonds-filemap.json is invalid.");
|
return UpdateEngineResults.Failed("update.check", "invalid_manifest", "plonds-filemap.json is invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var pdcVerified = signatureVerifier.Verify(
|
var plondsVerified = signatureVerifier.Verify(
|
||||||
paths.PlondsFileMapPath,
|
paths.PlondsFileMapPath,
|
||||||
paths.PlondsSignaturePath,
|
paths.PlondsSignaturePath,
|
||||||
UpdateEnginePaths.PlondsSignatureFileName);
|
UpdateEnginePaths.PlondsSignatureFileName);
|
||||||
if (!pdcVerified.Success)
|
if (!plondsVerified.Success)
|
||||||
{
|
{
|
||||||
return UpdateEngineResults.Failed("update.check", "signature_failed", pdcVerified.Message);
|
return UpdateEngineResults.Failed("update.check", "signature_failed", plondsVerified.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
var pdcMetadata = PlondsManifestParser.LoadMetadata(paths.PlondsUpdateMetadataPath);
|
var plondsMetadata = PlondsManifestParser.LoadMetadata(paths.PlondsUpdateMetadataPath);
|
||||||
return new LauncherResult
|
return new LauncherResult
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = true,
|
||||||
@@ -36,7 +36,7 @@ internal sealed class PendingUpdateDetector(
|
|||||||
Code = "available",
|
Code = "available",
|
||||||
Message = "Pending PLONDS update is available.",
|
Message = "Pending PLONDS update is available.",
|
||||||
CurrentVersion = deploymentLocator.GetCurrentVersion(),
|
CurrentVersion = deploymentLocator.GetCurrentVersion(),
|
||||||
TargetVersion = PlondsManifestParser.ResolveTargetVersion(pdcFileMap, pdcMetadata)
|
TargetVersion = PlondsManifestParser.ResolveTargetVersion(plondsFileMap, plondsMetadata)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,11 +39,11 @@ internal sealed class PlondsUpdateApplier(
|
|||||||
return UpdateEngineResults.Failed("update.apply", "invalid_manifest", "No PLONDS file entries were found.");
|
return UpdateEngineResults.Failed("update.apply", "invalid_manifest", "No PLONDS file entries were found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var pdcMetadata = PlondsManifestParser.LoadMetadata(paths.PlondsUpdateMetadataPath);
|
var plondsMetadata = PlondsManifestParser.LoadMetadata(paths.PlondsUpdateMetadataPath);
|
||||||
var currentDeployment = deploymentLocator.FindCurrentDeploymentDirectory();
|
var currentDeployment = deploymentLocator.FindCurrentDeploymentDirectory();
|
||||||
var currentVersion = deploymentLocator.GetCurrentVersion();
|
var currentVersion = deploymentLocator.GetCurrentVersion();
|
||||||
var sourceVersion = string.IsNullOrWhiteSpace(currentVersion) ? "0.0.0" : currentVersion;
|
var sourceVersion = string.IsNullOrWhiteSpace(currentVersion) ? "0.0.0" : currentVersion;
|
||||||
var expectedSourceVersion = PlondsManifestParser.ResolveSourceVersion(fileMap, pdcMetadata);
|
var expectedSourceVersion = PlondsManifestParser.ResolveSourceVersion(fileMap, plondsMetadata);
|
||||||
if (!string.IsNullOrWhiteSpace(expectedSourceVersion) &&
|
if (!string.IsNullOrWhiteSpace(expectedSourceVersion) &&
|
||||||
!string.Equals(expectedSourceVersion, sourceVersion, StringComparison.OrdinalIgnoreCase))
|
!string.Equals(expectedSourceVersion, sourceVersion, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@@ -53,7 +53,7 @@ internal sealed class PlondsUpdateApplier(
|
|||||||
$"PLONDS update requires source version {expectedSourceVersion} but current is {sourceVersion}.");
|
$"PLONDS update requires source version {expectedSourceVersion} but current is {sourceVersion}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetVersion = PlondsManifestParser.ResolveTargetVersion(fileMap, pdcMetadata);
|
var targetVersion = PlondsManifestParser.ResolveTargetVersion(fileMap, plondsMetadata);
|
||||||
if (string.IsNullOrWhiteSpace(targetVersion))
|
if (string.IsNullOrWhiteSpace(targetVersion))
|
||||||
{
|
{
|
||||||
targetVersion = sourceVersion;
|
targetVersion = sourceVersion;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public sealed record UpdateManifest(
|
|||||||
IReadOnlyList<UpdateMirrorAsset>? InstallerMirrors,
|
IReadOnlyList<UpdateMirrorAsset>? InstallerMirrors,
|
||||||
IReadOnlyDictionary<string, string> Metadata)
|
IReadOnlyDictionary<string, string> Metadata)
|
||||||
{
|
{
|
||||||
public bool IsDelta => Kind is UpdatePayloadKind.DeltaPlonds or UpdatePayloadKind.DeltaLegacy;
|
public bool IsDelta => Kind is UpdatePayloadKind.DeltaPlonds;
|
||||||
|
|
||||||
public long EstimatedDeltaBytes
|
public long EstimatedDeltaBytes
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ public enum UpdatePhase
|
|||||||
public enum UpdatePayloadKind
|
public enum UpdatePayloadKind
|
||||||
{
|
{
|
||||||
DeltaPlonds,
|
DeltaPlonds,
|
||||||
DeltaLegacy,
|
|
||||||
FullInstaller
|
FullInstaller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ internal sealed class UpdateInstallGateway
|
|||||||
return new InstallResult(false, lockError, false, lockErrorCode);
|
return new InstallResult(false, lockError, false, lockErrorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payloadKind is UpdatePayloadKind.DeltaPlonds or UpdatePayloadKind.DeltaLegacy)
|
if (payloadKind is UpdatePayloadKind.DeltaPlonds)
|
||||||
{
|
{
|
||||||
var launched = LaunchLauncherForApplyUpdate(launcherRoot);
|
var launched = LaunchLauncherForApplyUpdate(launcherRoot);
|
||||||
if (!launched)
|
if (!launched)
|
||||||
@@ -108,7 +108,7 @@ internal sealed class UpdateInstallGateway
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var expectedKind = payloadKind is UpdatePayloadKind.DeltaLegacy or UpdatePayloadKind.DeltaPlonds ? "delta" : "full";
|
var expectedKind = payloadKind is UpdatePayloadKind.DeltaPlonds ? "delta" : "full";
|
||||||
if (!string.Equals(deploymentLock.Kind, expectedKind, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(deploymentLock.Kind, expectedKind, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
errorCode = "lock_conflict";
|
errorCode = "lock_conflict";
|
||||||
|
|||||||
@@ -15,11 +15,7 @@ public static class UpdateSettingsValues
|
|||||||
|
|
||||||
// NOTE: keep constant name for compatibility with existing call sites.
|
// NOTE: keep constant name for compatibility with existing call sites.
|
||||||
public const string DownloadSourcePlonds = "plonds-api";
|
public const string DownloadSourcePlonds = "plonds-api";
|
||||||
public const string DownloadSourcePdc = DownloadSourcePlonds;
|
|
||||||
public const string DownloadSourceStcn = DownloadSourcePlonds;
|
public const string DownloadSourceStcn = DownloadSourcePlonds;
|
||||||
public const string LegacyDownloadSourcePlonds = "pdc";
|
|
||||||
public const string LegacyDownloadSourcePdc = LegacyDownloadSourcePlonds;
|
|
||||||
public const string LegacyDownloadSourceStcn = "stcn";
|
|
||||||
public const string DownloadSourceGitHub = "github";
|
public const string DownloadSourceGitHub = "github";
|
||||||
public const string DownloadSourceGhProxy = "gh-proxy";
|
public const string DownloadSourceGhProxy = "gh-proxy";
|
||||||
public const string PlondsStaticBaseUrlEnvironmentVariable = "LANMOUNTAIN_UPDATE_BASE_URL";
|
public const string PlondsStaticBaseUrlEnvironmentVariable = "LANMOUNTAIN_UPDATE_BASE_URL";
|
||||||
@@ -62,12 +58,12 @@ public static class UpdateSettingsValues
|
|||||||
|
|
||||||
public static string NormalizeDownloadSource(string? value)
|
public static string NormalizeDownloadSource(string? value)
|
||||||
{
|
{
|
||||||
if (string.Equals(value, LegacyDownloadSourcePlonds, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(value, "pdc", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return DownloadSourcePlonds;
|
return DownloadSourcePlonds;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(value, LegacyDownloadSourceStcn, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(value, "stcn", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return DownloadSourcePlonds;
|
return DownloadSourcePlonds;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public sealed partial class UpdateSettingsViewModel : ViewModelBase, IDisposable
|
|||||||
[ObservableProperty] private bool _forceReinstall;
|
[ObservableProperty] private bool _forceReinstall;
|
||||||
|
|
||||||
[ObservableProperty] private string _selectedUpdateChannelValue = UpdateSettingsValues.ChannelStable;
|
[ObservableProperty] private string _selectedUpdateChannelValue = UpdateSettingsValues.ChannelStable;
|
||||||
[ObservableProperty] private string _selectedUpdateSourceValue = UpdateSettingsValues.DownloadSourcePdc;
|
[ObservableProperty] private string _selectedUpdateSourceValue = UpdateSettingsValues.DownloadSourcePlonds;
|
||||||
[ObservableProperty] private string _selectedUpdateModeValue = UpdateSettingsValues.ModeSilentDownload;
|
[ObservableProperty] private string _selectedUpdateModeValue = UpdateSettingsValues.ModeSilentDownload;
|
||||||
[ObservableProperty] private double _downloadThreadsSliderValue = UpdateSettingsValues.DefaultDownloadThreads;
|
[ObservableProperty] private double _downloadThreadsSliderValue = UpdateSettingsValues.DefaultDownloadThreads;
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ public sealed partial class UpdateSettingsViewModel : ViewModelBase, IDisposable
|
|||||||
LatestVersionText = report.LatestVersion ?? string.Empty;
|
LatestVersionText = report.LatestVersion ?? string.Empty;
|
||||||
PublishedAtText = report.PublishedAt?.ToLocalTime().ToString("g", CultureInfo.CurrentCulture) ?? string.Empty;
|
PublishedAtText = report.PublishedAt?.ToLocalTime().ToString("g", CultureInfo.CurrentCulture) ?? string.Empty;
|
||||||
UpdateTypeText = GetUpdateTypeText(report.PayloadKind);
|
UpdateTypeText = GetUpdateTypeText(report.PayloadKind);
|
||||||
IsDeltaUpdate = report.PayloadKind is UpdatePayloadKind.DeltaPlonds or UpdatePayloadKind.DeltaLegacy;
|
IsDeltaUpdate = report.PayloadKind is UpdatePayloadKind.DeltaPlonds;
|
||||||
StatusMessage = report.LatestVersion is null
|
StatusMessage = report.LatestVersion is null
|
||||||
? GetUpdateAvailableStatusText(string.Empty)
|
? GetUpdateAvailableStatusText(string.Empty)
|
||||||
: string.Format(CultureInfo.CurrentCulture, L("settings.update.status_available_format", "New version {0} is available. Click Download and Install."), report.LatestVersion);
|
: string.Format(CultureInfo.CurrentCulture, L("settings.update.status_available_format", "New version {0} is available. Click Download and Install."), report.LatestVersion);
|
||||||
@@ -627,7 +627,7 @@ public sealed partial class UpdateSettingsViewModel : ViewModelBase, IDisposable
|
|||||||
|
|
||||||
return payloadKind switch
|
return payloadKind switch
|
||||||
{
|
{
|
||||||
UpdatePayloadKind.DeltaPlonds or UpdatePayloadKind.DeltaLegacy => L("settings.update.type_delta", "Incremental Update"),
|
UpdatePayloadKind.DeltaPlonds => L("settings.update.type_delta", "Incremental Update"),
|
||||||
UpdatePayloadKind.FullInstaller => L("settings.update.type_reinstall", "Reinstall"),
|
UpdatePayloadKind.FullInstaller => L("settings.update.type_reinstall", "Reinstall"),
|
||||||
_ => string.Empty
|
_ => string.Empty
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace Plonds.Core.Publishing;
|
namespace Plonds.Core.Publishing;
|
||||||
|
|
||||||
public sealed record DdssBuildOptions(
|
public sealed record PlondsBuildOptions(
|
||||||
string ReleaseTag,
|
string ReleaseTag,
|
||||||
string AssetsDirectory,
|
string AssetsDirectory,
|
||||||
string OutputRoot,
|
string OutputRoot,
|
||||||
@@ -3,18 +3,18 @@ using Plonds.Shared.Models;
|
|||||||
|
|
||||||
namespace Plonds.Core.Publishing;
|
namespace Plonds.Core.Publishing;
|
||||||
|
|
||||||
public sealed class DdssManifestBuilder
|
public sealed class PlondsManifestBuilder
|
||||||
{
|
{
|
||||||
private readonly RsaFileSigner _signer = new();
|
private readonly RsaFileSigner _signer = new();
|
||||||
|
|
||||||
public string Build(DdssBuildOptions options)
|
public string Build(PlondsBuildOptions options)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(options);
|
ArgumentNullException.ThrowIfNull(options);
|
||||||
|
|
||||||
var assetsDirectory = Path.GetFullPath(options.AssetsDirectory);
|
var assetsDirectory = Path.GetFullPath(options.AssetsDirectory);
|
||||||
if (!Directory.Exists(assetsDirectory))
|
if (!Directory.Exists(assetsDirectory))
|
||||||
{
|
{
|
||||||
throw new DirectoryNotFoundException($"DDSS assets directory not found: {assetsDirectory}");
|
throw new DirectoryNotFoundException($"PLONDS assets directory not found: {assetsDirectory}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var assetEntries = Directory
|
var assetEntries = Directory
|
||||||
@@ -22,14 +22,14 @@ public sealed class DdssManifestBuilder
|
|||||||
.Where(static path =>
|
.Where(static path =>
|
||||||
{
|
{
|
||||||
var name = Path.GetFileName(path);
|
var name = Path.GetFileName(path);
|
||||||
return !name.Equals("ddss.json", StringComparison.OrdinalIgnoreCase)
|
return !name.Equals("plonds.json", StringComparison.OrdinalIgnoreCase)
|
||||||
&& !name.Equals("ddss.json.sig", StringComparison.OrdinalIgnoreCase);
|
&& !name.Equals("plonds.json.sig", StringComparison.OrdinalIgnoreCase);
|
||||||
})
|
})
|
||||||
.OrderBy(static path => Path.GetFileName(path), StringComparer.OrdinalIgnoreCase)
|
.OrderBy(static path => Path.GetFileName(path), StringComparer.OrdinalIgnoreCase)
|
||||||
.Select(path => BuildAssetEntry(path, options.Repository, options.ReleaseTag, options.S3BaseUrl))
|
.Select(path => BuildAssetEntry(path, options.Repository, options.ReleaseTag, options.S3BaseUrl))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var manifest = new DdssManifest(
|
var manifest = new PlondsManifest(
|
||||||
FormatVersion: "1.0",
|
FormatVersion: "1.0",
|
||||||
ReleaseTag: options.ReleaseTag,
|
ReleaseTag: options.ReleaseTag,
|
||||||
GeneratedAt: DateTimeOffset.UtcNow,
|
GeneratedAt: DateTimeOffset.UtcNow,
|
||||||
@@ -37,28 +37,28 @@ public sealed class DdssManifestBuilder
|
|||||||
|
|
||||||
var outputRoot = Path.GetFullPath(options.OutputRoot);
|
var outputRoot = Path.GetFullPath(options.OutputRoot);
|
||||||
Directory.CreateDirectory(outputRoot);
|
Directory.CreateDirectory(outputRoot);
|
||||||
var manifestPath = Path.Combine(outputRoot, "ddss.json");
|
var manifestPath = Path.Combine(outputRoot, "plonds.json");
|
||||||
PayloadUtilities.WriteJson(manifestPath, manifest);
|
PayloadUtilities.WriteJson(manifestPath, manifest);
|
||||||
_signer.SignFile(manifestPath, options.PrivateKeyPath, manifestPath + ".sig");
|
_signer.SignFile(manifestPath, options.PrivateKeyPath, manifestPath + ".sig");
|
||||||
return manifestPath;
|
return manifestPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DdssAssetEntry BuildAssetEntry(string assetPath, string repository, string releaseTag, string? s3BaseUrl)
|
private static PlondsAssetEntry BuildAssetEntry(string assetPath, string repository, string releaseTag, string? s3BaseUrl)
|
||||||
{
|
{
|
||||||
var fileName = Path.GetFileName(assetPath);
|
var fileName = Path.GetFileName(assetPath);
|
||||||
var mirrors = new List<DdssMirrorEntry>
|
var mirrors = new List<PlondsMirrorEntry>
|
||||||
{
|
{
|
||||||
new("github", $"https://github.com/{repository}/releases/download/{releaseTag}/{Uri.EscapeDataString(fileName)}")
|
new("github", $"https://github.com/{repository}/releases/download/{releaseTag}/{Uri.EscapeDataString(fileName)}")
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(s3BaseUrl))
|
if (!string.IsNullOrWhiteSpace(s3BaseUrl))
|
||||||
{
|
{
|
||||||
mirrors.Add(new DdssMirrorEntry(
|
mirrors.Add(new PlondsMirrorEntry(
|
||||||
"s3",
|
"s3",
|
||||||
$"{s3BaseUrl.TrimEnd('/')}/{Uri.EscapeDataString(fileName)}"));
|
$"{s3BaseUrl.TrimEnd('/')}/{Uri.EscapeDataString(fileName)}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DdssAssetEntry(
|
return new PlondsAssetEntry(
|
||||||
AssetId: fileName,
|
AssetId: fileName,
|
||||||
FileName: fileName,
|
FileName: fileName,
|
||||||
Sha256: PayloadUtilities.ComputeSha256(assetPath),
|
Sha256: PayloadUtilities.ComputeSha256(assetPath),
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
namespace Plonds.Shared.Models;
|
namespace Plonds.Shared.Models;
|
||||||
|
|
||||||
public sealed record DdssAssetEntry(
|
public sealed record PlondsAssetEntry(
|
||||||
string AssetId,
|
string AssetId,
|
||||||
string FileName,
|
string FileName,
|
||||||
string Sha256,
|
string Sha256,
|
||||||
long Size,
|
long Size,
|
||||||
IReadOnlyList<DdssMirrorEntry> Mirrors);
|
IReadOnlyList<PlondsMirrorEntry> Mirrors);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Plonds.Shared.Models;
|
namespace Plonds.Shared.Models;
|
||||||
|
|
||||||
public sealed record DdssManifest(
|
public sealed record PlondsManifest(
|
||||||
string FormatVersion,
|
string FormatVersion,
|
||||||
string ReleaseTag,
|
string ReleaseTag,
|
||||||
DateTimeOffset GeneratedAt,
|
DateTimeOffset GeneratedAt,
|
||||||
IReadOnlyList<DdssAssetEntry> Assets);
|
IReadOnlyList<PlondsAssetEntry> Assets);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
namespace Plonds.Shared.Models;
|
namespace Plonds.Shared.Models;
|
||||||
|
|
||||||
public sealed record DdssMirrorEntry(
|
public sealed record PlondsMirrorEntry(
|
||||||
string Type,
|
string Type,
|
||||||
string Url);
|
string Url);
|
||||||
@@ -38,8 +38,8 @@ internal static class PlondsCli
|
|||||||
case "build-index":
|
case "build-index":
|
||||||
RunBuildIndex(options);
|
RunBuildIndex(options);
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
case "build-ddss":
|
case "build-plonds":
|
||||||
RunBuildDdss(options);
|
RunBuildPlonds(options);
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
default:
|
default:
|
||||||
Console.Error.WriteLine($"Unknown command: {command}");
|
Console.Error.WriteLine($"Unknown command: {command}");
|
||||||
@@ -157,10 +157,10 @@ internal static class PlondsCli
|
|||||||
Console.WriteLine(manifestPath);
|
Console.WriteLine(manifestPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RunBuildDdss(Dictionary<string, string> options)
|
private static void RunBuildPlonds(Dictionary<string, string> options)
|
||||||
{
|
{
|
||||||
var builder = new DdssManifestBuilder();
|
var builder = new PlondsManifestBuilder();
|
||||||
var manifestPath = builder.Build(new DdssBuildOptions(
|
var manifestPath = builder.Build(new PlondsBuildOptions(
|
||||||
ReleaseTag: Require(options, "release-tag"),
|
ReleaseTag: Require(options, "release-tag"),
|
||||||
AssetsDirectory: Require(options, "assets-dir"),
|
AssetsDirectory: Require(options, "assets-dir"),
|
||||||
OutputRoot: Require(options, "output-dir"),
|
OutputRoot: Require(options, "output-dir"),
|
||||||
@@ -215,7 +215,7 @@ internal static class PlondsCli
|
|||||||
Console.WriteLine(" pack-payload --source-dir <dir> --output-zip <file>");
|
Console.WriteLine(" pack-payload --source-dir <dir> --output-zip <file>");
|
||||||
Console.WriteLine(" build-delta --platform <platform> --current-version <v> --current-tag <tag> --current-zip <file> --output-dir <dir> --private-key <pem> [--baseline-tag <tag>] [--baseline-version <v>] [--baseline-zip <file>] [--is-full-payload] [--static-output-dir <dir>] [--update-base-url <url>]");
|
Console.WriteLine(" build-delta --platform <platform> --current-version <v> --current-tag <tag> --current-zip <file> --output-dir <dir> --private-key <pem> [--baseline-tag <tag>] [--baseline-version <v>] [--baseline-zip <file>] [--is-full-payload] [--static-output-dir <dir>] [--update-base-url <url>]");
|
||||||
Console.WriteLine(" build-index --release-tag <tag> --version <v> --platform-summaries-dir <dir> --output-dir <dir> --private-key <pem> [--channel <channel>]");
|
Console.WriteLine(" build-index --release-tag <tag> --version <v> --platform-summaries-dir <dir> --output-dir <dir> --private-key <pem> [--channel <channel>]");
|
||||||
Console.WriteLine(" build-ddss --release-tag <tag> --assets-dir <dir> --output-dir <dir> --private-key <pem> --repository <owner/repo> [--s3-base-url <url>]");
|
Console.WriteLine(" build-plonds --release-tag <tag> --assets-dir <dir> --output-dir <dir> --private-key <pem> --repository <owner/repo> [--s3-base-url <url>]");
|
||||||
Console.WriteLine(" sign --manifest <file> --private-key <pem> [--output <file>]");
|
Console.WriteLine(" sign --manifest <file> --private-key <pem> [--output <file>]");
|
||||||
Console.WriteLine(" generate --current-version <v> --current-dir <dir> --platform <platform> --output-dir <dir> [--previous-version <v>] [--previous-dir <dir>]");
|
Console.WriteLine(" generate --current-version <v> --current-dir <dir> --platform <platform> --output-dir <dir> [--previous-version <v>] [--previous-dir <dir>]");
|
||||||
Console.WriteLine(" publish --version <v> --app-artifacts-root <dir> --installer-artifacts-root <dir> --output-dir <dir> --private-key <pem> [--baseline-root <dir>]");
|
Console.WriteLine(" publish --version <v> --app-artifacts-root <dir> --installer-artifacts-root <dir> --output-dir <dir> --private-key <pem> [--baseline-root <dir>]");
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
| Category | Count | Files |
|
| Category | Count | Files |
|
||||||
|----------|-------|-------|
|
|----------|-------|-------|
|
||||||
| CI/CD Workflows | 3 | `ddss-publish.yml`, `ddss-rollback.yml`, `plonds-build.yml` |
|
| CI/CD Workflows | 3 | `plonds-uploader.yml`, `plonds-rollback.yml`, `plonds-comparator.yml` |
|
||||||
| Shared Contracts | 3 | `DeploymentLock.cs`, `UpdatePaths.cs`, `UpdateState.cs` |
|
| Shared Contracts | 3 | `DeploymentLock.cs`, `UpdatePaths.cs`, `UpdateState.cs` |
|
||||||
| Launcher | 2 | `AppJsonContext.cs`, `UpdateModels.cs` |
|
| Launcher | 2 | `AppJsonContext.cs`, `UpdateModels.cs` |
|
||||||
| Services | 7 | `UpdateEngineService.cs`, `DeploymentLockService.cs`, `UpdateDownloadEngine.cs`, `UpdateInstallGateway.cs`, `UpdateOrchestrator.cs`, `UpdateWorkflowService.cs`, `WindowPassthroughService.cs` |
|
| Services | 7 | `UpdateEngineService.cs`, `DeploymentLockService.cs`, `UpdateDownloadEngine.cs`, `UpdateInstallGateway.cs`, `UpdateOrchestrator.cs`, `UpdateWorkflowService.cs`, `WindowPassthroughService.cs` |
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
### 1. CI/CD Workflows Enhancement
|
### 1. CI/CD Workflows Enhancement
|
||||||
|
|
||||||
#### `.github/workflows/ddss-publish.yml` (+106 lines)
|
#### `.github/workflows/plonds-uploader.yml` (+106 lines)
|
||||||
**Purpose:** Enhanced deployment publishing workflow
|
**Purpose:** Enhanced deployment publishing workflow
|
||||||
|
|
||||||
**Key Changes:**
|
**Key Changes:**
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
- Added atomic channel pointer publishing
|
- Added atomic channel pointer publishing
|
||||||
- Improved deployment pipeline reliability
|
- Improved deployment pipeline reliability
|
||||||
|
|
||||||
#### `.github/workflows/ddss-rollback.yml` (+146 lines) — **NEW**
|
#### `.github/workflows/plonds-rollback.yml` (+146 lines) — **NEW**
|
||||||
**Purpose:** Automated rollback workflow
|
**Purpose:** Automated rollback workflow
|
||||||
|
|
||||||
**Key Features:**
|
**Key Features:**
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
- Emergency deployment recovery
|
- Emergency deployment recovery
|
||||||
- Version rollback automation
|
- Version rollback automation
|
||||||
|
|
||||||
#### `.github/workflows/plonds-build.yml` (+5 lines)
|
#### `.github/workflows/plonds-comparator.yml` (+5 lines)
|
||||||
**Changes:**
|
**Changes:**
|
||||||
- Adjusted build concurrency settings
|
- Adjusted build concurrency settings
|
||||||
- Updated release event triggers
|
- Updated release event triggers
|
||||||
|
|||||||
Reference in New Issue
Block a user