Files
deepseek-harness/.github/workflows/windows-package.yml
T

218 lines
11 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Package Desktop · Windows
on:
workflow_dispatch:
inputs:
preset:
description: '打包环境:选择机器上的 test 或 production 配置;同时决定后续发布环境'
type: choice
options: [test, production]
default: test
required: true
signing:
description: '签名方式:unsigned 仅限内部调试,禁止发布到 test / production 或用于自动更新;需要发布请选择 signed(EV 硬件令牌)'
type: choice
options: [signed, unsigned]
default: signed
required: true
test_release_id:
description: '测试 release ID:32 位小写十六进制随机前缀(非鉴权);留空使用机器默认值,连续升级测试须保持相同值'
type: string
default: ''
required: false
source_ref:
description: '打包源码:test 支持仓库内分支或 dsh-v* tag;production 仅支持 master 或 dsh-v* tag;源码须包含 CI 适配脚本'
type: string
default: master
required: true
update_channel:
description: '升级通道:nightly 或 latest(须为稳定版本);自动更新不会切换通道'
type: choice
options: [nightly, latest]
default: nightly
required: true
version_mode:
description: '版本模式:default 为 test 自动编号、production 跟随产品;product 保留原版本,auto 自动编号,manual 手填'
type: choice
options: [default, product, auto, manual]
default: default
required: true
build_version:
description: '手动版本号:仅 manual 时填写完整版本;须为产品原版本或受支持的预发布后缀'
type: string
default: ''
required: false
cache_namespace:
description: '缓存测量命名空间:留空使用共享缓存;新名称用于冷缓存,再次使用同名测热缓存,不清除现有缓存'
type: string
default: ''
required: false
build_root:
description: '独立构建根目录:填写绝对路径,每次任务创建独立源码副本;留空使用 runner 工作区'
type: string
default: ''
required: false
permissions:
contents: read
concurrency:
group: windows-desktop-package
cancel-in-progress: false
jobs:
package:
runs-on: dsh-win-package-trial
timeout-minutes: 120
defaults:
run:
shell: pwsh
env:
PACKAGE_SOURCE_REF: ${{ inputs.source_ref }}
PACKAGE_VERSION_MODE: ${{ inputs.version_mode }}
DSH_DESKTOP_UPDATE_CHANNEL: ${{ inputs.update_channel }}
DSH_TELEMETRY_DISABLED: '1'
DSH_PACKAGING_PRESET: ${{ inputs.preset }}
PACKAGE_TEST_RELEASE_ID: ${{ inputs.test_release_id }}
PACKAGE_SIGNING: ${{ inputs.signing }}
PACKAGE_CACHE_NAMESPACE: ${{ inputs.cache_namespace }}
PACKAGE_BUILD_ROOT: ${{ inputs.build_root }}
steps:
- name: Reset packaging checkout
working-directory: ${{ runner.temp }}
run: |
$workspace = [IO.Path]::GetFullPath($env:GITHUB_WORKSPACE)
$parent = [IO.Path]::GetFullPath($env:RUNNER_WORKSPACE)
if ([IO.Path]::GetDirectoryName($workspace) -ne $parent) { throw 'Checkout must be a direct child of RUNNER_WORKSPACE' }
for ($item = [IO.DirectoryInfo]::new($workspace); $null -ne $item; $item = $item.Parent) {
if ($item.Exists -and ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) { throw 'Checkout ancestors cannot be links' }
}
node -e "const fs = require('node:fs'); fs.rmSync(process.argv[1], { recursive: true, force: true, maxRetries: 3 }); fs.mkdirSync(process.argv[1])" $workspace
if ($LASTEXITCODE -ne 0) { throw 'Checkout cleanup failed' }
- uses: actions/[email protected]
id: checkout
with:
persist-credentials: false
clean: true
ref: ${{ inputs.source_ref }}
- name: Validate selected source and adapter support
run: >-
node -e "const fs=require('node:fs'); const ref=process.env.PACKAGE_SOURCE_REF;
const cp=require('node:child_process'); const preset=process.env.DSH_PACKAGING_PRESET;
if(!['test','production'].includes(preset)) throw Error('Unknown packaging preset');
const tag=/^dsh-v[0-9][0-9A-Za-z.-]*$/.test(ref);
if(preset==='production' && ref!=='master' && !tag) throw Error('Production source must be master or dsh-v*');
if(tag) {
const v=JSON.parse(fs.readFileSync('package.json','utf8')).version;
if(ref!=='dsh-v'+v) throw Error('Source tag must match product version');
const tagged=cp.execFileSync('git',['rev-parse','--verify','refs/tags/'+ref+'^{commit}'],{encoding:'utf8'}).trim();
const head=cp.execFileSync('git',['rev-parse','HEAD'],{encoding:'utf8'}).trim();
if(tagged!==head) throw Error('Checkout does not match source tag');
} else {
const branch=cp.execFileSync('git',['rev-parse','--abbrev-ref','HEAD'],{encoding:'utf8'}).trim();
if(branch==='HEAD' || branch!==ref || ref.startsWith('refs/')) throw Error('Select a branch in this repository, not a SHA or PR ref');
}
if(!fs.readFileSync('apps/desktop/scripts/desktop-ci-version.mjs','utf8').includes('PACKAGE_VERSION_MODE')) throw Error('Source lacks Desktop channel/version CI support; select a newer release');"
- uses: pnpm/[email protected]
with:
dest: ${{ runner.temp }}/setup-pnpm-${{ github.run_id }}-${{ github.run_attempt }}
- uses: actions/[email protected]
with:
node-version: '24'
- name: Select packaging workspace
id: build_workspace
env:
PACKAGE_SOURCE_SHA: ${{ steps.checkout.outputs.commit }}
run: |
if (!$env:PACKAGE_BUILD_ROOT) {
"directory=$env:GITHUB_WORKSPACE" >> $env:GITHUB_OUTPUT
} else {
node apps/desktop/scripts/windows-build-workspace.mjs
exit $LASTEXITCODE
}
- name: Configure persistent pnpm store
# PNPM_HOME belongs to this run; keep downloaded packages outside its temporary directory.
env:
DSH_DESKTOP_PACKAGE_CACHE_DIR: ${{ runner.tool_cache }}/dsh-desktop-package-cache
run: |
$storeRoot = Join-Path ([IO.Path]::GetPathRoot($env:GITHUB_WORKSPACE)) '.pnpm-store'
$namespace = $env:PACKAGE_CACHE_NAMESPACE
if ($namespace) {
if ($namespace -cnotmatch '^[a-z0-9][a-z0-9-]{0,63}\z') { throw 'Cache namespace must contain 1-64 lowercase letters, digits or hyphens' }
if ($namespace -match '^(con|prn|aux|nul|com[1-9]|lpt[1-9])$') { throw 'Cache namespace cannot be a Windows device name' }
$storeRoot = Join-Path $storeRoot $namespace
$env:DSH_DESKTOP_PACKAGE_CACHE_DIR = Join-Path $env:DSH_DESKTOP_PACKAGE_CACHE_DIR $namespace
}
"DSH_DESKTOP_PACKAGE_CACHE_DIR=$env:DSH_DESKTOP_PACKAGE_CACHE_DIR" >> $env:GITHUB_ENV
"PNPM_CONFIG_STORE_DIR=$storeRoot" >> $env:GITHUB_ENV
- name: Install locked dependencies
working-directory: ${{ steps.build_workspace.outputs.directory }}
run: |
pnpm store path
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
pnpm install --frozen-lockfile
exit $LASTEXITCODE
- name: Validate preset and resolve build version
id: settings
working-directory: ${{ steps.build_workspace.outputs.directory }}
env:
PACKAGE_BUILD_VERSION: ${{ inputs.build_version }}
run: node apps/desktop/scripts/prepare-windows-ci.mjs
- name: Check packaging configuration and toolchain
working-directory: ${{ steps.build_workspace.outputs.directory }}
env:
PACKAGE_VERSION: ${{ steps.settings.outputs.version }}
run: |
$packageArgs = @('run', 'package:desktop:win:x64', '--check', '--build-version', $env:PACKAGE_VERSION)
if ($env:PACKAGE_SIGNING -eq 'unsigned') { $packageArgs += '--unsigned' }
pnpm @packageArgs
exit $LASTEXITCODE
- name: Build installer and verify packaged runtime
working-directory: ${{ steps.build_workspace.outputs.directory }}
env:
PACKAGE_VERSION: ${{ steps.settings.outputs.version }}
run: |
$packageArgs = @('run', 'package:desktop:win:x64', '--build-version', $env:PACKAGE_VERSION)
if ($env:PACKAGE_SIGNING -eq 'unsigned') { $packageArgs += '--unsigned' }
pnpm @packageArgs
exit $LASTEXITCODE
- name: Retain complete package outside the checkout
id: retained
working-directory: ${{ steps.build_workspace.outputs.directory }}
env:
PACKAGE_SOURCE_SHA: ${{ steps.checkout.outputs.commit }}
PACKAGE_VERSION: ${{ steps.settings.outputs.version }}
run: node --import tsx apps/desktop/scripts/retain-desktop-ci.ts
- name: Retain packaging diagnostics
if: always() && steps.checkout.outcome == 'success'
uses: actions/[email protected]
with:
name: windows-package-logs-${{ github.run_id }}-${{ github.run_attempt }}
include-hidden-files: true
path: ${{ steps.build_workspace.outputs.directory || github.workspace }}/apps/desktop/.desktop-build/packaging-runs/
if-no-files-found: warn
retention-days: 14
- name: Retain verified unsigned installer
if: success() && inputs.signing == 'unsigned'
uses: actions/[email protected]
with:
name: windows-x64-unsigned-${{ steps.settings.outputs.version }}-${{ github.run_id }}-${{ github.run_attempt }}
include-hidden-files: true
path: ${{ steps.retained.outputs.directory }}/*
if-no-files-found: error
retention-days: 14
- name: Retain verified signed installer
if: success() && inputs.signing == 'signed'
uses: actions/[email protected]
with:
name: windows-x64-signed-${{ steps.settings.outputs.version }}-${{ github.run_id }}-${{ github.run_attempt }}
include-hidden-files: true
path: ${{ steps.retained.outputs.directory }}/*
if-no-files-found: error
retention-days: 14
- name: Remove isolated packaging workspace
if: success() && inputs.build_root != ''
env:
PACKAGE_SOURCE_SHA: ${{ steps.checkout.outputs.commit }}
run: node apps/desktop/scripts/windows-build-workspace.mjs --remove