mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-05-12 00:28:20 -04:00
feat(desktop): ship-readiness metadata & CI scaffolding (#5255)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
3
.github/release.yml
vendored
3
.github/release.yml
vendored
@@ -26,6 +26,9 @@ changelog:
|
||||
labels:
|
||||
- enhancement
|
||||
- feature
|
||||
- title: 🖥️ Desktop
|
||||
labels:
|
||||
- desktop
|
||||
- title: 🛠️ Fixes
|
||||
labels:
|
||||
- bug
|
||||
|
||||
2
.github/workflows/pr_enforce_labels.yml
vendored
2
.github/workflows/pr_enforce_labels.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
script: |
|
||||
// Extract labels from the payload directly to avoid extra API calls
|
||||
const latestLabels = context.payload.pull_request.labels.map(label => label.name);
|
||||
const requiredLabels = ['bugfix', 'enhancement', 'automation', 'dependencies', 'repo', 'release', 'refactor', 'chore', 'ci', 'build', 'testing', 'documentation'];
|
||||
const requiredLabels = ['bugfix', 'enhancement', 'automation', 'dependencies', 'repo', 'release', 'refactor', 'desktop', 'chore', 'ci', 'build', 'testing', 'documentation'];
|
||||
console.log('Labels from payload:', latestLabels);
|
||||
const hasRequiredLabel = latestLabels.some(label => requiredLabels.includes(label));
|
||||
if (!hasRequiredLabel) {
|
||||
|
||||
26
.github/workflows/release.yml
vendored
26
.github/workflows/release.yml
vendored
@@ -53,6 +53,14 @@ on:
|
||||
required: false
|
||||
INTERNAL_BUILDS_HOST_PAT:
|
||||
required: false
|
||||
APPLE_SIGNING_IDENTITY:
|
||||
required: false
|
||||
APPLE_ID:
|
||||
required: false
|
||||
APPLE_APP_SPECIFIC_PASSWORD:
|
||||
required: false
|
||||
APPLE_TEAM_ID:
|
||||
required: false
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ inputs.tag_name }}
|
||||
@@ -284,7 +292,13 @@ jobs:
|
||||
- name: Package Native Distributions
|
||||
env:
|
||||
ORG_GRADLE_PROJECT_appVersionName: ${{ needs.prepare-build-info.outputs.APP_VERSION_NAME }}
|
||||
VERSION_CODE: ${{ needs.prepare-build-info.outputs.APP_VERSION_CODE }}
|
||||
APPIMAGE_EXTRACT_AND_RUN: 1
|
||||
SIGN_MACOS: ${{ runner.os == 'macOS' && 'true' || 'false' }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
# Quote the -P flag: PowerShell on Windows interprets the dot in
|
||||
# `-PaboutLibraries.release=true` as member access on `-PaboutLibraries`,
|
||||
# splitting the token and feeding `.release=true` to Gradle as a task name.
|
||||
@@ -309,6 +323,18 @@ jobs:
|
||||
retention-days: 1
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Attest Desktop artifact provenance
|
||||
if: success()
|
||||
uses: actions/attest-build-provenance@v4
|
||||
with:
|
||||
subject-path: |
|
||||
desktop/build/compose/binaries/main-release/*/*.dmg
|
||||
desktop/build/compose/binaries/main-release/*/*.msi
|
||||
desktop/build/compose/binaries/main-release/*/*.exe
|
||||
desktop/build/compose/binaries/main-release/*/*.deb
|
||||
desktop/build/compose/binaries/main-release/*/*.rpm
|
||||
desktop/build/compose/binaries/main-release/*/*.AppImage
|
||||
|
||||
github-release:
|
||||
if: ${{ !cancelled() && !failure() }}
|
||||
runs-on: ubuntu-24.04-arm
|
||||
|
||||
@@ -39,6 +39,10 @@ width="24%">](https://play.google.com/store/apps/details?id=com.geeksville.mesh&
|
||||
The play store is the last to update of these options, but if you want to join the Play Store testing program go to [this URL](https://play.google.com/apps/testing/com.geeksville.mesh) and opt-in to become a tester.
|
||||
If you encounter any problems or have questions, [ask us on the discord](https://discord.gg/meshtastic), [create an issue](https://github.com/meshtastic/Meshtastic-Android/issues), or [post in the forum](https://github.com/orgs/meshtastic/discussions) and we'll help as we can.
|
||||
|
||||
### Desktop
|
||||
|
||||
**Meshtastic Desktop** installers (macOS DMG, Windows MSI/EXE, Linux DEB/RPM/AppImage) are available from [GitHub Releases](https://github.com/meshtastic/Meshtastic-Android/releases). A Flatpak package is maintained at [vidplace7/org.meshtastic.desktop](https://github.com/vidplace7/org.meshtastic.desktop).
|
||||
|
||||
## Documentation
|
||||
|
||||
The project's documentation is generated with [Dokka](https://kotlinlang.org/docs/dokka-introduction.html) and hosted on GitHub Pages. It is automatically updated on every push to the `main` branch.
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
# Meshtastic-Android Release Process
|
||||
# Meshtastic Release Process
|
||||
|
||||
This guide summarizes the steps for releasing a new version of Meshtastic-Android. The process is fully automated via GitHub Actions and Fastlane.
|
||||
This guide summarizes the steps for releasing new versions of Meshtastic Android and Desktop. The process is fully automated via GitHub Actions and Fastlane.
|
||||
|
||||
## Overview
|
||||
|
||||
The entire release process is managed by a single, manually-triggered GitHub Action: **`Create or Promote Release`**.
|
||||
|
||||
- **Trigger:** To start a new release or promote an existing one, a developer manually runs the workflow from the GitHub Actions tab.
|
||||
- **Inputs:** The workflow requires two inputs:
|
||||
- **Inputs:** The workflow requires the following inputs:
|
||||
1. `version`: The base version number you are releasing (e.g., `2.4.0`).
|
||||
2. `channel`: The release channel you are targeting (`internal`, `closed`, `open`, or `production`).
|
||||
3. `build_desktop`: Whether to build and attach Desktop native installers (default: `false`).
|
||||
- **Automation:** The workflow handles everything automatically:
|
||||
- **Syncs Assets:** Fetches the latest firmware/hardware lists, protobuf definitions, and translations (Crowdin).
|
||||
- **Generates Changelog:** Creates a clean changelog from commits since the last production release and commits it to the repo.
|
||||
- **Updates Config:** Automatically bumps the `VERSION_NAME_BASE` in `config.properties`.
|
||||
- **Verifies & Tags:** Runs lint checks, builds the app, and *only* tags the release if successful.
|
||||
- **Deploys:** Uploads the build to the correct Google Play track and attaches artifacts (`.aab`/`.apk`) to a GitHub Release.
|
||||
- **Deploys Android:** Uploads the build to the correct Google Play track and attaches artifacts (`.aab`/`.apk`) to a GitHub Release.
|
||||
- **Deploys Desktop** *(when enabled)*: Builds native installers (DMG, MSI, EXE, DEB, RPM, AppImage) on a matrix of runners and attaches them to the GitHub Release.
|
||||
- **Changelog:** Release notes are auto-generated from PR labels. Ensure PRs are labeled correctly to maintain an accurate changelog.
|
||||
|
||||
## Release Steps
|
||||
@@ -27,13 +29,15 @@ The entire release process is managed by a single, manually-triggered GitHub Act
|
||||
3. Click the **"Run workflow"** dropdown.
|
||||
4. Enter the base `version` (e.g., `2.4.0`).
|
||||
5. Select the `internal` channel.
|
||||
6. Click **"Run workflow"**.
|
||||
6. Check **`build_desktop`** if you want Desktop installers included in this release.
|
||||
7. Click **"Run workflow"**.
|
||||
|
||||
The workflow will:
|
||||
1. **Create a new commit** on the current branch containing updated assets, translations, and the new changelog.
|
||||
2. **Tag** that commit with an incremental internal tag (e.g., `v2.4.0-internal.1`).
|
||||
3. **Build & Deploy** the verified artifact to the Play Store Internal track.
|
||||
4. Publish a **draft** pre-release on GitHub.
|
||||
3. **Build & Deploy** the verified Android artifact to the Play Store Internal track.
|
||||
4. **Build Desktop** *(if enabled)* native installers on macOS, Windows, and Linux runners.
|
||||
5. Publish a **draft** pre-release on GitHub with all artifacts attached.
|
||||
|
||||
### 2. Promote to the Next Channel
|
||||
|
||||
@@ -54,8 +58,43 @@ After testing is complete on all pre-release channels, you can create the final
|
||||
|
||||
### 4. Post-Release
|
||||
|
||||
1. **Verify:** Check the Google Play Console to ensure the build is available on the correct track.
|
||||
2. **Merge:** Merge the release branch (if one was used for stabilization) back into `main`.
|
||||
1. **Verify Android:** Check the Google Play Console to ensure the build is available on the correct track.
|
||||
2. **Verify Desktop** *(if built)*: Download and smoke-test at least one installer (DMG, MSI, or AppImage) from the GitHub Release.
|
||||
3. **Merge:** Merge the release branch (if one was used for stabilization) back into `main`.
|
||||
|
||||
## Desktop Release Details
|
||||
|
||||
Desktop native installers are built as part of the main release pipeline when `build_desktop` is enabled. There is no separate promotion flow for Desktop — installers are built once during the `internal` release and attached to the GitHub Release alongside Android artifacts.
|
||||
|
||||
### Artifacts Produced
|
||||
|
||||
| Platform | Format | Runner |
|
||||
|---|---|---|
|
||||
| macOS | `.dmg` | `macos-latest` |
|
||||
| Windows | `.msi`, `.exe` | `windows-latest` |
|
||||
| Linux (x86_64) | `.deb`, `.rpm`, `.AppImage` | `ubuntu-24.04` |
|
||||
| Linux (ARM64) | `.deb`, `.rpm`, `.AppImage` | `ubuntu-24.04-arm` |
|
||||
|
||||
### macOS Code Signing & Notarization
|
||||
|
||||
macOS builds are signed and notarized when the following CI secrets are configured:
|
||||
|
||||
| Secret | Source |
|
||||
|---|---|
|
||||
| `APPLE_SIGNING_IDENTITY` | Developer ID Application certificate (from Apple Developer account) |
|
||||
| `APPLE_ID` | Apple ID email used for notarization |
|
||||
| `APPLE_APP_SPECIFIC_PASSWORD` | App-specific password from [appleid.apple.com](https://appleid.apple.com) |
|
||||
| `APPLE_TEAM_ID` | 10-character Apple Developer Team ID |
|
||||
|
||||
Without these secrets, macOS builds are produced unsigned. Unsigned DMGs will trigger Gatekeeper warnings on end-user machines.
|
||||
|
||||
### Version Alignment
|
||||
|
||||
Desktop uses the same version resolution chain as Android — both read `VERSION_CODE_OFFSET` and `VERSION_NAME_BASE` from `config.properties`, with CI passing the resolved values as environment variables. Version names are sanitized to strict `X.Y.Z` format for native installer compatibility.
|
||||
|
||||
### Flatpak
|
||||
|
||||
Flatpak packaging is maintained externally at [vidplace7/org.meshtastic.desktop](https://github.com/vidplace7/org.meshtastic.desktop). It builds `:desktop:packageUberJarForCurrentOS` (not the native distribution pipeline) and includes its own AppStream metainfo, `.desktop` entry, and JBR bundling.
|
||||
|
||||
## Build Attestations & Provenance
|
||||
|
||||
|
||||
@@ -124,8 +124,8 @@ compose.desktop {
|
||||
mainClass = "org.meshtastic.desktop.MainKt"
|
||||
jvmArgs(
|
||||
"-Xmx2G",
|
||||
"-Dapple.awt.application.name=Meshtastic",
|
||||
"-Dcom.apple.mrj.application.apple.menu.about.name=Meshtastic",
|
||||
"-Dapple.awt.application.name=Meshtastic Desktop",
|
||||
"-Dcom.apple.mrj.application.apple.menu.about.name=Meshtastic Desktop",
|
||||
"-Dcom.apple.bundle.identifier=org.meshtastic.desktop",
|
||||
)
|
||||
|
||||
@@ -140,7 +140,7 @@ compose.desktop {
|
||||
}
|
||||
|
||||
nativeDistributions {
|
||||
packageName = "Meshtastic"
|
||||
packageName = "Meshtastic Desktop"
|
||||
|
||||
// Ensure critical JVM modules are included in the custom JRE bundled with the app.
|
||||
// jdeps might miss some of these if they are loaded via reflection or JNI.
|
||||
@@ -157,8 +157,8 @@ compose.desktop {
|
||||
// Increase max heap size to prevent OOM issues on complex maps/data
|
||||
jvmArgs(
|
||||
"-Xmx2G",
|
||||
"-Dapple.awt.application.name=Meshtastic",
|
||||
"-Dcom.apple.mrj.application.apple.name=Meshtastic",
|
||||
"-Dapple.awt.application.name=Meshtastic Desktop",
|
||||
"-Dcom.apple.mrj.application.apple.menu.about.name=Meshtastic Desktop",
|
||||
"-Dcom.apple.bundle.identifier=org.meshtastic.desktop",
|
||||
)
|
||||
|
||||
@@ -167,6 +167,7 @@ compose.desktop {
|
||||
iconFile.set(project.file("src/main/resources/icon.icns"))
|
||||
minimumSystemVersion = "12.0"
|
||||
bundleID = "org.meshtastic.desktop"
|
||||
appCategory = "public.app-category.utilities"
|
||||
entitlementsFile.set(project.file("entitlements.plist"))
|
||||
infoPlist {
|
||||
extraKeysRawXml =
|
||||
@@ -191,22 +192,41 @@ compose.desktop {
|
||||
"""
|
||||
.trimIndent()
|
||||
}
|
||||
// TODO: To prepare for real distribution on macOS, you'll need to sign and notarize.
|
||||
// You can inject these from CI environment variables.
|
||||
// sign = true
|
||||
// notarize = true
|
||||
// appleID = System.getenv("APPLE_ID")
|
||||
// appStorePassword = System.getenv("APPLE_APP_SPECIFIC_PASSWORD")
|
||||
// macOS code signing and notarization.
|
||||
// Required CI secrets:
|
||||
// APPLE_SIGNING_IDENTITY – e.g. "Developer ID Application: Meshtastic LLC (TEAMID)"
|
||||
// APPLE_ID – Apple ID email used for notarization
|
||||
// APPLE_APP_SPECIFIC_PASSWORD – App-specific password from appleid.apple.com
|
||||
// APPLE_TEAM_ID – 10-character Apple Developer Team ID
|
||||
val signMacOs = System.getenv("SIGN_MACOS")?.toBoolean() ?: false
|
||||
if (signMacOs) {
|
||||
signing {
|
||||
sign.set(true)
|
||||
identity.set(System.getenv("APPLE_SIGNING_IDENTITY"))
|
||||
}
|
||||
notarization {
|
||||
appleID.set(System.getenv("APPLE_ID"))
|
||||
password.set(System.getenv("APPLE_APP_SPECIFIC_PASSWORD"))
|
||||
teamID.set(System.getenv("APPLE_TEAM_ID"))
|
||||
}
|
||||
}
|
||||
}
|
||||
windows {
|
||||
iconFile.set(project.file("src/main/resources/icon.ico"))
|
||||
menuGroup = "Meshtastic"
|
||||
// TODO: Must generate and set a consistent UUID for Windows upgrades.
|
||||
// upgradeUuid = "YOUR-UPGRADE-UUID-HERE"
|
||||
shortcut = true
|
||||
menu = true
|
||||
dirChooser = true
|
||||
// Stable UUID ensures MSI upgrades replace the previous installation
|
||||
// rather than installing side-by-side. NEVER change this value.
|
||||
upgradeUuid = "4974EA87-98AA-470E-B590-0BD5CF9FAE8E"
|
||||
}
|
||||
linux {
|
||||
iconFile.set(project.file("src/main/resources/icon.png"))
|
||||
menuGroup = "Network"
|
||||
debMaintainer = "developers@meshtastic.org"
|
||||
appCategory = "Network"
|
||||
rpmLicenseType = "GPLv3+"
|
||||
}
|
||||
|
||||
// Define target formats based on the current host OS to avoid configuration errors
|
||||
|
||||
@@ -10,5 +10,9 @@
|
||||
<true/>
|
||||
<key>com.apple.security.device.bluetooth</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.usb</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -77,7 +77,7 @@ These items address structural gaps identified in the March 2026 architecture re
|
||||
| Notifications | ✅ Desktop native notifications with system tray icon support |
|
||||
| MenuBar | ✅ Removed — replaced with `onPreviewKeyEvent` keyboard shortcuts (⌘Q, ⌘,, ⌘⇧T, ⌘1-4, ⌘/) |
|
||||
| About | ✅ Shared `commonMain` screen (AboutLibraries KMP `produceLibraries` + per-platform JSON) |
|
||||
| Packaging | ✅ Done — Native distribution pipeline in CI (DMG, MSI, DEB) |
|
||||
| Packaging | ✅ Done — Native distribution pipeline in CI (DMG, MSI, DEB). Windows `upgradeUuid` set; macOS signing/notarization wired behind `SIGN_MACOS` env flag; desktop build attestation in release CI. Flatpak packaging maintained externally at [vidplace7/org.meshtastic.desktop](https://github.com/vidplace7/org.meshtastic.desktop) (includes AppStream metainfo, `.desktop` entry, and JBR bundling); see [PR #4807](https://github.com/meshtastic/Meshtastic-Android/pull/4807) for `flatpakGradleGenerator` integration |
|
||||
|
||||
## Near-Term Priorities (30 days)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user