153 lines
5.3 KiB
Markdown
153 lines
5.3 KiB
Markdown
# Production Launcher Deployment
|
|
|
|
`tool/deploy_launcher.ps1` automates a complete Windows launcher release:
|
|
|
|
1. reads `X.Y.Z+N` from `pubspec.yaml`
|
|
2. verifies that the private DSA key matches the public key embedded in the
|
|
launcher
|
|
3. runs dependency resolution, formatting checks, static analysis, and tests
|
|
4. builds the Windows release with the production API and AppCast URLs
|
|
5. compiles the Inno Setup installer
|
|
6. signs the installer and verifies the signature
|
|
7. generates `appcast.xml` with the real version, byte length, URL, and
|
|
signature
|
|
8. uploads the installer to Yandex Object Storage with public read access
|
|
9. downloads the published installer and compares its SHA-256
|
|
10. publishes AppCast through the service API and verifies the public feed
|
|
|
|
The installer is always uploaded before AppCast. Clients therefore never see a
|
|
release that has not passed the remote download and checksum verification.
|
|
|
|
## Prerequisites
|
|
|
|
The release machine needs:
|
|
|
|
- latest stable Flutter and Dart available on `PATH`
|
|
- Inno Setup 6, normally installed at
|
|
`C:\Program Files (x86)\Inno Setup 6\ISCC.exe`
|
|
- OpenSSL, normally supplied by Git for Windows at
|
|
`C:\Program Files\Git\usr\bin\openssl.exe`
|
|
- Python 3 with `boto3`
|
|
- `.moonwell_signing\dsa_priv.pem`
|
|
- the matching public key at `windows\runner\resources\dsa_pub.pem`
|
|
|
|
Install the Python dependency if required:
|
|
|
|
```powershell
|
|
python -m pip install boto3
|
|
```
|
|
|
|
Back up `.moonwell_signing\dsa_priv.pem` in the project secret store. Never
|
|
commit it, upload it to Object Storage, or send it through chat. Losing this key
|
|
prevents released launchers from accepting future updates.
|
|
|
|
## Required Environment
|
|
|
|
The script reads secrets and storage configuration only from environment
|
|
variables:
|
|
|
|
| Variable | Required | Purpose |
|
|
| --- | --- | --- |
|
|
| `AWS_ACCESS_KEY_ID` | yes | Yandex Object Storage access key |
|
|
| `AWS_SECRET_ACCESS_KEY` | yes | Yandex Object Storage secret |
|
|
| `LAUNCHER_AUTH_KEY` | yes | `Auth` header for the AppCast service endpoint |
|
|
| `AWS_DEFAULT_REGION` | recommended | Defaults to `ru-central1` |
|
|
| `AWS_ENDPOINT` | optional | Defaults to `https://storage.yandexcloud.net` |
|
|
| `AWS_BUCKET` | optional | Defaults to `warcraft-client` |
|
|
| `AWS_USE_PATH_STYLE_ENDPOINT` | optional | Defaults to `true` |
|
|
|
|
Load secrets from the team secret manager into the current PowerShell process.
|
|
Do not put real values in a tracked `.env` file or in the script.
|
|
|
|
## Prepare a Release
|
|
|
|
Increase both parts of the version in `pubspec.yaml`:
|
|
|
|
```yaml
|
|
version: 1.0.2+3
|
|
```
|
|
|
|
`X.Y.Z` is the WinSparkle release version. `N` is the Flutter build number.
|
|
Every production release must have an `X.Y.Z` value greater than the version
|
|
currently published in AppCast.
|
|
|
|
Run a dry run first:
|
|
|
|
```powershell
|
|
.\tool\deploy_launcher.ps1 `
|
|
-DryRun `
|
|
-ExpectedVersion 1.0.2 `
|
|
-ReleaseNotes "Исправления и улучшения MoonWell Launcher."
|
|
```
|
|
|
|
Dry run performs the local build, packaging, signing, signature verification,
|
|
and AppCast generation. It writes the generated feed to
|
|
`build\launcher_release\appcast.xml` and does not change S3 or the website.
|
|
|
|
## Deploy to Production
|
|
|
|
After reviewing the dry-run artifacts:
|
|
|
|
```powershell
|
|
.\tool\deploy_launcher.ps1 `
|
|
-ExpectedVersion 1.0.2 `
|
|
-ReleaseNotes "Исправления и улучшения MoonWell Launcher."
|
|
```
|
|
|
|
The production defaults are:
|
|
|
|
- API: `https://moon-well.online`
|
|
- AppCast: `https://moon-well.online/appcast.xml`
|
|
- bucket: `warcraft-client`
|
|
- object: `moonwell_launcher_setup.exe`
|
|
- installer:
|
|
`https://storage.yandexcloud.net/warcraft-client/moonwell_launcher_setup.exe`
|
|
|
|
On success, the command prints the deployed version, installer URL, SHA-256,
|
|
and AppCast URL. The tracked root `appcast.xml` contains the exact feed sent to
|
|
the server.
|
|
|
|
## Safety Options
|
|
|
|
- `-ExpectedVersion X.Y.Z` prevents deploying an unintended `pubspec.yaml`
|
|
version.
|
|
- The script rejects a release version that is not newer than the public
|
|
AppCast version.
|
|
- `-Force` bypasses that version guard. Use it only to repeat an already
|
|
published version after confirming that replacing the artifact is intended.
|
|
- `-SkipChecks` skips dependency resolution, formatting, analysis, and tests.
|
|
It should not be used for a normal production release.
|
|
- `-FlutterCommand`, `-DartCommand`, `-InnoSetupCommand`, and
|
|
`-OpenSslCommand` override tool locations when they are not on `PATH`.
|
|
|
|
Run `Get-Help .\tool\deploy_launcher.ps1 -Full` or inspect the parameter block
|
|
for all endpoint, bucket, key, and signing-path overrides.
|
|
|
|
## Failure Recovery
|
|
|
|
The script stops on the first failed command.
|
|
|
|
- Failure before S3 upload leaves production unchanged.
|
|
- Failure after S3 upload but before AppCast publication leaves clients on the
|
|
preceding AppCast. Fix the issue and rerun the same release.
|
|
- Failure after AppCast publication requires checking both public URLs and the
|
|
DSA signature before using `-Force`.
|
|
- Never publish AppCast manually before the installer is publicly downloadable
|
|
and its SHA-256 matches the local artifact.
|
|
|
|
After deployment, verify:
|
|
|
|
```powershell
|
|
Invoke-WebRequest `
|
|
-Uri "https://moon-well.online/appcast.xml" `
|
|
-UseBasicParsing
|
|
|
|
Invoke-WebRequest `
|
|
-Uri "https://storage.yandexcloud.net/warcraft-client/moonwell_launcher_setup.exe" `
|
|
-Method Head `
|
|
-UseBasicParsing
|
|
```
|
|
|
|
Rotate any infrastructure credential that was exposed in terminal logs, chat,
|
|
or another non-secret channel.
|