Repository navigation
202 lines (182 loc) · 8 KB
/
Copy pathbuild.yml
File metadata and controls
202 lines (182 loc) · 8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
name: Build
on:
push:
pull_request:
workflow_dispatch:
inputs:
commit_hash:
description: 'Specific commit SHA to build (leave empty for latest branch commit)'
required: false
type: string
# One run per branch (and event). On working branches a newer push cancels the older run;
# on basic / v2 it waits instead (only the newest waits), so "latest" still ends with the
# build of the newest commit (#90) and a publish is never cut off halfway. A manual run of the
# branch head shares that group (so each branch has one publish at a time and the shared
# release-latest group below never holds more than one waiting job); a manual run of an older
# commit (commit_hash) has a group of its own and does not publish.
concurrency:
group: ${{ github.event_name == 'workflow_dispatch' && inputs.commit_hash != '' && format('manual-{0}', github.run_id) || format('build-{0}-{1}', github.event_name == 'pull_request' && 'pull_request' || 'push', github.ref) }}
cancel-in-progress: ${{ !(github.event_name == 'workflow_dispatch' && inputs.commit_hash != '') && github.ref != 'refs/heads/v2' && github.ref != 'refs/heads/basic' }}
# Read-only by default; only the publish job writes the release
permissions:
contents: read
jobs:
# The version check of pull requests is .github/workflows/version.yml (#244).
# Unit tests and lint; also runs for pull requests from forks (no secrets needed)
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Switch to specified commit (keep latest workflow files)
if: inputs.commit_hash != ''
run: |
git fetch --unshallow
git checkout ${{ inputs.commit_hash }}
git checkout ${{ github.ref_name }} -- .github/
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
cache: gradle
- name: Unit tests and lint
working-directory: android
run: |
./gradlew testDebugUnitTest
# Commits from before the lint baseline would fail on known findings
if [ -f app/lint-baseline.xml ]; then
./gradlew lintDebug
else
echo "No lint baseline in this commit, lint skipped"
fi
- name: Upload reports
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-and-lint-reports
path: |
android/app/build/reports/
android/app/build/test-results/
# Signed release build; needs secrets, so it does not run for pull requests
build:
needs: test
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
outputs:
mapping: ${{ steps.apk.outputs.mapping }} # 1 when the build has an R8 mapping
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Switch to specified commit (keep latest workflow files)
if: inputs.commit_hash != ''
run: |
git fetch --unshallow
git checkout ${{ inputs.commit_hash }}
git checkout ${{ github.ref_name }} -- .github/
- name: Set artifact name
id: vars
run: |
case "${{ github.ref_name }}" in
basic) echo "name=decoder" ;;
v2) echo "name=decoder-v2" ;;
*) echo "name=decoder-$(echo '${{ github.ref_name }}' | tr '/' '-')" ;;
esac >> $GITHUB_OUTPUT
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
cache: gradle
- name: Build
id: apk
working-directory: android
env:
KEYSTORE_PASS: ${{ secrets.KEYSTORE_PASS }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASS: ${{ secrets.KEY_PASS }}
run: |
echo "${{ secrets.KEY }}" | base64 -d > key.jks
# APK only while in development; the .aab (bundleRelease) is for store uploads
./gradlew assembleRelease
mv app/build/outputs/apk/release/app-release.apk ../${{ steps.vars.outputs.name }}.apk
# R8 mapping of this APK, to retrace obfuscated stack traces (#181). A build without
# minify has none: warn instead of failing
MAPPING=app/build/outputs/mapping/release/mapping.txt
if [ -f "$MAPPING" ]; then
cp "$MAPPING" ../${{ steps.vars.outputs.name }}-mapping.txt
echo "mapping=1" >> "$GITHUB_OUTPUT"
else
echo "::warning::No R8 mapping.txt at $MAPPING"
fi
# Every build keeps its R8 mapping as a workflow artifact (#181)
- name: Upload mapping
uses: actions/upload-artifact@v4
with:
name: ${{ steps.vars.outputs.name }}-mapping
path: ${{ steps.vars.outputs.name }}-mapping.txt
if-no-files-found: warn
# Every build is a workflow artifact; on basic / v2 the publish job takes it from here
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.vars.outputs.name }}
path: ${{ steps.vars.outputs.name }}.apk
# The one release, "latest" (#194, #229): updated in place by v2 and basic, each with its
# own files; v2 moves the tag to its commit and sets the title "Decoder <version>".
# A new version (not every build) goes to Telegram. The
# concurrency group is shared with basic's workflow: one publish at a time.
publish:
needs: build
# basic publishes from its own workflow (same script, same concurrency group); a manual
# run of an older commit (commit_hash) builds but does not publish
if: github.ref_name == 'v2' && (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.commit_hash == ''))
runs-on: ubuntu-latest
permissions:
contents: write # update the release and move its tag
concurrency:
group: release-latest
cancel-in-progress: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download the build
uses: actions/download-artifact@v4
with:
name: decoder-v2
path: dist
# only when the build has one (a build without minify has none, #181); then it must come
- name: Download the mapping
if: needs.build.outputs.mapping == '1'
uses: actions/download-artifact@v4
with:
name: decoder-v2-mapping
path: dist
- name: Publish
id: publish
env:
GH_TOKEN: ${{ github.token }}
run: |
VER=$(sed -n 's/^[[:space:]]*versionName[[:space:]]*"\([^"]*\)"[[:space:]]*$/\1/p' android/app/build.gradle)
[ -n "$VER" ] || { echo "::error::no versionName in android/app/build.gradle"; exit 1; }
echo "VER=$VER" >> "$GITHUB_ENV"
files=(dist/decoder-v2.apk)
[ -f dist/decoder-v2-mapping.txt ] && files+=(dist/decoder-v2-mapping.txt)
.github/publish-latest.sh v2 "$VER" "${files[@]}"
# Organization secrets; a failed upload is a warning, not a failed release
- name: Telegram
if: steps.publish.outputs.new == 'true'
env:
TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }}
TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }}
run: |
if [ -z "$TG_TOKEN" ] || [ -z "$TG_CHANNEL" ]; then
echo "::warning::Telegram secrets are not available, version not announced"; exit 0
fi
CAPTION=$(printf 'Decoder %s\nCommit: %s\nBranch: %s\nTime: %s\n\n%s' "$VER" "${GITHUB_SHA::7}" \
"${GITHUB_REF_NAME}" "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" \
"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/latest")
HTTP=$(curl -sS -o tg.json -w '%{http_code}' "https://api.telegram.org/bot${TG_TOKEN}/sendDocument" \
-F chat_id="$TG_CHANNEL" -F caption="$CAPTION" -F document=@dist/decoder-v2.apk) || HTTP=000
echo "Telegram response: $HTTP"
[ "$HTTP" = 200 ] || echo "::warning::Telegram upload failed (HTTP $HTTP)"