mirror of
https://github.com/therealaleph/MasterHttpRelayVPN-RUST.git
synced 2026-05-18 05:44:35 +03:00
af44abbcd3
v1.2.4 tagged cleanly but its CI failed — parallel Linux matrix jobs
on the self-hosted runners all raced on `/var/lib/apt/lists/lock` and
failed the `sudo apt-get install` step within ~20s. v1.2.4's release
job therefore skipped and no assets were published.
Fix:
- Pre-installed every apt dependency the workflow needs on both
self-hosted runners (eframe system libs, gcc-aarch64-linux-gnu,
gcc-arm-linux-gnueabihf).
- Seeded per-runner cargo linker configs at
/home/ghrunner/cargo-{01,02}/config.toml so the "echo
[target.xxx] linker = ..." workflow step is also unnecessary.
- Gated the "Install Linux eframe system deps" and the two cross-
compile-toolchain steps on `runner.environment == 'github-hosted'`
so only hosted runners call apt-get; self-hosted runners skip the
whole thing and use pre-installed tooling.
Re-tagging as v1.2.5 since v1.2.4 is an abandoned tag (git tag exists
but no GitHub Release was cut for it).
Same code changes as what v1.2.4 was meant to ship: PR #78 range-
parallel validation, PR #79 port-collision rejection, README note
on Android 7+ user-CA trust.
492 lines
22 KiB
YAML
492 lines
22 KiB
YAML
name: release
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- 'v*'
|
||
|
||
permissions:
|
||
contents: write
|
||
|
||
# Runner strategy:
|
||
# - Linux + Android + mipsel: self-hosted (mhrv-hetzner-*, Hetzner
|
||
# 8-core / 31 GB Ubuntu 24.04 box with
|
||
# Rust, Android SDK+NDK, Docker, all
|
||
# cross-compile toolchains pre-installed).
|
||
# Two runners registered for parallelism.
|
||
# - macOS arm64 + amd64, Windows: GitHub-hosted (we don't self-host those
|
||
# OSes; the free minutes on a public repo
|
||
# are plenty for those two platforms).
|
||
#
|
||
# Why self-hosted: GH-hosted 2-core runners were spending ~13 min cold per
|
||
# release; on the Hetzner box a cold linux-amd64 build is 1m9s, and warm
|
||
# builds with Swatinem/rust-cache are sub-minute. Keeps the toolchain warm,
|
||
# and more importantly keeps target/ warm via the rust-cache action.
|
||
|
||
jobs:
|
||
build:
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
include:
|
||
# Pin to Ubuntu 22.04 GLIBC target (GLIBC 2.35) so the glibc builds
|
||
# load on any distro ≥ Ubuntu 22.04 / Debian 12 / Mint 21 / Fedora 36.
|
||
# On self-hosted this is a Rust-side choice (cargo target triple),
|
||
# not an OS-of-the-runner choice — the runner itself is Ubuntu 24.04
|
||
# (GLIBC 2.39), but we link against the 2.35-era glibc via the
|
||
# x86_64-unknown-linux-gnu target triple which pins to the oldest
|
||
# GLIBC symbol version rustc is willing to emit. Users behind tight
|
||
# internet who can't dist-upgrade keep working.
|
||
- target: x86_64-unknown-linux-gnu
|
||
os: [self-hosted, linux, x64, mhrv-build]
|
||
name: mhrv-rs-linux-amd64
|
||
- target: aarch64-unknown-linux-gnu
|
||
os: [self-hosted, linux, x64, mhrv-build]
|
||
name: mhrv-rs-linux-arm64
|
||
- target: arm-unknown-linux-gnueabihf
|
||
os: [self-hosted, linux, x64, mhrv-build]
|
||
name: mhrv-rs-raspbian-armhf
|
||
- target: x86_64-apple-darwin
|
||
os: macos-latest
|
||
name: mhrv-rs-macos-amd64
|
||
- target: aarch64-apple-darwin
|
||
os: macos-latest
|
||
name: mhrv-rs-macos-arm64
|
||
- target: x86_64-pc-windows-gnu
|
||
os: windows-latest
|
||
name: mhrv-rs-windows-amd64
|
||
- target: x86_64-unknown-linux-musl
|
||
os: [self-hosted, linux, x64, mhrv-build]
|
||
name: mhrv-rs-linux-musl-amd64
|
||
- target: aarch64-unknown-linux-musl
|
||
os: [self-hosted, linux, x64, mhrv-build]
|
||
name: mhrv-rs-linux-musl-arm64
|
||
# OpenWRT MT7621 (soft-float mipsel 32-bit). Dozens of cheap
|
||
# home routers run this chipset and they *specifically* need
|
||
# the soft-float variant — MT7621 has no hardware FPU and a
|
||
# hard-float binary segfaults on the first fp op. Tier-3 in
|
||
# Rust since 1.72; we build it via messense's musl-cross
|
||
# docker image which still has a mipsel-softfloat toolchain.
|
||
# `continue-on-error: true` so a regression here doesn't block
|
||
# the rest of the release. Issue #26.
|
||
- target: mipsel-unknown-linux-musl
|
||
os: [self-hosted, linux, x64, mhrv-build]
|
||
name: mhrv-rs-openwrt-mipsel-softfloat
|
||
mipsel_softfloat: true
|
||
|
||
runs-on: ${{ matrix.os }}
|
||
# mipsel-softfloat is best-effort: the Rust tier-3 target occasionally
|
||
# regresses. Letting it fail keeps the main release going so
|
||
# desktop/Android users aren't blocked by MT7621 router support.
|
||
continue-on-error: ${{ matrix.mipsel_softfloat == true }}
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
# Skip the host-level rustup install for mipsel-softfloat — that
|
||
# target is tier-3 in stable Rust (no prebuilt stdlib available
|
||
# via rustup), and the docker image we use for this build ships
|
||
# its own Rust toolchain + std. Trying to pass
|
||
# `targets: mipsel-unknown-linux-musl` to dtolnay/rust-toolchain
|
||
# errors out with "error: component 'rust-std' for target
|
||
# 'mipsel-unknown-linux-musl' is unavailable for download", which
|
||
# fails the job before the docker step ever runs.
|
||
#
|
||
# On self-hosted this action is mostly a no-op: rustup is already
|
||
# installed and the standard target triples are pre-added. It
|
||
# still verifies the target is present and is cheap enough to keep
|
||
# as a safety net.
|
||
- uses: dtolnay/rust-toolchain@stable
|
||
if: matrix.mipsel_softfloat != true
|
||
with:
|
||
targets: ${{ matrix.target }}
|
||
|
||
# Cache target/ + cargo registry across runs — this is the big
|
||
# self-hosted speedup. Without it, actions/checkout@v4's default
|
||
# `git clean -ffdx` wipes target/ between runs and every build is
|
||
# cold. With it, warm builds are sub-minute even for the full
|
||
# release profile.
|
||
- uses: Swatinem/rust-cache@v2
|
||
if: matrix.mipsel_softfloat != true
|
||
with:
|
||
key: ${{ matrix.target }}
|
||
|
||
# eframe needs a few system libs on Linux for window management, keyboard,
|
||
# and OpenGL/X11/Wayland. Gated to GitHub-hosted runners only — the
|
||
# self-hosted runners pre-install all of these once at setup time, and
|
||
# letting multiple parallel matrix jobs race on `sudo apt-get install`
|
||
# fights over /var/lib/apt/lists/lock and fails them all.
|
||
- name: Install Linux eframe system deps
|
||
if: runner.os == 'Linux' && runner.environment == 'github-hosted'
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y \
|
||
libxkbcommon-dev \
|
||
libwayland-dev \
|
||
libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
|
||
libx11-dev \
|
||
libgl1-mesa-dev libglib2.0-dev libgtk-3-dev
|
||
|
||
# Cross-compile toolchains. Same story as above — gated to hosted
|
||
# runners; self-hosted has gcc-aarch64-linux-gnu + gcc-arm-linux-gnueabihf
|
||
# pre-installed, and the linker entries live in
|
||
# /home/ghrunner/cargo-{01,02}/config.toml (seeded once at runner
|
||
# setup time, picked up via CARGO_HOME env).
|
||
- name: Install aarch64 cross-compile toolchain (Linux only)
|
||
if: matrix.target == 'aarch64-unknown-linux-gnu' && runner.environment == 'github-hosted'
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y gcc-aarch64-linux-gnu
|
||
echo '[target.aarch64-unknown-linux-gnu]' >> ~/.cargo/config.toml
|
||
echo 'linker = "aarch64-linux-gnu-gcc"' >> ~/.cargo/config.toml
|
||
|
||
- name: Install armhf cross-compile toolchain (Linux only)
|
||
if: matrix.target == 'arm-unknown-linux-gnueabihf' && runner.environment == 'github-hosted'
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y gcc-arm-linux-gnueabihf
|
||
echo '[target.arm-unknown-linux-gnueabihf]' >> ~/.cargo/config.toml
|
||
echo 'linker = "arm-linux-gnueabihf-gcc"' >> ~/.cargo/config.toml
|
||
|
||
- name: Install Windows MinGW toolchain
|
||
if: matrix.target == 'x86_64-pc-windows-gnu'
|
||
id: msys2
|
||
uses: msys2/setup-msys2@v2
|
||
with:
|
||
msystem: MINGW64
|
||
update: true
|
||
install: mingw-w64-x86_64-gcc
|
||
|
||
- name: Configure Windows GNU linker
|
||
if: matrix.target == 'x86_64-pc-windows-gnu'
|
||
shell: pwsh
|
||
run: |
|
||
$gcc = "${{ steps.msys2.outputs.msys2-location }}\mingw64\bin\gcc.exe" -replace '\\','/'
|
||
New-Item -ItemType Directory -Force -Path $env:USERPROFILE/.cargo | Out-Null
|
||
Add-Content -Path $env:USERPROFILE/.cargo/config.toml -Value '[target.x86_64-pc-windows-gnu]'
|
||
Add-Content -Path $env:USERPROFILE/.cargo/config.toml -Value "linker = '$gcc'"
|
||
|
||
- name: Build CLI
|
||
if: "!endsWith(matrix.target, '-linux-musl')"
|
||
run: cargo build --release --target ${{ matrix.target }} --bin mhrv-rs
|
||
|
||
# Fully-static musl builds for OpenWRT / Alpine / libc-less systems.
|
||
# messense/rust-musl-cross ships a pre-built musl toolchain so `ring`
|
||
# (rustls' crypto backend) cross-compiles cleanly on both archs.
|
||
- name: Build CLI (musl via docker)
|
||
if: matrix.target == 'x86_64-unknown-linux-musl'
|
||
run: |
|
||
docker run --rm -v "$PWD":/src -w /src \
|
||
messense/rust-musl-cross:x86_64-musl \
|
||
cargo build --release --target x86_64-unknown-linux-musl --bin mhrv-rs
|
||
sudo chown -R "$(id -u):$(id -g)" target
|
||
|
||
- name: Build CLI (musl via docker, arm64)
|
||
if: matrix.target == 'aarch64-unknown-linux-musl'
|
||
run: |
|
||
docker run --rm -v "$PWD":/src -w /src \
|
||
messense/rust-musl-cross:aarch64-musl \
|
||
cargo build --release --target aarch64-unknown-linux-musl --bin mhrv-rs
|
||
sudo chown -R "$(id -u):$(id -g)" target
|
||
|
||
# OpenWRT MT7621 / mipsel-softfloat. messense doesn't publish a
|
||
# `:mipsel-musl-softfloat` tag — the mipsel-musl image is
|
||
# hardfloat. We build soft-float anyway via
|
||
# `RUSTFLAGS=-C target-feature=+soft-float` + `-Z build-std` so
|
||
# libstd itself is recompiled to emit soft-float code. The
|
||
# gcc/musl shipping in the image is hardfloat but we never link
|
||
# anything more than libc (`ring` is pure asm for the crypto
|
||
# that matters), so musl's lack of softfloat libm doesn't bite.
|
||
# Requires nightly Rust since mipsel is Rust tier 3 in the
|
||
# stable channel — no prebuilt std.
|
||
- name: Build CLI (mipsel-softfloat via docker)
|
||
if: matrix.target == 'mipsel-unknown-linux-musl' && matrix.mipsel_softfloat == true
|
||
# The inner script is single-quoted so the `#` lines stay as
|
||
# real comments. An earlier version of this step used
|
||
# `sh -c "... \` (backslash-continuation inside a
|
||
# double-quoted YAML folded string) which collapsed into one
|
||
# line — the first `#` then commented out everything after it,
|
||
# reducing the whole docker payload to `set -eux;` and failing
|
||
# silently at the post-docker chown. Heredoc-style single
|
||
# quotes preserve newlines verbatim; no comment collapse.
|
||
run: |
|
||
docker run --rm -v "$PWD":/src -w /src \
|
||
-e RUSTFLAGS='-C target-feature=+soft-float' \
|
||
messense/rust-musl-cross:mipsel-musl \
|
||
bash -c '
|
||
set -eux
|
||
# The image ships a pre-installed nightly that rustup
|
||
# cannot upgrade in place — `clippy-preview/share/doc/clippy/README.md`
|
||
# is missing from the pre-bake, and rustup errors with
|
||
# "failure removing component clippy-preview". Nuke it
|
||
# first, then install fresh.
|
||
rustup toolchain uninstall nightly 2>/dev/null || true
|
||
rustup toolchain install nightly --profile minimal
|
||
rustup component add rust-src --toolchain nightly
|
||
cargo +nightly build --release \
|
||
-Z build-std=std,panic_abort \
|
||
--target mipsel-unknown-linux-musl \
|
||
--bin mhrv-rs
|
||
'
|
||
sudo chown -R "$(id -u):$(id -g)" target
|
||
|
||
# UI build: we try to build the UI binary on every platform. If it fails
|
||
# on cross-compile for linux-arm64 (missing arm64 system libs cross),
|
||
# we still ship the CLI. We also skip the UI on musl targets (OpenWRT etc.
|
||
# are headless, bundling X11 makes no sense).
|
||
- name: Build UI
|
||
if: matrix.target != 'aarch64-unknown-linux-gnu' && matrix.target != 'arm-unknown-linux-gnueabihf' && !endsWith(matrix.target, '-linux-musl')
|
||
run: cargo build --release --target ${{ matrix.target }} --features ui --bin mhrv-rs-ui
|
||
|
||
- name: Package (unix)
|
||
if: runner.os != 'Windows'
|
||
run: |
|
||
mkdir -p dist
|
||
cp target/${{ matrix.target }}/release/mhrv-rs dist/mhrv-rs
|
||
chmod +x dist/mhrv-rs
|
||
if [ -f target/${{ matrix.target }}/release/mhrv-rs-ui ]; then
|
||
cp target/${{ matrix.target }}/release/mhrv-rs-ui dist/mhrv-rs-ui
|
||
chmod +x dist/mhrv-rs-ui
|
||
fi
|
||
# OpenWRT / musl archives get the procd init script instead of run.sh,
|
||
# since routers don't have a CA to install and run headless via procd.
|
||
case "${{ matrix.target }}" in
|
||
*-linux-musl)
|
||
cp assets/openwrt/mhrv-rs.init dist/mhrv-rs.init
|
||
chmod +x dist/mhrv-rs.init
|
||
;;
|
||
*)
|
||
cp assets/launchers/run.sh dist/run.sh
|
||
chmod +x dist/run.sh
|
||
if [ "${{ runner.os }}" = "macOS" ]; then
|
||
cp assets/launchers/run.command dist/run.command
|
||
chmod +x dist/run.command
|
||
fi
|
||
;;
|
||
esac
|
||
|
||
- name: Build macOS .app bundle
|
||
if: runner.os == 'macOS'
|
||
run: |
|
||
VER="${GITHUB_REF#refs/tags/v}"
|
||
./assets/macos/build-app.sh dist/mhrv-rs-ui "$VER" dist
|
||
# Make a clean zip of just the .app for the release
|
||
cd dist
|
||
zip -qry "${{ matrix.name }}-app.zip" mhrv-rs.app
|
||
|
||
- name: Package (windows)
|
||
if: runner.os == 'Windows'
|
||
shell: pwsh
|
||
run: |
|
||
New-Item -ItemType Directory -Force -Path dist | Out-Null
|
||
Copy-Item target/${{ matrix.target }}/release/mhrv-rs.exe dist/mhrv-rs.exe
|
||
if (Test-Path target/${{ matrix.target }}/release/mhrv-rs-ui.exe) {
|
||
Copy-Item target/${{ matrix.target }}/release/mhrv-rs-ui.exe dist/mhrv-rs-ui.exe
|
||
}
|
||
Copy-Item assets/launchers/run.bat dist/run.bat
|
||
|
||
- name: Make archive
|
||
shell: bash
|
||
run: |
|
||
cd dist
|
||
case "${{ matrix.target }}" in
|
||
*-pc-windows-*)
|
||
7z a -tzip "${{ matrix.name }}.zip" mhrv-rs.exe mhrv-rs-ui.exe run.bat
|
||
;;
|
||
*-apple-darwin)
|
||
tar czf "${{ matrix.name }}.tar.gz" mhrv-rs mhrv-rs-ui run.sh run.command
|
||
;;
|
||
*-linux-musl)
|
||
tar czf "${{ matrix.name }}.tar.gz" mhrv-rs mhrv-rs.init
|
||
;;
|
||
*)
|
||
tar czf "${{ matrix.name }}.tar.gz" mhrv-rs mhrv-rs-ui run.sh 2>/dev/null || tar czf "${{ matrix.name }}.tar.gz" mhrv-rs run.sh
|
||
;;
|
||
esac
|
||
|
||
- uses: actions/upload-artifact@v4
|
||
with:
|
||
name: ${{ matrix.name }}
|
||
path: |
|
||
dist/${{ matrix.name }}.tar.gz
|
||
dist/${{ matrix.name }}.zip
|
||
dist/${{ matrix.name }}-app.zip
|
||
if-no-files-found: ignore
|
||
|
||
# Android build — separate job so it doesn't inflate the matrix. The
|
||
# Rust side here cross-compiles to FOUR ABIs (arm64-v8a, armeabi-v7a,
|
||
# x86_64, x86) via cargo-ndk and drops the .so files into the Gradle
|
||
# project's jniLibs/ tree, which then packages them into a single
|
||
# universal APK. Users pick it once, no per-ABI split.
|
||
#
|
||
# Runs on self-hosted. The runner has Android SDK + NDK r26c + cargo-ndk
|
||
# pre-installed under /opt/android-sdk; the env block below points Gradle
|
||
# at those paths so we don't re-download ~1 GB of SDK per release.
|
||
android:
|
||
runs-on: [self-hosted, linux, x64, mhrv-build]
|
||
env:
|
||
ANDROID_SDK_ROOT: /opt/android-sdk
|
||
ANDROID_HOME: /opt/android-sdk
|
||
ANDROID_NDK_HOME: /opt/android-sdk/ndk/26.2.11394342
|
||
ANDROID_NDK_ROOT: /opt/android-sdk/ndk/26.2.11394342
|
||
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
# Rust toolchain: idempotent on self-hosted (targets already present),
|
||
# kept here so the workflow still works if we ever run it on a GH-hosted
|
||
# fallback.
|
||
- uses: dtolnay/rust-toolchain@stable
|
||
with:
|
||
targets: aarch64-linux-android,armv7-linux-androideabi,x86_64-linux-android,i686-linux-android
|
||
|
||
# Cache cargo + target/ across Android release builds. Four cargo-ndk
|
||
# release builds back-to-back with LTO is where the cold cost comes
|
||
# from; rust-cache brings warm runs down to ~3–4 min from ~9 min cold.
|
||
- uses: Swatinem/rust-cache@v2
|
||
with:
|
||
key: android-universal
|
||
# cargo-ndk writes into `target/<android-triple>/release/`, all
|
||
# four of which we want to cache.
|
||
workspaces: |
|
||
. -> target
|
||
|
||
# `./gradlew :app:assembleRelease` triggers cargoBuildRelease first
|
||
# which invokes cargo-ndk with all four targets, then Gradle packages
|
||
# the APK (release buildType signed with the committed release.jks —
|
||
# see android/app/build.gradle.kts comment explaining why).
|
||
- name: Build release APK
|
||
working-directory: android
|
||
run: |
|
||
chmod +x ./gradlew
|
||
./gradlew :app:assembleRelease --no-daemon --stacktrace
|
||
|
||
- name: Rename APK with version
|
||
working-directory: android
|
||
run: |
|
||
VER="${GITHUB_REF#refs/tags/v}"
|
||
SRC="app/build/outputs/apk/release/app-release.apk"
|
||
if [ ! -f "$SRC" ]; then
|
||
# Some AGP versions name it differently when the release config
|
||
# can't be auto-signed. Catch that up front with a clear error
|
||
# instead of a silent missing-artifact later.
|
||
echo "::error::expected $SRC to exist; actual outputs:"
|
||
find app/build/outputs/apk -type f -name '*.apk' -print
|
||
exit 1
|
||
fi
|
||
mkdir -p ../dist
|
||
cp "$SRC" "../dist/mhrv-rs-android-universal-v${VER}.apk"
|
||
|
||
- uses: actions/upload-artifact@v4
|
||
with:
|
||
name: mhrv-rs-android-universal
|
||
path: dist/*.apk
|
||
if-no-files-found: error
|
||
|
||
# release + telegram: lightweight aggregation jobs kept on GH-hosted
|
||
# ubuntu-latest. They only download artifacts and call APIs — no build
|
||
# tooling needed, no benefit from moving to self-hosted, and keeping them
|
||
# off the self-hosted runners avoids contention with Linux build jobs from
|
||
# the next tag if two releases overlap.
|
||
release:
|
||
needs: [build, android]
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: write
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- uses: actions/download-artifact@v4
|
||
with:
|
||
path: dist
|
||
merge-multiple: true
|
||
|
||
- name: Release
|
||
uses: softprops/action-gh-release@v2
|
||
with:
|
||
files: dist/*
|
||
generate_release_notes: true
|
||
|
||
# Notify the Persian-speaking Telegram channel with the CI-built
|
||
# Android APK + its sha256 + the per-version changelog from
|
||
# `docs/changelog/v<tag>.md`.
|
||
#
|
||
# Two Telegram API calls:
|
||
# 1. sendDocument — APK file + a short caption (Telegram caps
|
||
# captions at 1024 chars, and we have bigger changelogs than
|
||
# that).
|
||
# 2. sendMessage — full changelog as a reply to #1, Persian
|
||
# quote-block first then English, same pattern as the
|
||
# previous manual post. No emojis, as the user asked.
|
||
#
|
||
# Needs two repo secrets:
|
||
# TELEGRAM_BOT_TOKEN — bot the channel admits as poster
|
||
# TELEGRAM_CHAT_ID — numeric chat id (starts with -100...)
|
||
# Missing either => the whole job is skipped (not failed) so a
|
||
# forker who hasn't set up a Telegram channel gets a clean release.
|
||
telegram:
|
||
needs: [android, release]
|
||
runs-on: ubuntu-latest
|
||
# Gated on the repo variable `TELEGRAM_NOTIFY_ENABLED`. Default is
|
||
# OFF — the job skips silently unless the variable is set to the
|
||
# literal string "true". Toggle via:
|
||
#
|
||
# gh variable set TELEGRAM_NOTIFY_ENABLED --body true
|
||
# gh variable set TELEGRAM_NOTIFY_ENABLED --body false
|
||
#
|
||
# Keeping the machinery (script + secrets) in place so flipping
|
||
# the switch back on is a one-liner, not a workflow edit.
|
||
if: ${{ vars.TELEGRAM_NOTIFY_ENABLED == 'true' && needs.android.result == 'success' }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- uses: actions/download-artifact@v4
|
||
with:
|
||
name: mhrv-rs-android-universal
|
||
path: apk
|
||
|
||
- name: Post to Telegram
|
||
env:
|
||
BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||
CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||
INCLUDE_CHANGELOG: ${{ vars.TELEGRAM_INCLUDE_CHANGELOG }}
|
||
# Python over curl/bash so we don't have to fight curl's -F
|
||
# value-interpretation rules. curl treats `-F "caption=<..."`
|
||
# as "read the caption from file named ..." when the value
|
||
# starts with `<`, which matches our `<b>` HTML-bold tags and
|
||
# silently turns the whole job into a "file not found" exit
|
||
# 26. Python stdlib has no such wart.
|
||
run: |
|
||
set -euo pipefail
|
||
VER="${GITHUB_REF#refs/tags/v}"
|
||
APK="apk/mhrv-rs-android-universal-v${VER}.apk"
|
||
|
||
if [ -z "${BOT_TOKEN:-}" ] || [ -z "${CHAT_ID:-}" ]; then
|
||
echo "::notice::TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID not set, skipping Telegram post"
|
||
exit 0
|
||
fi
|
||
|
||
if [ ! -f "$APK" ]; then
|
||
echo "::error::expected $APK to exist; got:"
|
||
ls -la apk/
|
||
exit 1
|
||
fi
|
||
|
||
# --with-changelog is opt-in. Default post is just the APK
|
||
# plus a short caption with the SHA-256, repo URL, and release
|
||
# URL — no long body. To include the Persian/English bullets
|
||
# for a specific tag, set the repo variable
|
||
# TELEGRAM_INCLUDE_CHANGELOG=true before pushing that tag.
|
||
INCLUDE_CHANGELOG_FLAG=""
|
||
if [ "${INCLUDE_CHANGELOG:-}" = "true" ]; then
|
||
INCLUDE_CHANGELOG_FLAG="--with-changelog"
|
||
fi
|
||
python3 .github/scripts/telegram_release_notify.py \
|
||
--apk "$APK" \
|
||
--version "$VER" \
|
||
--repo "$GITHUB_REPOSITORY" \
|
||
--changelog "docs/changelog/v${VER}.md" \
|
||
$INCLUDE_CHANGELOG_FLAG
|