Maintaining mdo
Maintainer-facing procedures: releases, packaging, the docs site, and public metrics. Users never need this page.
Releases
GitHub releases are published from this repository by
.github/workflows/release.yml. Push a version tag such as v0.6.1 to build
Linux, macOS, Windows, and signed Android packages and publish them to a
GitHub Release. The workflow can also be run manually with an existing tag via
Actions → Release → Run workflow.
The release workflow keeps repository access read-only for build jobs and
grants contents: write only to the final release-publishing job. GitHub
Actions are pinned to commit SHAs, with Dependabot configured to propose
updates.
Release checklist:
- Update
CHANGELOG.md: move Unreleased items under the new version heading with the release date. - Bump
versioninCargo.toml(and letCargo.lockupdate by building, e.g.cargo check). - Set Android's literal
versionNameand monotonically increasingversionCodeinandroid/app/build.gradle. Confirm both Cargo and Android versions match thevX.Y.Ztag you're about to create. - Run the quality gates (
cargo test,cargo clippy, andcd android && ./gradlew assembleDebug assembleRelease bundleRelease lintDebug lintRelease). - Verify the crate payload:
cargo publish --locked --dry-run. - Commit the release changes (
CHANGELOG.md,Cargo.toml,Cargo.lock,android/app/build.gradle, and the Android changelog entry) and push the commit, confirminggit statusis clean before tagging — a tag records whatever commitHEADpoints to, so uncommitted or unpushed edits are silently left out of the release. - Tag and push:
git tag vX.Y.Z && git push origin vX.Y.Z. - Publish the crate from that clean release commit:
cargo publish --locked. - After the workflow publishes assets, refresh the package manifests
(below) with the new version, URLs, and
SHA256SUMShashes.
The crates.io package is mdo-cli (the mdo crate name was taken); the
installed binary is mdo. Crates.io publishing is authenticated separately
and is not performed by the GitHub Release workflow.
Android release signing
The release workflow can add a signed ARM64 APK and signed Android App Bundle to each GitHub Release. It remains safely disabled until these repository secrets exist:
ANDROID_KEYSTORE_BASE64ANDROID_KEYSTORE_PASSWORDANDROID_KEY_ALIASANDROID_KEY_PASSWORD
After the secrets are configured, set the repository variable
ANDROID_RELEASE_SIGNING_ENABLED to true. The workflow reconstructs the
keystore only in the runner's temporary directory, verifies both signatures,
and publishes mdo-android-arm64.apk and mdo-android-arm64.aab alongside
the desktop archives. Never commit the keystore or its passwords.
Use a long-lived key (at least 25 years), keep an offline backup, and use Play App Signing with this key as the upload key. The APK published on GitHub must keep using the same signing key for Android to accept in-place updates.
Detailed store preparation and the current human-owned steps are in
packaging/google-play/README.md and
packaging/fdroid/README.md.
Package-manager manifests
packaging/ contains starter manifests that install the mdo executable
from GitHub Release assets:
packaging/homebrew/mdo.rb— formula for a Homebrew tappackaging/winget/— WinGet package manifestspackaging/scoop/mdo.json— Scoop bucket manifest
See packaging/README.md
for the currently targeted release and hashes. When cutting a new release,
update the version, URLs, and hashes from that release's SHA256SUMS asset
before submitting to a tap, bucket, or the WinGet repository.
Docs site
The GitHub Pages site is the docs/ directory, deployed by
.github/workflows/pages.yml on every push to main. The workflow builds
mdo, then renders every docs/**/*.md page to HTML with
scripts/build-docs.py using mdo's out-of-the-box settings — so the site
shows the same output users get on their own machines. The one exception is
the homepage docs/index.md, rendered with the --css docs/assets/site.css
override to demo the faux browser window.
Cross-page links in the Markdown sources point at .md files so they keep
working when the sources are browsed on GitHub; scripts/build-docs.py
rewrites relative .md links to .html in the generated pages so they also
resolve on the published site.
Regenerate the pages locally with:
python scripts/build-docs.py
Generated pages are not checked in — they are gitignored and built fresh by
the Pages workflow on every deploy. The only tracked HTML under docs/ is
the hand-written metrics pages (docs/metrics/*.html).
README.html at the repository root is a plain mdo README.md render kept
as an example of default output; scripts/build-docs.py does not touch it.
Regenerate it separately when the README changes, e.g.
cargo run --quiet -- README.md.
Architecture decision records
Design decisions live in docs/adr/:
- ADR 0001 — Rename to mdo
- ADR 0002 — Distribution strategy
- ADR 0003 — Keep Python metrics tooling
- ADR 0004 — State-aware setup launcher
Public metrics
scripts/collect-metrics.py collects passive public metrics (GitHub release
download counts, stars, crates.io downloads) into docs/metrics/, published
at https://maphew.github.io/mdo/metrics/. It runs daily from
.github/workflows/metrics.yml.
The collector writes only aggregate or already-public information. It does not read local user data, runtime mdo output, server logs, IP addresses, user agents, cookies, or unique identifiers — mdo itself has no telemetry. See the metrics privacy note and ADR 0003 for why this tooling is Python.