Skip to content

Commit c0a61f7

Browse files
committed
chore: github action ci
1 parent 0cd147b commit c0a61f7

2 files changed

Lines changed: 294 additions & 1 deletion

File tree

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
name: Build Release And Upload To Telegram
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version_name:
7+
description: "Override output file version name, for example 1.0.1"
8+
required: false
9+
type: string
10+
send_to_telegram:
11+
description: "Upload release APKs to Telegram"
12+
required: true
13+
default: true
14+
type: boolean
15+
push:
16+
branches:
17+
- "**"
18+
tags:
19+
- "v*"
20+
21+
permissions:
22+
contents: read
23+
24+
jobs:
25+
build-release:
26+
runs-on: ubuntu-latest
27+
env:
28+
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
29+
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
30+
TELEGRAM_MESSAGE_THREAD_ID: ${{ secrets.TELEGRAM_MESSAGE_THREAD_ID }}
31+
TELEGRAM_MAX_DOCUMENT_BYTES: ${{ vars.TELEGRAM_MAX_DOCUMENT_BYTES }}
32+
RELEASE_KEYSTORE_BASE64: ${{ secrets.RELEASE_KEYSTORE_BASE64 }}
33+
RELEASE_KEYSTORE_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_PASSWORD }}
34+
RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
35+
RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
36+
SEND_TO_TELEGRAM: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.send_to_telegram == 'true' }}
37+
REQUESTED_VERSION_NAME: ${{ github.event.inputs.version_name }}
38+
39+
steps:
40+
- name: Checkout
41+
uses: actions/checkout@v4
42+
with:
43+
fetch-depth: 0
44+
45+
- name: Make Gradle wrapper executable
46+
run: chmod +x ./gradlew
47+
48+
- name: Set up JDK
49+
uses: actions/setup-java@v4
50+
with:
51+
distribution: temurin
52+
java-version: "25"
53+
54+
- name: Set up Gradle
55+
uses: gradle/actions/setup-gradle@v4
56+
57+
- name: Set up Android SDK
58+
uses: android-actions/setup-android@v3
59+
60+
- name: Install Android SDK packages
61+
shell: bash
62+
run: |
63+
set -euo pipefail
64+
65+
set +o pipefail
66+
yes | sdkmanager --licenses >/dev/null
67+
licenses_status="${PIPESTATUS[1]}"
68+
set -o pipefail
69+
if [ "$licenses_status" -ne 0 ]; then
70+
echo "::error::Failed to accept Android SDK licenses."
71+
exit "$licenses_status"
72+
fi
73+
74+
build_tools_package="$(sdkmanager --list | awk '$1 ~ /^build-tools;[0-9]/ { print $1 }' | sort -V | tail -n 1)"
75+
ndk_package="$(sdkmanager --list | awk '$1 ~ /^ndk;[0-9]/ { print $1 }' | sort -V | tail -n 1)"
76+
77+
if [ -z "$build_tools_package" ]; then
78+
echo "::error::No Android build-tools package is available from sdkmanager."
79+
exit 1
80+
fi
81+
if [ -z "$ndk_package" ]; then
82+
echo "::error::No Android NDK package is available from sdkmanager."
83+
exit 1
84+
fi
85+
86+
sdkmanager --install "platforms;android-37.0" "$build_tools_package" "$ndk_package"
87+
88+
ndk_version="${ndk_package#ndk;}"
89+
echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/$ndk_version" >> "$GITHUB_ENV"
90+
echo "ANDROID_NDK_ROOT=$ANDROID_HOME/ndk/$ndk_version" >> "$GITHUB_ENV"
91+
92+
- name: Validate signing secrets
93+
shell: bash
94+
run: |
95+
set -euo pipefail
96+
if [ -z "${RELEASE_KEYSTORE_BASE64:-}" ]; then
97+
echo "::error::Missing repository secret RELEASE_KEYSTORE_BASE64."
98+
exit 1
99+
fi
100+
if [ -z "${RELEASE_KEYSTORE_PASSWORD:-}" ]; then
101+
echo "::error::Missing repository secret RELEASE_KEYSTORE_PASSWORD."
102+
exit 1
103+
fi
104+
if [ -z "${RELEASE_KEY_ALIAS:-}" ]; then
105+
echo "::error::Missing repository secret RELEASE_KEY_ALIAS."
106+
exit 1
107+
fi
108+
109+
- name: Build release APKs
110+
run: ./gradlew --no-daemon :app:assembleRelease
111+
112+
- name: Sign release APKs
113+
shell: bash
114+
run: |
115+
set -euo pipefail
116+
117+
keystore_path="$RUNNER_TEMP/release.keystore"
118+
printf '%s' "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "$keystore_path"
119+
120+
key_password="${RELEASE_KEY_PASSWORD:-$RELEASE_KEYSTORE_PASSWORD}"
121+
export RELEASE_KEYSTORE_PASSWORD
122+
export RELEASE_KEY_PASSWORD="$key_password"
123+
124+
zipalign="$(find "$ANDROID_HOME/build-tools" -type f -name zipalign | sort -V | tail -n 1)"
125+
apksigner="$(find "$ANDROID_HOME/build-tools" -type f -name apksigner | sort -V | tail -n 1)"
126+
127+
if [ -z "$zipalign" ]; then
128+
echo "::error::zipalign was not found in Android build-tools."
129+
exit 1
130+
fi
131+
if [ -z "$apksigner" ]; then
132+
echo "::error::apksigner was not found in Android build-tools."
133+
exit 1
134+
fi
135+
136+
mkdir -p signed-apks
137+
shopt -s nullglob
138+
for apk in app/build/outputs/apk/release/*.apk; do
139+
base_name="$(basename "$apk" .apk)"
140+
aligned_apk="$RUNNER_TEMP/${base_name}-aligned.apk"
141+
signed_apk="signed-apks/${base_name}-signed.apk"
142+
143+
"$zipalign" -p -f 4 "$apk" "$aligned_apk"
144+
"$apksigner" sign \
145+
--ks "$keystore_path" \
146+
--ks-pass env:RELEASE_KEYSTORE_PASSWORD \
147+
--ks-key-alias "$RELEASE_KEY_ALIAS" \
148+
--key-pass env:RELEASE_KEY_PASSWORD \
149+
--out "$signed_apk" \
150+
"$aligned_apk"
151+
"$apksigner" verify --verbose "$signed_apk"
152+
done
153+
154+
if ! find signed-apks -type f -name "*.apk" | grep -q .; then
155+
echo "::error::No signed release APKs were produced."
156+
exit 1
157+
fi
158+
159+
- name: Collect release APKs
160+
id: collect
161+
shell: bash
162+
run: |
163+
set -euo pipefail
164+
165+
config_version_name="$(sed -n 's/.*const val VERSION_NAME = "\([^"]*\)".*/\1/p' buildSrc/src/main/kotlin/BuildConfig.kt | head -n 1)"
166+
ref_version_name="${GITHUB_REF_NAME#v}"
167+
version_name="${REQUESTED_VERSION_NAME:-}"
168+
169+
if [ -z "$version_name" ] && [ "${GITHUB_REF_TYPE:-}" = "tag" ] && [ -n "$ref_version_name" ]; then
170+
version_name="$ref_version_name"
171+
fi
172+
if [ -z "$version_name" ]; then
173+
version_name="$config_version_name"
174+
fi
175+
176+
version_code="$(git rev-list --count HEAD)"
177+
mkdir -p release-artifacts
178+
179+
shopt -s nullglob
180+
for apk in signed-apks/*.apk; do
181+
file_name="$(basename "$apk")"
182+
abi="universal"
183+
case "$file_name" in
184+
*arm64-v8a*) abi="arm64-v8a" ;;
185+
*armeabi-v7a*) abi="armeabi-v7a" ;;
186+
*x86_64*) abi="x86_64" ;;
187+
*x86*) abi="x86" ;;
188+
*universal*) abi="universal" ;;
189+
esac
190+
191+
cp "$apk" "release-artifacts/AsteriskNG_${version_name}-${version_code}-${abi}.apk"
192+
done
193+
194+
if ! find release-artifacts -type f -name "*.apk" | grep -q .; then
195+
echo "::error::No release APKs were found under app/build/outputs/apk/release."
196+
exit 1
197+
fi
198+
199+
echo "version_name=$version_name" >> "$GITHUB_OUTPUT"
200+
echo "version_code=$version_code" >> "$GITHUB_OUTPUT"
201+
ls -lh release-artifacts
202+
203+
- name: Upload GitHub artifact
204+
uses: actions/upload-artifact@v4
205+
with:
206+
name: AsteriskNG_${{ steps.collect.outputs.version_name }}-${{ steps.collect.outputs.version_code }}
207+
path: release-artifacts/*.apk
208+
if-no-files-found: error
209+
210+
- name: Validate Telegram secrets
211+
if: ${{ env.SEND_TO_TELEGRAM == 'true' }}
212+
shell: bash
213+
run: |
214+
set -euo pipefail
215+
if [ -z "${TELEGRAM_BOT_TOKEN:-}" ]; then
216+
echo "::error::Missing repository secret TELEGRAM_BOT_TOKEN."
217+
exit 1
218+
fi
219+
if [ -z "${TELEGRAM_CHAT_ID:-}" ]; then
220+
echo "::error::Missing repository secret TELEGRAM_CHAT_ID."
221+
exit 1
222+
fi
223+
224+
- name: Upload release APKs to Telegram
225+
if: ${{ env.SEND_TO_TELEGRAM == 'true' }}
226+
shell: bash
227+
run: |
228+
set -euo pipefail
229+
230+
mapfile -d '' apks < <(find release-artifacts -maxdepth 1 -type f -name '*.apk' -print0 | sort -z)
231+
if [ "${#apks[@]}" -eq 0 ]; then
232+
echo "::error::No APK files were found in release-artifacts before Telegram upload."
233+
find release-artifacts -maxdepth 1 -type f -print || true
234+
exit 1
235+
fi
236+
237+
ls -lh release-artifacts
238+
max_document_bytes="${TELEGRAM_MAX_DOCUMENT_BYTES:-52428800}"
239+
commit_id="$(git rev-parse HEAD)"
240+
commit_short_id="$(git rev-parse --short=12 HEAD)"
241+
commit_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/commit/$commit_id"
242+
workflow_run_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
243+
commit_message="$(git log -1 --pretty=%B)"
244+
commit_message="${commit_message//$'\r'/}"
245+
if [ -z "${commit_message//[[:space:]]/}" ]; then
246+
commit_message="(empty commit message)"
247+
fi
248+
if [ "${#commit_message}" -gt 650 ]; then
249+
commit_message="${commit_message:0:650}"$'\n...'
250+
fi
251+
commit_message_html="$(printf '%s' "$commit_message" | python3 -c 'import html, sys; print(html.escape(sys.stdin.read(), quote=False), end="")')"
252+
253+
for apk in "${apks[@]}"; do
254+
apk_path="$(realpath "$apk")"
255+
apk_name="$(basename "$apk")"
256+
if [ ! -r "$apk_path" ]; then
257+
echo "::error::APK is not readable: $apk_path"
258+
exit 1
259+
fi
260+
261+
apk_size="$(stat -c '%s' "$apk_path")"
262+
if [ "$apk_size" -gt "$max_document_bytes" ]; then
263+
echo "::warning::Skipping Telegram upload for $apk_name because it is $apk_size bytes, above the $max_document_bytes byte limit."
264+
continue
265+
fi
266+
267+
echo "Uploading $apk_name to Telegram"
268+
269+
caption="$(printf 'AsteriskNG\n\n%s\n\n%s\n<a href="%s">Commit</a> | <a href="%s">Workflow run</a>' \
270+
"$commit_message_html" \
271+
"$commit_short_id" \
272+
"$commit_url" \
273+
"$workflow_run_url")"
274+
275+
args=(
276+
--fail-with-body
277+
-sS
278+
-X POST
279+
"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument"
280+
--form-string "chat_id=${TELEGRAM_CHAT_ID}"
281+
--form "document=@${apk_path};filename=${apk_name}"
282+
--form-string "caption=${caption}"
283+
--form-string "parse_mode=HTML"
284+
)
285+
286+
if [ -n "${TELEGRAM_MESSAGE_THREAD_ID:-}" ]; then
287+
args+=(--form-string "message_thread_id=${TELEGRAM_MESSAGE_THREAD_ID}")
288+
fi
289+
290+
curl "${args[@]}"
291+
done

setuidgid/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ android {
2525
val buildSetuidgid by tasks.registering(BuildSetuidgidTask::class) {
2626
sourceFile.set(layout.projectDirectory.file("src/main/native/setuidgid.c"))
2727
outputDirectory.set(generatedJniLibsDir)
28-
localPropertiesFile.set(rootProject.layout.projectDirectory.file("local.properties"))
28+
rootProject.layout.projectDirectory.file("local.properties")
29+
.takeIf { it.asFile.exists() }
30+
?.let(localPropertiesFile::set)
2931
minSdk.set(ProjectConfig.MIN_SDK)
3032
targetAbis.set(ProjectConfig.SUPPORTED_ANDROID_ABIS)
3133
}

0 commit comments

Comments
 (0)