Files
msime-windows/.github/workflows/release.yml
T
fanlusky 9dfa69c7e5 build(installer): 打包神经整句模型并在发布流程中下载
Prepare-PackageFiles 断言并拷贝两个模型与授权声明;release workflow 在收集产物前
运行 fetch-neural-model.ps1。
2026-09-24 14:03:43 +08:00

623 lines
29 KiB
YAML

name: Release
# Releasing is automatic. A push to main that carries a fix or a feat ends with a published installer, without anybody merging or dispatching anything: this workflow refreshes release-please's pull request, tests it, merges it, turns the merge into a draft release, then builds, signs and publishes that draft.
#
# The whole cycle runs inside the one run that the original push started. land-release-pr.sh merges with GITHUB_TOKEN, whose pushes do not start workflow runs, so the merge cannot produce a second Release run queued behind this one on the concurrency group.
#
# This spends code signing signatures on every releasable merge to main -- one per payload EXE/DLL plus one for the installer, so roughly fifteen per release rather than one. The certificate allows 3000 signatures a month, so the quota is still not what constrains this; what it spends is release hygiene -- see docs/product-release.md.
#
# workflow_dispatch stays, and is now a repair path rather than the normal one. It builds an existing draft, which is what a run that failed after creating the draft leaves behind.
on:
push:
branches:
- main
workflow_dispatch:
inputs:
tag:
description: Draft release tag to build, sign and publish, for example v2026.9.1
required: true
type: string
permissions:
contents: read
concurrency:
# A push refreshes release-please metadata while workflow_dispatch builds a
# selected draft. They must not block each other on the same branch lock.
group: release-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: false
jobs:
prepare:
name: Prepare release metadata
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
# Read the PR-triggered run; merging stays scoped to GITHUB_TOKEN.
actions: read
contents: write
pull-requests: write
outputs:
should_publish: ${{ github.event_name == 'workflow_dispatch' || steps.target.outputs.release_created == 'true' }}
tag_name: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || steps.target.outputs.tag_name }}
version: ${{ github.event_name == 'workflow_dispatch' && steps.requested_release.outputs.version || steps.target.outputs.version }}
target_sha: ${{ github.event_name == 'workflow_dispatch' && steps.requested_release.outputs.target_sha || steps.target.outputs.target_sha }}
steps:
- name: Check out release automation
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Separate release metadata from PR updates to preserve release-please ordering.
# Recover an already-merged release before calculating the next PR, matching release-please's
# normal releases-then-pull-requests ordering.
- name: Require the release metadata credential
if: ${{ github.event_name == 'push' }}
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }}
run: |
if [[ -z "$RELEASE_TOKEN" ]]; then
echo '::error::RELEASE_PLEASE_TOKEN must allow contents and workflows writes to create release tags.'
exit 1
fi
- name: Recover releases from previously merged pull requests
if: ${{ github.event_name == 'push' }}
id: release_pr
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
with:
# release-please reads and writes the repository's default branch unless told otherwise, and that is now develop. The release branch is main: without this the version pull request, the changelog and the tag all land on develop, and the branch this workflow waits for (release-please--branches--main--*) is never created.
target-branch: main
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
skip-github-pull-request: true
- name: Refresh the release pull request
# When recovery found a release to publish, do not create the next
# release PR in the same run. That PR belongs to the next main push.
if: ${{ github.event_name == 'push' && steps.release_pr.outputs.release_created != 'true' }}
id: release_update
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
with:
target-branch: main
# A trusted credential starts normal PR checks without manual workflow approval.
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
skip-github-release: true
- name: Test and merge the release pull request
if: ${{ github.event_name == 'push' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
run: bash scripts/ci/land-release-pr.sh
- name: Create the release for the merged pull request
if: ${{ github.event_name == 'push' }}
id: release
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
with:
target-branch: main
# Creating a tag at a historical workflow-changing commit needs workflows:write.
# Only GITHUB_TOKEN merges to main, preventing a second Release run.
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
skip-github-pull-request: true
- name: Resolve the release this run publishes
if: ${{ github.event_name == 'push' }}
id: target
env:
FIRST_CREATED: ${{ steps.release_pr.outputs.release_created }}
FIRST_TAG: ${{ steps.release_pr.outputs.tag_name }}
FIRST_VERSION: ${{ steps.release_pr.outputs.version }}
FIRST_SHA: ${{ steps.release_pr.outputs.sha }}
SECOND_CREATED: ${{ steps.release.outputs.release_created }}
SECOND_TAG: ${{ steps.release.outputs.tag_name }}
SECOND_VERSION: ${{ steps.release.outputs.version }}
SECOND_SHA: ${{ steps.release.outputs.sha }}
run: bash scripts/ci/resolve-auto-release.sh
- name: Validate requested draft release
if: ${{ github.event_name == 'workflow_dispatch' }}
id: requested_release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
TAG_NAME: ${{ inputs.tag }}
run: bash scripts/ci/validate-draft-release.sh
dependencies:
name: Load the release product lock
needs: prepare
if: ${{ needs.prepare.outputs.should_publish == 'true' }}
runs-on: ubuntu-24.04
timeout-minutes: 60
outputs:
dictionary_tag: ${{ steps.lock.outputs.dictionary_tag }}
steps:
- name: Read dependencies from the release commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.prepare.outputs.target_sha }}
persist-credentials: false
# verify-published is a release gate and is deliberately absent from ci.yml: a pull request
# legitimately locks a branch commit while a change lands in the engine and here at once, and
# enforcing reachability there would deadlock the landing it protects.
- name: Validate and export the product lock
id: lock
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 scripts/product_lock.py verify-published
python3 scripts/product_lock.py outputs --github-output "$GITHUB_OUTPUT"
tsf:
name: Build TSF ${{ matrix.name }}
needs: [prepare, dependencies]
if: ${{ needs.prepare.outputs.should_publish == 'true' }}
runs-on: [self-hosted, Windows, X64, msime-windows]
env:
# Each self-hosted runner has a different default vcpkg installation.
# Keep every matrix job aligned with the registry selected below even
# when GitHub schedules x64 and Win32 on different runner instances.
VCPKG_ROOT: ${{ matrix.vcpkg_root }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- name: x64
architecture: x64
triplet: x64-windows-static
build_dir: windows/build64-release
vcpkg_root: E:\msime-runner\vcpkg-1
- name: Win32
architecture: Win32
triplet: x86-windows-static
build_dir: windows/build32-release
vcpkg_root: E:\msime-runner\vcpkg-2
steps:
- name: Check out release commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.prepare.outputs.target_sha }}
submodules: recursive
persist-credentials: false
# Some runner instances leave _work owned by SYSTEM while the job itself
# runs as `runner`. checkout still succeeds, so the first plain git call
# is what exits 128 on dubious ownership, minutes into the job.
#
# The self-hosted jobs are separate runner instances on one machine, so
# they share C:\Users\runner\.gitconfig and reach this step in the same
# second. Whoever loses that race gets "could not lock config file". Read
# the list back before each attempt so a peer's write counts as success.
- name: Trust the runner workspace
shell: pwsh
run: |
$workspace = $env:GITHUB_WORKSPACE -replace '\\', '/'
foreach ($attempt in 1..10) {
$trusted = git config --global --get-all safe.directory
if ($trusted -contains $workspace) { exit 0 }
git config --global --add safe.directory $workspace
if ($LASTEXITCODE -eq 0) { exit 0 }
Start-Sleep -Milliseconds (200 * $attempt)
}
throw "Could not add $workspace to the global safe.directory list"
- name: Stamp the version resource
shell: pwsh
run: |
python scripts/apply_version.py
python scripts/apply_version.py --check
- name: Install dependencies
shell: pwsh
working-directory: windows
run: |
& "$env:VCPKG_ROOT\\vcpkg.exe" install --triplet ${{ matrix.triplet }}
# CMakePresets.json points at a developer machine's vcpkg, so the presets cannot be used
# here. This mirrors what .github/workflows/ci.yml already does, into the build directory
# layout that the installer's Prepare-PackageFiles.ps1 expects.
- name: Verify the selected vcpkg root
shell: pwsh
run: |
$expected = '${{ matrix.vcpkg_root }}'
if ($env:VCPKG_ROOT -ne $expected) {
throw "VCPKG_ROOT is '$env:VCPKG_ROOT'; expected '$expected' for ${{ matrix.name }} on runner '$env:RUNNER_NAME'"
}
- name: Configure
shell: pwsh
run: >
cmake -S windows -B ${{ matrix.build_dir }} -A ${{ matrix.architecture }}
-DCMAKE_TOOLCHAIN_FILE="${{ matrix.vcpkg_root }}/scripts/buildsystems/vcpkg.cmake"
-DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }}
- name: Build
shell: pwsh
run: cmake --build ${{ matrix.build_dir }} --config Release --parallel
- name: Check the TSF binary and symbols the installer expects
shell: pwsh
run: ./scripts/ci/check-tsf-dll.ps1 -BuildDir '${{ matrix.build_dir }}'
- name: Test the wire contract on this architecture
run: ctest --test-dir ${{ matrix.build_dir }} -C Release --output-on-failure
- name: Upload the TSF binary and symbols
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: tsf-${{ matrix.name }}
# Upload the output directory so download-artifact restores its contents directly into
# the layout Prepare-PackageFiles.ps1 expects.
path: ${{ matrix.build_dir }}/Release
if-no-files-found: error
server:
name: Build Server
needs: [prepare, dependencies]
if: ${{ needs.prepare.outputs.should_publish == 'true' }}
runs-on: [self-hosted, Windows, X64, msime-windows]
env:
VCPKG_INSTALLATION_ROOT: E:\\msime-runner\\vcpkg-3
timeout-minutes: 90
steps:
- name: Check out release commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.prepare.outputs.target_sha }}
submodules: recursive
persist-credentials: false
# Some runner instances leave _work owned by SYSTEM while the job itself
# runs as `runner`. checkout still succeeds, so the first plain git call
# is what exits 128 on dubious ownership, minutes into the job.
#
# The self-hosted jobs are separate runner instances on one machine, so
# they share C:\Users\runner\.gitconfig and reach this step in the same
# second. Whoever loses that race gets "could not lock config file". Read
# the list back before each attempt so a peer's write counts as success.
- name: Trust the runner workspace
shell: pwsh
run: |
$workspace = $env:GITHUB_WORKSPACE -replace '\\', '/'
foreach ($attempt in 1..10) {
$trusted = git config --global --get-all safe.directory
if ($trusted -contains $workspace) { exit 0 }
git config --global --add safe.directory $workspace
if ($LASTEXITCODE -eq 0) { exit 0 }
Start-Sleep -Milliseconds (200 * $attempt)
}
throw "Could not add $workspace to the global safe.directory list"
- name: Install Boost
shell: pwsh
run: ./scripts/ci/install-boost.ps1
# The package job stages these outputs into the installer's expected directory.
- name: Configure
shell: pwsh
run: >
cmake -S server -B server/build-release -A x64
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"
-DVCPKG_TARGET_TRIPLET=x64-windows
- name: Build
shell: pwsh
run: cmake --build server/build-release --config Release --parallel
- name: Check the binaries the installer requires
shell: pwsh
run: ./scripts/ci/check-server-binaries.ps1 -BuildDir server/build-release/bin/Release
- name: Test Server with the release's exact dictionaries
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./scripts/ci/test-server.ps1 -ServerRoot server -StagingRoot "$env:RUNNER_TEMP/product-data" -BuildDir build-release
# A uiAccess=true binary cannot be launched from the non-interactive
# service session used by this runner. Test the normal build first, then
# embed the manifest before upload and signing.
- name: Embed the Server uiAccess manifest
shell: pwsh
run: ./scripts/ci/embed-server-manifest.ps1 -BuildDir server/build-release/bin/Release
- name: Verify the embedded Server uiAccess manifest
shell: pwsh
run: ./scripts/ci/check-server-binaries.ps1 -BuildDir server/build-release/bin/Release
- name: Upload the Server build
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: server
path: server/build-release/bin/Release
if-no-files-found: error
ui:
name: Build settings page
needs: [prepare, dependencies]
if: ${{ needs.prepare.outputs.should_publish == 'true' }}
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Check out release commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.prepare.outputs.target_sha }}
persist-credentials: false
- name: Verify the shipped pages carry the engine's contract
run: python3 ui-html/scripts/sync-contracts.py --check
- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
with:
version: 10
- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: pnpm
cache-dependency-path: ui-html/webview2/settings/ime-settings/pnpm-lock.yaml
- name: Install and build the settings page
working-directory: ui-html/webview2/settings/ime-settings
run: |
pnpm install --frozen-lockfile
pnpm build
- name: Upload the web assets
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: webview2
path: |
ui-html/webview2/candwnd
ui-html/webview2/ftb
ui-html/webview2/menu
ui-html/webview2/shared
ui-html/webview2/settings/ime-settings/dist
if-no-files-found: error
package:
name: Package and publish installer
needs: [prepare, dependencies, tsf, server, ui]
# Stated explicitly even though skipped needs would already skip this job. This is the only job
# that spends a signature, so the condition that stops it belongs here rather than being a
# consequence of four other jobs' conditions that a later edit could quietly undo.
if: ${{ needs.prepare.outputs.should_publish == 'true' }}
runs-on: [self-hosted, Windows, X64, msime-windows]
timeout-minutes: 60
permissions:
contents: write
# Build provenance. Unlike Authenticode this costs nothing and needs no certificate, and the
# Sigstore transparency log it writes to is outside this organisation's control, so it is the
# one integrity signal a repository admin cannot forge by swapping a release asset.
id-token: write
attestations: write
env:
DICTIONARY_TAG: ${{ needs.dependencies.outputs.dictionary_tag }}
# download-dictionaries.sh stages MetasequoiaImeDict/out under this root, and
# Prepare-PackageFiles.ps1 reads its dictionary directory from the same place. Before the
# consolidation this was a synthetic tree holding five sibling checkouts under their
# historical names; now the dictionary release is the only source that still arrives from
# outside, so it lands beside the components in the one checkout.
STAGING_ROOT: .
steps:
# The helpcodes are collected out of engine/helpcode, which is a directory of this repository,
# so a plain checkout of the release commit already carries them.
- name: Check out the release commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.prepare.outputs.target_sha }}
persist-credentials: false
# Some runner instances leave _work owned by SYSTEM while the job itself
# runs as `runner`. checkout still succeeds, so the first plain git call
# is what exits 128 on dubious ownership, minutes into the job.
#
# The self-hosted jobs are separate runner instances on one machine, so
# they share C:\Users\runner\.gitconfig and reach this step in the same
# second. Whoever loses that race gets "could not lock config file". Read
# the list back before each attempt so a peer's write counts as success.
- name: Trust the runner workspace
shell: pwsh
run: |
$workspace = $env:GITHUB_WORKSPACE -replace '\\', '/'
foreach ($attempt in 1..10) {
$trusted = git config --global --get-all safe.directory
if ($trusted -contains $workspace) { exit 0 }
git config --global --add safe.directory $workspace
if ($LASTEXITCODE -eq 0) { exit 0 }
Start-Sleep -Milliseconds (200 * $attempt)
}
throw "Could not add $workspace to the global safe.directory list"
- name: Verify the release commit is on main
shell: bash
run: bash scripts/ci/verify-commit-on-main.sh
- name: Download the x64 TSF binary and symbols
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: tsf-x64
path: windows/build64-release/Release
- name: Download the 32-bit TSF binary and symbols
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: tsf-Win32
path: windows/build32-release/Release
- name: Download the Server build
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: server
path: server/build-release/bin/Release
- name: Download the web assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: webview2
path: ui-html/webview2
- name: Download the dictionaries
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash scripts/ci/download-dictionaries.sh
# The word-lattice language model is the one product input that is neither built from this
# repository's sources nor published in the dictionary release: it is converted here from the
# ARPA corpus pinned in language-model/lock.json. Both the download and the converted result
# are checked against that lock, so this step is reproducible rather than a fetch of whatever
# the upstream file server serves today. It configures engine/ngram alone, so it needs no
# vcpkg and no SQLite on this runner.
- name: Build the word-lattice language model
shell: pwsh
run: ./scripts/build-language-model.ps1
# The neural sentence models are downloaded from the chinese-ime-lm release pinned in
# neural-model/lock.json and checked against the SHA256 recorded there. Prepare-PackageFiles.ps1
# asserts they exist, so this has to run before the payload is collected.
- name: Download the neural sentence models
shell: pwsh
run: ./scripts/fetch-neural-model.ps1
- name: Decide the signing mode
id: signing
shell: pwsh
env:
CERTIFICATE_BASE64: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_BASE64 }}
CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PASSWORD }}
CERTIFICATE_THUMBPRINT: ${{ vars.WINDOWS_SIGNING_CERTIFICATE_THUMBPRINT }}
run: ./scripts/ci/detect-release-signing.ps1
# -IncludeSymbols is what makes the published installer carry the PDBs matching its binaries.
# Staging symbols is opt-in because they are ~140 MB against ~20 MB of binaries and Inno Setup
# compresses them with solid LZMA2, which is why the local test scripts leave them out.
- name: Collect the installer payload
shell: pwsh
working-directory: installer
env:
TARGET_VERSION: ${{ needs.prepare.outputs.version }}
run: >
pwsh -File ./Prepare-PackageFiles.ps1 -TargetVersion $env:TARGET_VERSION
-RepoRoot (Resolve-Path '..').Path
-TsfDirectory windows -ServerDirectory server -UiHtmlDirectory ui-html -NoticesDirectory .
-HelpCodeDirectory engine/helpcode -IncludeSymbols
- name: Embed the exact product dependency manifest
env:
WINDOWS_COMMIT: ${{ needs.prepare.outputs.target_sha }}
run: >
python scripts/product_lock.py manifest
--windows-commit "$env:WINDOWS_COMMIT"
--output installer/app_data/product-manifest.json
# Every payload EXE/DLL, not just the uiAccess server. The server is the only one that
# technically requires a signature (uiAccess=true is ignored without one), but Microsoft
# Defender blocks the unsigned helper processes -- settings page, emoji panel, watchdog --
# and the user sees an input method that installs and then cannot open its own panels.
- name: Sign the payload binaries
if: ${{ steps.signing.outputs.signing_enabled == 'true' }}
shell: pwsh
working-directory: installer
env:
CERTIFICATE_BASE64: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_BASE64 }}
CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PASSWORD }}
CERTIFICATE_THUMBPRINT: ${{ vars.WINDOWS_SIGNING_CERTIFICATE_THUMBPRINT }}
TIMESTAMP_URL: ${{ vars.WINDOWS_SIGNING_TIMESTAMP_URL || 'http://timestamp.digicert.com' }}
run: ../scripts/ci/sign-binaries.ps1 -Recurse -Path 'server_exe', 'tsf_dll'
- name: Install the Chinese language file for Inno Setup
shell: pwsh
run: ./scripts/ci/install-inno-language.ps1
- name: Compile the installer
shell: pwsh
working-directory: installer
run: pwsh -File ./Compile-Installer.ps1
- name: Sign the installer
if: ${{ steps.signing.outputs.signing_enabled == 'true' }}
shell: pwsh
working-directory: installer
env:
CERTIFICATE_BASE64: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_BASE64 }}
CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PASSWORD }}
CERTIFICATE_THUMBPRINT: ${{ vars.WINDOWS_SIGNING_CERTIFICATE_THUMBPRINT }}
TIMESTAMP_URL: ${{ vars.WINDOWS_SIGNING_TIMESTAMP_URL || 'http://timestamp.digicert.com' }}
TARGET_VERSION: ${{ needs.prepare.outputs.version }}
run: ../scripts/ci/sign-binaries.ps1 -Path "Output/MetasequoiaIME_Setup_v$env:TARGET_VERSION.exe"
- name: Name the asset and record its checksum
id: asset
shell: pwsh
working-directory: installer
env:
TARGET_VERSION: ${{ needs.prepare.outputs.version }}
ASSET_SUFFIX: ${{ steps.signing.outputs.asset_suffix }}
run: ../scripts/ci/name-installer-asset.ps1
- name: Upload the installer as a workflow artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: installer
path: |
${{ steps.asset.outputs.asset_path }}
installer/app_data/product-manifest.json
if-no-files-found: error
- name: Attest the installer's build provenance
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: ${{ steps.asset.outputs.asset_path }}
- name: Revalidate the draft release target
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
TAG_NAME: ${{ needs.prepare.outputs.tag_name }}
TARGET_SHA: ${{ needs.prepare.outputs.target_sha }}
run: bash scripts/ci/revalidate-draft-release.sh
- name: Upload and publish the release
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
TAG_NAME: ${{ needs.prepare.outputs.tag_name }}
ASSET_PATH: ${{ steps.asset.outputs.asset_path }}
ASSET_NAME: ${{ steps.asset.outputs.asset_name }}
ASSET_SHA256: ${{ steps.asset.outputs.asset_sha256 }}
SIGNING_ENABLED: ${{ steps.signing.outputs.signing_enabled }}
PRODUCT_MANIFEST: installer/app_data/product-manifest.json
RELEASE_TRIGGER: ${{ github.event_name }}
TARGET_SHA: ${{ needs.prepare.outputs.target_sha }}
run: bash scripts/ci/publish-release.sh
# msime.app/update.json is what the settings page's "检查更新" reads, and MSIME-Web only
# regenerated it from a */30 cron. Scheduled events on public repositories are delayed heavily
# -- measured runs sat roughly two hours apart -- so the site advertised an old version for
# hours after every release. MSIME-Web already declares a repository_dispatch trigger for
# exactly this and nothing was ever sending it.
#
# This runs after publishing on purpose. If the dispatch fails the release is already out and
# correct; what the failure means is that the website is now stale and someone has to act, so
# it is reported as a failure rather than swallowed.
#
# No event condition: the enclosing job already only runs when a release is being published, and gating this on workflow_dispatch limited the notification to the repair path -- the one branch of this workflow that almost never runs. Every release from the normal push path published in silence, MSIME-Web received no dispatch at all, and the site waited for a cron that GitHub delivers roughly seven times a day rather than the forty-eight the schedule asks for. 0.8.0 reached msime.app a day late that way.
- name: Refresh the download manifest on msime.app
shell: bash
env:
GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }}
run: |
if [[ -z "$GH_TOKEN" ]]; then
echo '::error::RELEASE_PLEASE_TOKEN is required to notify MSIME-Web; msime.app/update.json will stay on the previous version until its cron catches up.'
exit 1
fi
gh api --method POST repos/metasequoiaime/MSIME-Web/dispatches -f event_type=update-manifest