Mando CLI GitHub Build Mirror
Cross-platform binary build pipeline using GitHub Actions, mirroring source from GitLab.
Architecture
graph LR GL["GitLab<br/>Source"] -->|submodule| GH["GitHub Mirror<br/>wowjeeez/mando_cli_mirror"] GH -->|v* tag| BA["GitHub Actions<br/>8 platform builds"] BA -->|artifacts| GHR["GitHub Release"] BA -->|package registry| GLR["GitLab Release"] GLR -->|glab api| USR["User Install"]
| Component | Location |
|---|---|
| Source | gitlab.com/alpiq_cicd/sales-and-origination/flexible-assets/bess/poc/mando-cli |
| Build mirror | github.com/wowjeeez/mando_cli_mirror |
| Connection | Git submodule via SSH |
Why GitHub?
GitLab CI runners at Alpiq don’t cover macOS/Windows. GitHub Actions provides native runners for all target platforms.
Build Targets
| OS | Architecture | Artifact | Runner |
|---|---|---|---|
| Linux | x86_64 (glibc) | mando-linux-x86_64 | ubuntu-latest |
| Linux | ARM64 (glibc) | mando-linux-aarch64 | ubuntu-latest |
| Linux | x86_64 (musl) | mando-linux-x86_64-musl | ubuntu-latest |
| Linux | ARM64 (musl) | mando-linux-aarch64-musl | ubuntu-latest |
| macOS | x86_64 | mando-macos-x86_64 | macos-latest (cross) |
| macOS | ARM64 | mando-macos-aarch64 | macos-latest |
| Windows | x86_64 | mando-windows-x86_64.exe | windows-latest |
| Windows | ARM64 | mando-windows-aarch64.exe | windows-latest |
macos-13 deprecated
Originally used
macos-13for Intel builds, but runners are scarce and hang. Switched to cross-compilation onmacos-latest(ARM64).
Workflows
ci.yml — PR/Push CI
- Triggers: push/PR to main/master
- Jobs:
cargo check,clippy -D warnings,fmt --check,test
build.yml — Release Builds
- Triggers:
v*tags,workflow_dispatch - 8 parallel build jobs → GitHub Release + GitLab Package Registry
- ARM64 Linux cross-compilation uses
gcc-aarch64-linux-gnulinker
GitLab Release Flow
- Upload binaries to Generic Package Registry (
packages/generic/mando/{tag}/{filename}) - Create/recreate tag on GitLab (handles re-tags)
- Delete existing release if present (handles re-tags)
- Create release with asset links pointing to package registry URLs
Package Registry, not Project Uploads
Project uploads (
POST /uploads) require web session auth — can’t be downloaded via API tokens. Package Registry URLs work with standard API auth viaglab.
GitHub Secrets
| Secret | Purpose |
|---|---|
GITLAB_SSH_KEY | Personal SSH key for submodule clone |
GITLAB_TOKEN | GitLab legacy PAT (api scope) for package uploads + releases |
Install Scripts
Located in scripts/install.sh (bash) and scripts/install.ps1 (PowerShell).
One-liners
Linux/macOS:
glab api "projects/alpiq_cicd%2Fsales-and-origination%2Fflexible-assets%2Fbess%2Fpoc%2Fmando-cli/repository/files/scripts%2Finstall.sh/raw?ref=main" | bashWindows:
glab api "projects/alpiq_cicd%2Fsales-and-origination%2Fflexible-assets%2Fbess%2Fpoc%2Fmando-cli/repository/files/scripts%2Finstall.ps1/raw?ref=main" | iexHow it works
glab apifetches the script from GitLab (handles auth)- Script detects OS + arch
glab apifetches latest release tagglab apidownloads binary from Package Registry → temp file- Moves to install dir (auto
sudoif needed on macOS/Linux)
All output to stderr
Script output goes to stderr for pipe compatibility — stdout is the pipe feeding bash when using
glab api ... | bash.
Defaults
| Platform | Install Dir | Admin Required |
|---|---|---|
| Linux/macOS | /usr/local/bin | sudo (auto-escalated) |
| Windows | %USERPROFILE%\.local\bin | No |
Override with INSTALL_DIR env var.
Submodule Update Workflow
cd mando-cli && git fetch origin && git checkout origin/main
cd .. && git add mando-cli && git commit -m "Update submodule" && git push origin master:mainLocal Dev
tmando zsh alias → /Volumes/bandi/coding/poc/mando-cli/target/release/mando
Key Design Decisions
| Decision | Reason |
|---|---|
| GitHub for builds, GitLab for source | Alpiq runners lack macOS/Windows |
| Package Registry over project uploads | Upload URLs need web session auth, not API-compatible |
glab api for install auth | glab auth status -t exposes different token than what glab uses internally |
| Delete + recreate releases | Handles re-tagged versions cleanly |
macos-latest + cross-compile | macos-13 runners hang waiting for pickup |
Parallel release flow (2026-05)
Restructured .github/workflows/build.yml so binaries publish to GitLab as soon as each target builds, instead of waiting for the slowest matrix job (Windows aarch64) before any GitLab work happens.
Old shape
Single gitlab-release job with needs: build waited on the full matrix, then sequentially: created tag, deleted+recreated release, uploaded all binaries, posted all asset links. Linux users waited on Windows.
New shape — 4 jobs
init-gitlab-release— runs first on tag pushes. Creates GitLab tag (idempotent|| true),DELETEs any existing release for the tag,POSTs a fresh empty release. Acts as upload precondition for the matrix.buildmatrix —needs: init-gitlab-releasewithif: always() && (result == 'success' || result == 'skipped')so non-tagworkflow_dispatchruns still work. Afteractions/upload-artifact, each matrix job doescurl --upload-fileto GitLab Package Registry, thenPOSTs an asset link to/releases/${TAG}/assets/links. Each binary publishes the moment its target finishes — Linux/macOS no longer block on Windows.release(GitHub) — unchanged,needs: build.gitlab-finalize—needs: build. Only computes the aggregatechecksums.txt. Still gated on the full matrix because checksums are logically all-or-nothing; binaries themselves are already live by then.
Design notes
- Concurrent
POSTs to/releases/:tag/assets/linksfrom parallel matrix jobs are safe — each link is an independent record, no race. DELETE+POSTininit-gitlab-releaseis needed for re-tag safety (clean asset-links state before the matrix starts publishing).GITLAB_PROJECTenv var moved to top-level workflowenv(was per-job before).- URL pattern
${API}/packages/generic/mando/${TAG}/${filename}preserved so install scripts in the upstream GitLab repo (scripts/install.sh,scripts/install.ps1) keep working unchanged.
Edge case
No
concurrencygroup on the workflow, so re-pushing a tag while a previous run is still building can produce overlapping API calls into the same release. Pre-existing limitation, not introduced by this restructure.
Related
Local one-off Linux build
This note covers the automated CI pipeline. To build a Linux/WSL binary manually from an Apple Silicon Mac (e.g. ad-hoc for a tester), see mando-cli-wsl-linux-build — it documents the
--platform linux/amd64andpoc/-parent-mount gotchas that CI’s native x86_64 runners never hit.