Repository navigation
157 lines (141 loc) · 5.6 KB
/
Copy pathandroid.yml
File metadata and controls
157 lines (141 loc) · 5.6 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
name: Android
# A tag builds an APK and attaches it, signed, to its release. A push that touches
# the Android project builds an unsigned one, so a broken Gradle project shows up
# before the next tag.
#
# A tag runs two jobs, because an APK signed with a new key cannot update an installed
# app, so a stolen signing key could never be replaced. npm packages, Gradle plugins
# and setup actions all run in `build-release`, which has no secrets and a read-only
# token. `sign-release` runs on a fresh machine with none of that code: it only
# signs, checks and publishes the file it is handed.
on:
push:
tags: ['v*']
branches: [main]
# GitHub does not apply path filters to tags.
paths:
- android/**
- capacitor.config.json
- package-lock.json
- .github/actions/android-setup/**
- .github/workflows/android.yml
permissions:
contents: read
jobs:
check:
if: github.repository == 'tiennm99dev/gitnote' && github.ref_type == 'branch'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up the Android build
uses: ./.github/actions/android-setup
- name: Build an unsigned APK
working-directory: android
run: ./gradlew assembleDebug --no-daemon
build-release:
if: github.repository == 'tiennm99dev/gitnote' && github.ref_type == 'tag'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Warn about missing sign-in IDs
env:
CLIENT_ID_GITHUB: ${{ vars.VITE_GITHUB_CLIENT_ID }}
CLIENT_ID_GITLAB: ${{ vars.VITE_GITLAB_CLIENT_ID }}
run: |
[ -n "$CLIENT_ID_GITHUB" ] || echo "::warning::VITE_GITHUB_CLIENT_ID is not set, so this APK has no GitHub sign-in button."
[ -n "$CLIENT_ID_GITLAB" ] || echo "::warning::VITE_GITLAB_CLIENT_ID is not set, so this APK has no GitLab sign-in button."
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up the Android build
uses: ./.github/actions/android-setup
with:
github-client-id: ${{ vars.VITE_GITHUB_CLIENT_ID }}
github-app-slug: ${{ vars.VITE_GITHUB_APP_SLUG }}
gitlab-client-id: ${{ vars.VITE_GITLAB_CLIENT_ID }}
- name: Build the unsigned APK
working-directory: android
env:
GITNOTE_VERSION_CODE: ${{ github.run_number }}
TAG: ${{ github.ref_name }}
run: GITNOTE_VERSION_NAME="${TAG#v}" ./gradlew assembleRelease --no-daemon
- name: Hand it to the signing job
uses: actions/upload-artifact@v7
with:
name: unsigned-apk
path: android/app/build/outputs/apk/release/app-release-unsigned.apk
if-no-files-found: error
retention-days: 1
sign-release:
needs: build-release
runs-on: ubuntu-latest
timeout-minutes: 10
environment: android-release
permissions:
contents: write
env:
TAG: ${{ github.ref_name }}
steps:
- name: Require the signing secrets
env:
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
for name in KEYSTORE_BASE64 KEYSTORE_PASSWORD KEY_ALIAS KEY_PASSWORD; do
if [ -z "${!name}" ]; then
echo "::error::The secret ANDROID_$name is not set. See docs/android.md."
exit 1
fi
done
- name: Take the unsigned APK
uses: actions/download-artifact@v8
with:
name: unsigned-apk
path: ${{ runner.temp }}/unsigned
# The runner image's own SDK, so no setup action shares this job with the key.
- name: Put build-tools on the PATH
run: find "$ANDROID_HOME/build-tools" -mindepth 1 -maxdepth 1 | sort -V | tail -n 1 >> "$GITHUB_PATH"
- name: Sign the APK
env:
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
umask 077
keystore="$RUNNER_TEMP/release.jks"
trap 'rm -f "$keystore"' EXIT
printf '%s' "$KEYSTORE_BASE64" | base64 --decode > "$keystore"
apksigner sign \
--ks "$keystore" \
--ks-pass env:KEYSTORE_PASSWORD \
--ks-key-alias "$KEY_ALIAS" \
--key-pass env:KEY_PASSWORD \
--in "$RUNNER_TEMP/unsigned/app-release-unsigned.apk" \
--out "$RUNNER_TEMP/gitnote-$TAG.apk"
- name: Verify the signature
run: |
apk="$RUNNER_TEMP/gitnote-$TAG.apk"
zipalign -c -p 4 "$apk"
apksigner verify --print-certs --verbose "$apk" | tee "$RUNNER_TEMP/verify.txt"
grep -Eq 'Verified using v[23] scheme .*: true' "$RUNNER_TEMP/verify.txt"
- name: Attach the APK to the release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
file="$RUNNER_TEMP/gitnote-$TAG.apk"
if gh release view "$TAG" > /dev/null 2>&1; then
gh release upload "$TAG" "$file" --clobber
else
flags=()
case "$TAG" in *-*) flags+=(--prerelease) ;; esac
gh release create "$TAG" "$file" --title "$TAG" --generate-notes "${flags[@]}"
fi