diff --git a/electron-builder.json b/electron-builder.json index 7d10082..e0f011e 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -2,7 +2,6 @@ "$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json", "appId": "com.qclawai.qclaw", "asar": true, - "forceCodeSigning": true, "afterSign": "scripts/after-sign-notarize.cjs", "afterAllArtifactBuild": "scripts/after-all-artifact-build.cjs", "directories": { @@ -30,6 +29,7 @@ "icon": "build/icon.icns", "category": "public.app-category.developer-tools", "artifactName": "Qclaw-Lite_${env.QCLAW_DISPLAY_VERSION}.${ext}", + "forceCodeSigning": true, "hardenedRuntime": true, "gatekeeperAssess": false, "strictVerify": false, @@ -47,6 +47,7 @@ "format": "UDZO" }, "win": { + "icon": "build/icon.ico", "target": [ { "target": "nsis", diff --git a/package.json b/package.json index 0453956..e3169a3 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,9 @@ "package:mac": "npm run check:mac:release-env -- --allow-placeholder-publish --skip-notarize && npm run build:app && QCLAW_SKIP_NOTARIZE=1 node scripts/run-electron-builder.mjs --mac --publish never", "package:mac:notarized": "npm run check:mac:release-env -- --allow-placeholder-publish && npm run build:app && node scripts/run-electron-builder.mjs --mac --publish never", "release:mac": "npm run check:mac:release-env && npm run build:app && node scripts/run-electron-builder.mjs --mac --publish never", + "check:win:release-env": "node scripts/check-win-release-env.mjs", + "package:win": "npm run build:app && node scripts/run-electron-builder.mjs --win --publish never", + "release:win": "npm run check:win:release-env && npm run build:app && node scripts/run-electron-builder.mjs --win --publish never", "release:prepare-cos": "node scripts/prepare-cos-update-release.mjs", "preview": "vite preview", "pretest": "vite build --mode=test", diff --git a/scripts/after-all-artifact-build.cjs b/scripts/after-all-artifact-build.cjs index 68be6ef..92f37ef 100644 --- a/scripts/after-all-artifact-build.cjs +++ b/scripts/after-all-artifact-build.cjs @@ -53,6 +53,8 @@ function parseCodesignDetails(output) { } async function afterAllArtifactBuild(buildResult) { + if (process.platform !== 'darwin') return [] + const appBundles = findAppBundles(buildResult.outDir) if (appBundles.length === 0) return [] diff --git a/scripts/check-win-release-env.mjs b/scripts/check-win-release-env.mjs new file mode 100644 index 0000000..cf9c1d1 --- /dev/null +++ b/scripts/check-win-release-env.mjs @@ -0,0 +1,79 @@ +import { existsSync } from 'node:fs' +import { resolve } from 'node:path' +import { LOCAL_CONFIG_PATH, readLocalPublishUrl } from './electron-builder-local-config.mjs' +import { resolvePackageVersion } from './package-version.mjs' + +const args = new Set(process.argv.slice(2)) +const allowPlaceholderPublish = args.has('--allow-placeholder-publish') +const skipSign = args.has('--skip-sign') + +function fail(message) { + console.error(`[win-release-preflight] ${message}`) + process.exit(1) +} + +function warn(message) { + console.warn(`[win-release-preflight] ${message}`) +} + +function readTrimmedEnv(name) { + return String(process.env[name] || '').trim() +} + +function isPlaceholderPublishUrl(value) { + const normalized = String(value || '').trim() + return ( + !normalized || + /example\.invalid/i.test(normalized) || + /example\.com/i.test(normalized) || + /electron-vite-react/i.test(normalized) || + /releases\/download\/v0\.9\.9/i.test(normalized) + ) +} + +async function main() { + if (process.platform !== 'win32') { + fail('`release:win` 只能在 Windows 上运行。') + } + + const localPublishUrl = await readLocalPublishUrl() + const publishUrl = + localPublishUrl || + readTrimmedEnv('QCLAW_UPDATE_PUBLISH_URL') + + if (isPlaceholderPublishUrl(publishUrl)) { + const message = `当前自动更新源仍是占位值。正式发布前必须在 ${LOCAL_CONFIG_PATH} 或 QCLAW_UPDATE_PUBLISH_URL 中提供真实更新源。` + if (allowPlaceholderPublish) { + warn(message) + } else { + fail(`${message} 如只做本地构建测试,请改用 \`npm run package:win\`。`) + } + } + + if (!skipSign) { + const cscLink = readTrimmedEnv('WIN_CSC_LINK') + const cscPassword = readTrimmedEnv('WIN_CSC_KEY_PASSWORD') + + if (!cscLink) { + fail( + '未设置 WIN_CSC_LINK。请提供 .pfx 证书路径或 base64 编码内容,或使用 `npm run package:win` 构建未签名版本。' + ) + } + + if (!cscPassword) { + fail('未设置 WIN_CSC_KEY_PASSWORD。请提供证书密码。') + } + + if (!cscLink.startsWith('data:') && !existsSync(resolve(cscLink))) { + fail(`WIN_CSC_LINK 指向的证书文件不存在:${cscLink}`) + } + } + + const packageVersion = resolvePackageVersion() + const signSuffix = skipSign ? ',本次仅构建,不签名' : '' + console.log( + `[win-release-preflight] 检查通过${signSuffix},本次打包版本号将使用 ${packageVersion.displayVersion}(内部 semver ${packageVersion.version})。` + ) +} + +await main()