Skip to content

Commit 5a6b06d

Browse files
committed
Publish rolling edge pre-releases
1 parent 8c8b07d commit 5a6b06d

2 files changed

Lines changed: 291 additions & 8 deletions

File tree

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
name: Publish Edge Pre-Release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
12+
concurrency:
13+
group: edge-pre-release
14+
cancel-in-progress: true
15+
16+
env:
17+
EDGE_TAG: edge
18+
19+
jobs:
20+
build:
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
include:
25+
- os: ubuntu-latest
26+
artifact_name: linux-x64
27+
package_cmd: cargo packager -f deb
28+
- os: ubuntu-24.04-arm
29+
artifact_name: linux-arm64
30+
package_cmd: cargo packager -f deb
31+
- os: windows-latest
32+
artifact_name: windows-x64
33+
package_cmd: cargo packager -f nsis
34+
- os: windows-11-arm
35+
artifact_name: windows-arm64
36+
package_cmd: cargo packager -f nsis
37+
- os: macos-15
38+
artifact_name: macos-arm64
39+
package_cmd: cargo packager -f dmg
40+
- os: macos-15-intel
41+
artifact_name: macos-intel
42+
package_cmd: cargo packager -f dmg
43+
44+
runs-on: ${{ matrix.os }}
45+
name: Build ${{ matrix.artifact_name }}
46+
47+
steps:
48+
- uses: actions/checkout@v4
49+
50+
- name: Sync edge build version
51+
id: sync_version
52+
shell: bash
53+
run: |
54+
if command -v python3 >/dev/null 2>&1; then
55+
PYTHON_BIN=python3
56+
else
57+
PYTHON_BIN=python
58+
fi
59+
base_version=$("$PYTHON_BIN" - <<'PY'
60+
import pathlib
61+
import re
62+
content = pathlib.Path("Cargo.toml").read_text(encoding="utf-8")
63+
match = re.search(r'(?m)^version = "([^"]+)"$', content)
64+
if not match:
65+
raise SystemExit("failed to find Cargo package version")
66+
print(match.group(1))
67+
PY
68+
)
69+
build_serial="$(( GITHUB_RUN_NUMBER % 10000 ))"
70+
RELEASE_VERSION="${base_version}-edge.${GITHUB_RUN_NUMBER}" \
71+
ANDROID_VERSION_SERIAL="${build_serial}" \
72+
"$PYTHON_BIN" ./scripts/ci-sync-version.py
73+
74+
- uses: dtolnay/rust-toolchain@stable
75+
76+
- name: Use crates.io in CI
77+
shell: bash
78+
run: |
79+
mkdir -p .cargo
80+
cat > .cargo/config.toml <<'EOF'
81+
[registries.crates-io]
82+
protocol = "sparse"
83+
84+
[net]
85+
git-fetch-with-cli = true
86+
EOF
87+
88+
- name: Install Linux dependencies
89+
if: runner.os == 'Linux'
90+
run: |
91+
sudo apt-get update
92+
sudo apt-get install -y \
93+
libayatana-appindicator3-dev \
94+
libgtk-3-dev \
95+
libxdo-dev \
96+
libxkbcommon-dev \
97+
libxcb-render0-dev \
98+
libxcb-shape0-dev \
99+
libxcb-xfixes0-dev \
100+
libssl-dev \
101+
pkg-config
102+
103+
- name: Install cargo-packager
104+
run: cargo install cargo-packager --locked
105+
106+
- name: Build binary
107+
run: cargo build --release --locked --bin linuxdo-accelerator
108+
109+
- name: Package app
110+
run: ${{ matrix.package_cmd }}
111+
112+
- name: Upload artifacts
113+
uses: actions/upload-artifact@v4
114+
with:
115+
name: linuxdo-accelerator-${{ steps.sync_version.outputs.package_version }}-${{ matrix.artifact_name }}
116+
path: |
117+
dist/**
118+
target/release/linuxdo-accelerator*
119+
120+
build-android:
121+
strategy:
122+
fail-fast: false
123+
matrix:
124+
include:
125+
- abi: arm64-v8a
126+
rust_target: aarch64-linux-android
127+
artifact_name: android-arm64-v8a
128+
- abi: x86_64
129+
rust_target: x86_64-linux-android
130+
artifact_name: android-x86_64
131+
132+
runs-on: ubuntu-latest
133+
name: Build ${{ matrix.artifact_name }}
134+
135+
steps:
136+
- uses: actions/checkout@v4
137+
138+
- name: Sync edge build version
139+
id: sync_version
140+
shell: bash
141+
run: |
142+
if command -v python3 >/dev/null 2>&1; then
143+
PYTHON_BIN=python3
144+
else
145+
PYTHON_BIN=python
146+
fi
147+
base_version=$("$PYTHON_BIN" - <<'PY'
148+
import pathlib
149+
import re
150+
content = pathlib.Path("Cargo.toml").read_text(encoding="utf-8")
151+
match = re.search(r'(?m)^version = "([^"]+)"$', content)
152+
if not match:
153+
raise SystemExit("failed to find Cargo package version")
154+
print(match.group(1))
155+
PY
156+
)
157+
build_serial="$(( GITHUB_RUN_NUMBER % 10000 ))"
158+
RELEASE_VERSION="${base_version}-edge.${GITHUB_RUN_NUMBER}" \
159+
ANDROID_VERSION_SERIAL="${build_serial}" \
160+
"$PYTHON_BIN" ./scripts/ci-sync-version.py
161+
162+
- uses: actions/setup-java@v4
163+
with:
164+
distribution: temurin
165+
java-version: "17"
166+
167+
- uses: android-actions/setup-android@v3
168+
169+
- uses: gradle/actions/setup-gradle@v4
170+
171+
- uses: dtolnay/rust-toolchain@stable
172+
with:
173+
targets: ${{ matrix.rust_target }}
174+
175+
- name: Use crates.io in CI
176+
shell: bash
177+
run: |
178+
mkdir -p .cargo
179+
cat > .cargo/config.toml <<'EOF'
180+
[registries.crates-io]
181+
protocol = "sparse"
182+
183+
[net]
184+
git-fetch-with-cli = true
185+
EOF
186+
187+
- name: Install Android SDK / NDK
188+
shell: bash
189+
run: |
190+
yes | sdkmanager --licenses > /dev/null || true
191+
sdkmanager --install \
192+
"platform-tools" \
193+
"platforms;android-35" \
194+
"build-tools;35.0.0" \
195+
"ndk;27.2.12479018"
196+
197+
- name: Install cargo-ndk
198+
run: cargo install cargo-ndk --locked
199+
200+
- name: Build Android APK
201+
shell: bash
202+
env:
203+
ANDROID_ABI: ${{ matrix.abi }}
204+
RUST_TARGET: ${{ matrix.rust_target }}
205+
ANDROID_BUILD_TYPE: release
206+
APK_OUTPUT_NAME: linuxdo-accelerator-${{ steps.sync_version.outputs.package_version }}-android-${{ matrix.abi }}.apk
207+
run: |
208+
export ANDROID_NDK_HOME="${ANDROID_SDK_ROOT}/ndk/27.2.12479018"
209+
./scripts/build-android-apk.sh
210+
211+
- name: Upload Android artifacts
212+
uses: actions/upload-artifact@v4
213+
with:
214+
name: linuxdo-accelerator-${{ steps.sync_version.outputs.package_version }}-${{ matrix.artifact_name }}
215+
path: |
216+
android/dist/*.apk
217+
218+
publish-edge-release:
219+
needs:
220+
- build
221+
- build-android
222+
runs-on: ubuntu-latest
223+
name: Publish Edge Pre-Release
224+
225+
steps:
226+
- uses: actions/checkout@v4
227+
with:
228+
fetch-depth: 0
229+
230+
- name: Download packaged artifacts
231+
uses: actions/download-artifact@v4
232+
with:
233+
pattern: linuxdo-accelerator-*
234+
path: release-artifacts
235+
merge-multiple: false
236+
237+
- name: List release files
238+
run: find release-artifacts -type f | sort
239+
240+
- name: Replace edge tag and pre-release
241+
env:
242+
GITHUB_TOKEN: ${{ github.token }}
243+
shell: bash
244+
run: |
245+
if gh release view "${EDGE_TAG}" >/dev/null 2>&1; then
246+
gh release delete "${EDGE_TAG}" -y --cleanup-tag
247+
fi
248+
249+
git push -f origin "${GITHUB_SHA}:refs/tags/${EDGE_TAG}"
250+
251+
short_sha="$(git rev-parse --short "${GITHUB_SHA}")"
252+
notes_file="$(mktemp)"
253+
cat > "${notes_file}" <<EOF
254+
Auto-updated from main.
255+
256+
Commit: ${short_sha}
257+
Run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}
258+
EOF
259+
mapfile -t release_files < <(find release-artifacts -type f | sort)
260+
if [[ "${#release_files[@]}" -eq 0 ]]; then
261+
echo "no release files found" >&2
262+
exit 1
263+
fi
264+
gh release create "${EDGE_TAG}" \
265+
--prerelease \
266+
--title "Edge Pre-Release" \
267+
--notes-file "${notes_file}" \
268+
"${release_files[@]}"

scripts/ci-sync-version.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,39 @@ def replace_once(path: pathlib.Path, pattern: str, replacement: str) -> None:
1414

1515

1616
def main() -> int:
17+
explicit_version = (os.environ.get("RELEASE_VERSION") or "").strip()
1718
raw_tag = (
1819
os.environ.get("LINUXDO_RELEASE_TAG")
1920
or os.environ.get("RELEASE_TAG")
2021
or os.environ.get("GITHUB_REF_NAME")
2122
or ""
2223
).strip()
23-
if not raw_tag:
24-
raise SystemExit("missing release tag; set RELEASE_TAG or run this workflow from a tag ref")
25-
if not raw_tag.startswith("v"):
26-
raise SystemExit(f"release tag must start with 'v': {raw_tag}")
24+
if explicit_version:
25+
package_version = explicit_version
26+
else:
27+
if not raw_tag:
28+
raise SystemExit(
29+
"missing release tag or release version; set RELEASE_TAG/RELEASE_VERSION or run this workflow from a tag ref"
30+
)
31+
if not raw_tag.startswith("v"):
32+
raise SystemExit(f"release tag must start with 'v': {raw_tag}")
33+
package_version = raw_tag[1:]
2734

28-
package_version = raw_tag[1:]
2935
match = re.fullmatch(r"(\d+)\.(\d+)\.(\d+)(?:[-+][0-9A-Za-z.-]+)?", package_version)
3036
if not match:
31-
raise SystemExit(f"unsupported release tag format: {raw_tag}")
37+
raise SystemExit(f"unsupported release version format: {package_version}")
3238

3339
major, minor, patch = (int(part) for part in match.groups())
34-
android_version_code = (major * 1_000_000) + (minor * 1_000) + patch
40+
build_serial_raw = (os.environ.get("ANDROID_VERSION_SERIAL") or "").strip()
41+
if build_serial_raw:
42+
build_serial = int(build_serial_raw)
43+
if build_serial < 0 or build_serial > 9999:
44+
raise SystemExit("ANDROID_VERSION_SERIAL must be between 0 and 9999")
45+
android_version_code = (
46+
(major * 100_000_000) + (minor * 1_000_000) + (patch * 10_000) + build_serial
47+
)
48+
else:
49+
android_version_code = (major * 1_000_000) + (minor * 1_000) + patch
3550

3651
repo_root = pathlib.Path(
3752
os.environ.get("REPO_ROOT", pathlib.Path(__file__).resolve().parents[1])
@@ -65,7 +80,7 @@ def main() -> int:
6580
handle.write(f"package_version={package_version}\n")
6681
handle.write(f"android_version_code={android_version_code}\n")
6782

68-
print(f"release tag: {raw_tag}")
83+
print(f"release tag: {raw_tag or '(not set)'}")
6984
print(f"package version: {package_version}")
7085
print(f"android versionCode: {android_version_code}")
7186
return 0

0 commit comments

Comments
 (0)