1+ name : AAPS CI
2+
3+ on :
4+ workflow_dispatch :
5+ inputs :
6+ buildVariant :
7+ description : ' Select Build Variant'
8+ required : true
9+ default : ' fullRelease'
10+ type : choice
11+ options :
12+ - fullRelease
13+ - fullDebug
14+ - aapsclientRelease
15+ - aapsclientDebug
16+ - aapsclient2Release
17+ - aapsclient2Debug
18+ - pumpcontrolRelease
19+ - pumpcontrolDebug
20+
21+ jobs :
22+ build :
23+ name : Build AAPS
24+ runs-on : ubuntu-latest
25+ steps :
26+ - name : Decode Secrets Keystore Set and Oauth2 to Env
27+ run : |
28+ if [ -n "${{ secrets.KEYSTORE_SET }}" ]; then
29+ echo "🔐 Decoding KEYSTORE_SET..."
30+ DECODED=$(echo "${{ secrets.KEYSTORE_SET }}" | base64 -d)
31+
32+ KEYSTORE_BASE64=$(echo "$DECODED" | cut -d'|' -f1)
33+ KEYSTORE_PASSWORD=$(echo "$DECODED" | cut -d'|' -f2)
34+ KEY_ALIAS=$(echo "$DECODED" | cut -d'|' -f3)
35+ KEY_PASSWORD=$(echo "$DECODED" | cut -d'|' -f4)
36+
37+ echo "KEYSTORE_BASE64=$KEYSTORE_BASE64" >> $GITHUB_ENV
38+ echo "KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD" >> $GITHUB_ENV
39+ echo "KEY_ALIAS=$KEY_ALIAS" >> $GITHUB_ENV
40+ echo "KEY_PASSWORD=$KEY_PASSWORD" >> $GITHUB_ENV
41+
42+ echo "::add-mask::$KEYSTORE_BASE64"
43+ echo "::add-mask::$KEYSTORE_PASSWORD"
44+ echo "::add-mask::$KEY_ALIAS"
45+ echo "::add-mask::$KEY_PASSWORD"
46+
47+ echo "✅ Keystore parameters extracted from KEYSTORE_SET"
48+ else
49+ echo "ℹ️ KEYSTORE_SET not provided, using separate secrets."
50+ echo "KEYSTORE_BASE64=${{ secrets.KEYSTORE_BASE64 }}" >> $GITHUB_ENV
51+ echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> $GITHUB_ENV
52+ echo "KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> $GITHUB_ENV
53+ echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> $GITHUB_ENV
54+ fi
55+ echo "GDRIVE_OAUTH2=${{ secrets.GDRIVE_OAUTH2 }}" >> $GITHUB_ENV
56+
57+ - name : Check Secrets
58+ run : |
59+ echo "🔍 Checking required secrets..."
60+ MISSING=0
61+
62+ check_secret() {
63+ if [ -z "$1" ]; then
64+ echo "❌ Missing secret: $2"
65+ MISSING=1
66+ fi
67+ }
68+
69+ # Check secrets
70+ check_secret "$GDRIVE_OAUTH2" "GDRIVE_OAUTH2"
71+
72+ check_secret "$KEYSTORE_BASE64" "KEYSTORE_BASE64"
73+ check_secret "$KEYSTORE_PASSWORD" "KEYSTORE_PASSWORD"
74+ check_secret "$KEY_ALIAS" "KEY_ALIAS"
75+ check_secret "$KEY_PASSWORD" "KEY_PASSWORD"
76+
77+ if [ "$MISSING" -eq 1 ]; then
78+ echo "🛑 Missing required secrets. Stopping build."
79+ exit 1
80+ fi
81+
82+ echo "✅ All required secrets are present."
83+
84+ - name : Decode keystore file
85+ run : |
86+ mkdir -p "$RUNNER_TEMP/keystore"
87+ echo "$KEYSTORE_BASE64" | base64 -d > "$RUNNER_TEMP/keystore/keystore.jks"
88+
89+ - name : Validating keystore, alias and password
90+ run : |
91+ set -x
92+ echo "🔐 Validating keystore, alias and password"
93+
94+ # Create a dummy JAR file (quick method using zip)
95+ echo "test" > dummy.txt
96+ zip -q dummy.jar dummy.txt
97+ rm dummy.txt
98+
99+ # Attempt to validate using jarsigner
100+ JARSIGNER_LOG=$(mktemp)
101+ if ! jarsigner \
102+ -keystore "$RUNNER_TEMP/keystore/keystore.jks" \
103+ -storepass "$KEYSTORE_PASSWORD" \
104+ -keypass "$KEY_PASSWORD" \
105+ dummy.jar "$KEY_ALIAS" > "$JARSIGNER_LOG" 2>&1; then
106+ echo "❌ Either KEYSTORE_BASE64, KEYSTORE_PASSWORD, KEY_PASSWORD, or KEY_ALIAS is incorrect"
107+ echo "🔍 jarsigner error output:"
108+ cat "$JARSIGNER_LOG"
109+ rm -f "$JARSIGNER_LOG" dummy.jar
110+ exit 1
111+ fi
112+ rm -f "$JARSIGNER_LOG" dummy.jar
113+ echo "✅ Keystore, alias, and key password are valid."
114+
115+ rm -f "$KEYTOOL_LOG"
116+ echo "✅ Keystore and credentials validated."
117+
118+ - name : Decode GDrive OAuth2 secrets
119+ run : |
120+ echo "🔐 Decoding GDRIVE_OAUTH2..."
121+ DECODED=$(echo "${{ secrets.GDRIVE_OAUTH2 }}" | base64 -d)
122+
123+ GDRIVE_CLIENT_ID=$(echo "$DECODED" | cut -d'|' -f1)
124+ GDRIVE_REFRESH_TOKEN=$(echo "$DECODED" | cut -d'|' -f2)
125+
126+ echo "::add-mask::$GDRIVE_CLIENT_ID"
127+ echo "::add-mask::$GDRIVE_REFRESH_TOKEN"
128+
129+ echo "GDRIVE_CLIENT_ID=$GDRIVE_CLIENT_ID" >> $GITHUB_ENV
130+ echo "GDRIVE_REFRESH_TOKEN=$GDRIVE_REFRESH_TOKEN" >> $GITHUB_ENV
131+
132+ echo "✅ GDRIVE_CLIENT_ID and GDRIVE_REFRESH_TOKEN extracted from GDRIVE_OAUTH2"
133+
134+ - name : Retrieving Google Drive access token
135+ run : |
136+ echo "🔐 Getting Google OAuth2 access token..."
137+ TOKEN_RESPONSE=$(curl -s -X POST https://oauth2.googleapis.com/token \
138+ -d client_id="$GDRIVE_CLIENT_ID" \
139+ -d refresh_token="$GDRIVE_REFRESH_TOKEN" \
140+ -d grant_type=refresh_token)
141+ ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r .access_token)
142+ echo "::add-mask::$ACCESS_TOKEN"
143+ if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then
144+ echo "❌ Failed to get access token."
145+ echo "$TOKEN_RESPONSE"
146+ exit 1
147+ fi
148+ echo "ACCESS_TOKEN=$ACCESS_TOKEN" >> $GITHUB_ENV
149+ echo "✅ Access token obtained."
150+
151+ - name : Checkout source code
152+ uses : actions/checkout@v4
153+
154+ - name : Set BUILD_VARIANT
155+ run : |
156+ BUILD_VARIANT="${{ github.event.inputs.buildVariant }}"
157+ echo "BUILD_VARIANT=$BUILD_VARIANT" >> $GITHUB_ENV
158+ VARIANT_FLAVOR=$(echo "$BUILD_VARIANT" | sed -E 's/(Release|Debug)$//' | tr '[:upper:]' '[:lower:]')
159+ VARIANT_TYPE=$(echo "$BUILD_VARIANT" | grep -oE '(Release|Debug)$' | tr '[:upper:]' '[:lower:]')
160+ echo "VARIANT_FLAVOR=$VARIANT_FLAVOR" >> $GITHUB_ENV
161+ echo "VARIANT_TYPE=$VARIANT_TYPE" >> $GITHUB_ENV
162+ VERSION_SUFFIX=""
163+ if [[ "$VARIANT_FLAVOR" != "full" ]]; then VERSION_SUFFIX="$VARIANT_FLAVOR"; fi
164+ if [[ "$VARIANT_TYPE" == "debug" ]]; then VERSION_SUFFIX="$VERSION_SUFFIX-debug"; fi
165+ if [[ -n "$VERSION_SUFFIX" && "$VERSION_SUFFIX" != -* ]]; then VERSION_SUFFIX="-$VERSION_SUFFIX"; fi
166+ echo "VERSION_SUFFIX=$VERSION_SUFFIX" >> $GITHUB_ENV
167+
168+ - name : Extract VERSION
169+ run : |
170+ BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
171+ if echo "$BRANCH_NAME" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$'; then
172+ VERSION="$BRANCH_NAME"
173+ else
174+ VERSION=$(grep 'val appVersion' buildSrc/src/main/kotlin/Versions.kt | awk -F '"' '{print $2}')
175+ fi
176+ echo "VERSION=$VERSION" >> $GITHUB_ENV
177+
178+ - name : Set up JDK
179+ uses : actions/setup-java@v4
180+ with :
181+ # When upgrading the JDK, please update this section accordingly as well.
182+ java-version : 21
183+ distribution : ' temurin'
184+ cache : gradle
185+
186+ - name : Grant execute permission for gradlew
187+ run : chmod +x gradlew
188+
189+ - name : Build APKs
190+ run : |
191+ ./gradlew assemble${{ env.BUILD_VARIANT }} \
192+ -Pandroid.injected.signing.store.file="$RUNNER_TEMP/keystore/keystore.jks" \
193+ -Pandroid.injected.signing.store.password="$KEYSTORE_PASSWORD" \
194+ -Pandroid.injected.signing.key.alias="$KEY_ALIAS" \
195+ -Pandroid.injected.signing.key.password="$KEY_PASSWORD"
196+
197+ - name : Rename APKs with version
198+ run : |
199+ mv app/build/outputs/apk/${{ env.VARIANT_FLAVOR }}/${{ env.VARIANT_TYPE }}/*.apk aaps-${{ env.VERSION }}${{ env.VERSION_SUFFIX }}.apk
200+ mv wear/build/outputs/apk/${{ env.VARIANT_FLAVOR }}/${{ env.VARIANT_TYPE }}/*.apk aaps-wear-${{ env.VERSION }}${{ env.VERSION_SUFFIX }}.apk
201+
202+ - name : Upload APKs to Google Drive
203+ run : |
204+ set -e
205+ echo "🔐 Start uploading APKs to Google Drive..."
206+
207+ echo "📁 Checking or creating AAPS folder"
208+ AAPS_FOLDER_ID=$(curl -s -X GET \
209+ -H "Authorization: Bearer $ACCESS_TOKEN" \
210+ "https://www.googleapis.com/drive/v3/files?q=name='AAPS'+and+mimeType='application/vnd.google-apps.folder'+and+trashed=false" \
211+ | jq -r '.files[0].id')
212+
213+ if [ "$AAPS_FOLDER_ID" == "null" ] || [ -z "$AAPS_FOLDER_ID" ]; then
214+ AAPS_FOLDER_ID=$(curl -s -X POST \
215+ -H "Authorization: Bearer $ACCESS_TOKEN" \
216+ -H "Content-Type: application/json" \
217+ -d '{"name": "AAPS", "mimeType": "application/vnd.google-apps.folder"}' \
218+ "https://www.googleapis.com/drive/v3/files" | jq -r '.id')
219+ echo "📂 Created AAPS folder: $AAPS_FOLDER_ID"
220+ else
221+ echo "📂 Found AAPS folder: $AAPS_FOLDER_ID"
222+ fi
223+
224+ echo "📁 Checking or creating version folder: $VERSION"
225+ VERSION_FOLDER_ID=$(curl -s -X GET \
226+ -H "Authorization: Bearer $ACCESS_TOKEN" \
227+ "https://www.googleapis.com/drive/v3/files?q=name='${VERSION}'+and+mimeType='application/vnd.google-apps.folder'+and+'$AAPS_FOLDER_ID'+in+parents+and+trashed=false" \
228+ | jq -r '.files[0].id')
229+
230+ if [ "$VERSION_FOLDER_ID" == "null" ] || [ -z "$VERSION_FOLDER_ID" ]; then
231+ VERSION_FOLDER_ID=$(curl -s -X POST \
232+ -H "Authorization: Bearer $ACCESS_TOKEN" \
233+ -H "Content-Type: application/json" \
234+ -d "{\"name\": \"${VERSION}\", \"mimeType\": \"application/vnd.google-apps.folder\", \"parents\": [\"$AAPS_FOLDER_ID\"]}" \
235+ "https://www.googleapis.com/drive/v3/files" | jq -r '.id')
236+ echo "📂 Created version folder: $VERSION_FOLDER_ID"
237+ else
238+ echo "📂 Found version folder: $VERSION_FOLDER_ID"
239+ fi
240+
241+ upload_to_gdrive() {
242+ FILE=$1
243+ NAME=$2
244+ if [ ! -f "$FILE" ]; then
245+ echo "❌ File not found: $FILE"
246+ exit 26
247+ fi
248+
249+ echo "📄 Checking if file $NAME already exists in Google Drive..."
250+ QUERY="name='${NAME}' and '${VERSION_FOLDER_ID}' in parents and trashed=false"
251+ ENCODED_QUERY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''$QUERY'''))")
252+ FILE_ID=$(curl -s \
253+ -H "Authorization: Bearer $ACCESS_TOKEN" \
254+ "https://www.googleapis.com/drive/v3/files?q=${ENCODED_QUERY}&fields=files(id)" \
255+ | jq -r '.files[0].id')
256+
257+ if [[ -n "$FILE_ID" && "$FILE_ID" != "null" ]]; then
258+ echo "🗑️ Deleting existing file with ID: $FILE_ID"
259+ curl -s -X DELETE \
260+ -H "Authorization: Bearer $ACCESS_TOKEN" \
261+ "https://www.googleapis.com/drive/v3/files/${FILE_ID}"
262+ fi
263+
264+ echo "⬆️ Uploading $FILE as $NAME to Google Drive..."
265+ RESPONSE=$(curl -s -w "%{http_code}" -o /tmp/gdrive_response.json \
266+ -X POST \
267+ -H "Authorization: Bearer $ACCESS_TOKEN" \
268+ -F "metadata={\"name\":\"$NAME\", \"parents\":[\"$VERSION_FOLDER_ID\"]};type=application/json;charset=UTF-8" \
269+ -F "file=@$FILE;type=application/vnd.android.package-archive" \
270+ "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart")
271+
272+ HTTP_CODE="${RESPONSE: -3}"
273+ if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
274+ echo "❌ Upload failed with HTTP status: $HTTP_CODE"
275+ cat /tmp/gdrive_response.json
276+ exit 1
277+ fi
278+
279+ echo "✅ Uploaded: $NAME"
280+ }
281+
282+ upload_to_gdrive "aaps-${VERSION}${VERSION_SUFFIX}.apk" "aaps-${VERSION}${VERSION_SUFFIX}.apk"
283+ upload_to_gdrive "aaps-wear-${VERSION}${VERSION_SUFFIX}.apk" "aaps-wear-${VERSION}${VERSION_SUFFIX}.apk"
284+
285+ echo "🎉 APKs successfully uploaded to Google Drive!"
0 commit comments