|
10 | 10 | runs-on: ubuntu-latest |
11 | 11 | env: |
12 | 12 | GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} |
| 13 | + GDRIVE_SERVICE_ACCOUNT_JSON: ${{ secrets.GDRIVE_SERVICE_ACCOUNT_JSON }} |
13 | 14 |
|
14 | 15 | steps: |
15 | 16 | - name: Checkout |
|
39 | 40 | working-directory: app |
40 | 41 | run: flutter build apk --release |
41 | 42 |
|
42 | | - - name: Email APK |
| 43 | + - name: Install Drive upload dependencies |
| 44 | + run: | |
| 45 | + python -m pip install --upgrade pip |
| 46 | + python -m pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib |
| 47 | +
|
| 48 | + - name: Upload APK to Google Drive |
| 49 | + id: drive_upload |
| 50 | + run: | |
| 51 | + python - <<'PY' |
| 52 | + import datetime |
| 53 | + import json |
| 54 | + import os |
| 55 | +
|
| 56 | + from google.oauth2.service_account import Credentials |
| 57 | + from googleapiclient.discovery import build |
| 58 | + from googleapiclient.http import MediaFileUpload |
| 59 | +
|
| 60 | + sa_json = os.environ.get("GDRIVE_SERVICE_ACCOUNT_JSON") |
| 61 | + if not sa_json: |
| 62 | + raise SystemExit("Missing Drive service account secret") |
| 63 | +
|
| 64 | + info = json.loads(sa_json) |
| 65 | + creds = Credentials.from_service_account_info( |
| 66 | + info, |
| 67 | + scopes=["https://www.googleapis.com/auth/drive"], |
| 68 | + ) |
| 69 | + service = build("drive", "v3", credentials=creds) |
| 70 | +
|
| 71 | + def find_or_create_folder(name: str, parent_id: str | None = None) -> str: |
| 72 | + safe_name = name.replace("'", "\\'") |
| 73 | + query = ( |
| 74 | + "mimeType='application/vnd.google-apps.folder' " |
| 75 | + "and name='" + safe_name + "' and trashed=false" |
| 76 | + ) |
| 77 | + if parent_id: |
| 78 | + query += " and '" + parent_id + "' in parents" |
| 79 | + result = service.files().list( |
| 80 | + q=query, |
| 81 | + fields="files(id,name)", |
| 82 | + spaces="drive", |
| 83 | + ).execute() |
| 84 | + files = result.get("files", []) |
| 85 | + if files: |
| 86 | + return files[0]["id"] |
| 87 | + metadata = { |
| 88 | + "name": name, |
| 89 | + "mimeType": "application/vnd.google-apps.folder", |
| 90 | + } |
| 91 | + if parent_id: |
| 92 | + metadata["parents"] = [parent_id] |
| 93 | + folder = service.files().create(body=metadata, fields="id").execute() |
| 94 | + return folder["id"] |
| 95 | +
|
| 96 | + root_folder_id = find_or_create_folder("Talk-in-english") |
| 97 | + timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%d_%H-%M-%S_UTC") |
| 98 | + build_folder_id = find_or_create_folder(timestamp, root_folder_id) |
| 99 | +
|
| 100 | + apk_path = "app/build/app/outputs/flutter-apk/app-release.apk" |
| 101 | + media = MediaFileUpload( |
| 102 | + apk_path, |
| 103 | + mimetype="application/vnd.android.package-archive", |
| 104 | + resumable=True, |
| 105 | + ) |
| 106 | + file_metadata = { |
| 107 | + "name": "app-release.apk", |
| 108 | + "parents": [build_folder_id], |
| 109 | + } |
| 110 | + uploaded = service.files().create( |
| 111 | + body=file_metadata, |
| 112 | + media_body=media, |
| 113 | + fields="id,webViewLink,webContentLink", |
| 114 | + ).execute() |
| 115 | +
|
| 116 | + service.permissions().create( |
| 117 | + fileId=uploaded["id"], |
| 118 | + body={"type": "anyone", "role": "reader"}, |
| 119 | + ).execute() |
| 120 | +
|
| 121 | + link = uploaded.get("webViewLink") or uploaded.get("webContentLink") |
| 122 | + if not link: |
| 123 | + raise SystemExit("No Drive link generated") |
| 124 | +
|
| 125 | + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: |
| 126 | + fh.write(f"apk_link={link}\n") |
| 127 | + PY |
| 128 | +
|
| 129 | + - name: Email APK link |
43 | 130 | uses: dawidd6/action-send-mail@v3 |
44 | 131 | with: |
45 | 132 | server_address: ${{ secrets.SMTP_HOST }} |
|
49 | 136 | subject: "Speaking App - Release APK" |
50 | 137 | to: ${{ secrets.SMTP_TO }} |
51 | 138 | from: ${{ secrets.SMTP_FROM }} |
52 | | - body: "Attached is the latest release APK from the main branch build." |
53 | | - attachments: app/build/app/outputs/flutter-apk/app-release.apk |
| 139 | + body: "Latest release APK uploaded to Google Drive: ${{ steps.drive_upload.outputs.apk_link }}" |
0 commit comments