-
Notifications
You must be signed in to change notification settings - Fork 0
175 lines (157 loc) · 6.39 KB
/
Copy pathdeploy.yml
File metadata and controls
175 lines (157 loc) · 6.39 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
name: Deploy & Android Release
# Every push to master:
# 0. Detect whether backend/ and/or frontend/ actually changed
# 1. If either did: SSH redeploy on the server (frontend + backend + migrations)
# 2. If frontend did: build a signed APK and publish a GitHub Release (OTA pickup)
# A push that touches neither (docs, diagrams, README, etc.) is just a normal
# git update — no redeploy, no new APK/release, no wasted CI minutes.
# workflow_dispatch always runs everything (manual trigger = force it).
on:
push:
branches: [master]
workflow_dispatch:
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false
jobs:
changes:
name: Detect changed areas
runs-on: ubuntu-latest
outputs:
backend: ${{ steps.filter.outputs.backend }}
frontend: ${{ steps.filter.outputs.frontend }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend:
- 'fixit-pr3/fixit-backend/**'
frontend:
- 'fixit-pr3/fixit-frontend/**'
deploy-server:
name: Deploy to server
needs: changes
if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.backend == 'true' || needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-latest
steps:
- name: SSH redeploy (frontend + backend + DB migrations)
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.SSH_HOST }}
username: deploy
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.SSH_PORT }}
command_timeout: 20m
script: sudo -n /root/redeploy.sh
android-release:
name: Build & publish APK
needs: changes
# Only the frontend affects the APK bundle — a backend-only push would
# produce a byte-identical app and just clutter the release history.
if: github.event_name == 'workflow_dispatch' || needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
env:
FRONTEND_DIR: fixit-pr3/fixit-frontend
VITE_API_URL: https://fixit.olgtx.com/api
steps:
- uses: actions/checkout@v4
- name: Check Android signing secrets
id: sign
run: |
if [ -z "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" ]; then
echo "ready=false" >> "$GITHUB_OUTPUT"
echo "::warning::ANDROID_KEYSTORE_BASE64 not configured — skipping APK build. Add keystore secrets to enable."
else
echo "ready=true" >> "$GITHUB_OUTPUT"
fi
- uses: actions/setup-node@v4
if: steps.sign.outputs.ready == 'true'
with:
node-version: '20'
cache: npm
cache-dependency-path: ${{ env.FRONTEND_DIR }}/package-lock.json
- uses: actions/setup-java@v4
if: steps.sign.outputs.ready == 'true'
with:
distribution: temurin
java-version: '21'
- name: Setup Android SDK
if: steps.sign.outputs.ready == 'true'
uses: android-actions/setup-android@v3
- name: Install Android SDK 36 (required by androidx.browser 1.9)
if: steps.sign.outputs.ready == 'true'
run: sdkmanager "platforms;android-36"
- name: Resolve version
if: steps.sign.outputs.ready == 'true'
id: ver
working-directory: ${{ env.FRONTEND_DIR }}
run: |
BASE=$(node -p "require('./package.json').version")
# Monotonic build: 1.0.0 → 1.0.<run_number> for OTA comparison
echo "base=$BASE" >> "$GITHUB_OUTPUT"
echo "name=${BASE%.*}.${{ github.run_number }}" >> "$GITHUB_OUTPUT"
echo "tag=v${BASE%.*}.${{ github.run_number }}" >> "$GITHUB_OUTPUT"
echo "code=${{ github.run_number }}" >> "$GITHUB_OUTPUT"
- name: Build web + sync Capacitor
if: steps.sign.outputs.ready == 'true'
working-directory: ${{ env.FRONTEND_DIR }}
env:
VITE_API_URL: ${{ env.VITE_API_URL }}
run: |
npm ci
npm run build
npx cap sync android
- name: Stamp version into Gradle
if: steps.sign.outputs.ready == 'true'
working-directory: ${{ env.FRONTEND_DIR }}/android
run: |
sed -i "s/versionName \".*\"/versionName \"${{ steps.ver.outputs.name }}\"/" app/build.gradle
sed -i "s/versionCode [0-9]*/versionCode ${{ steps.ver.outputs.code }}/" app/build.gradle
- name: Write signing config
if: steps.sign.outputs.ready == 'true'
working-directory: ${{ env.FRONTEND_DIR }}/android
env:
KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
STORE_PASS: ${{ secrets.ANDROID_STORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEY_PASS: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
echo "$KEYSTORE_B64" | base64 -d > release.keystore
printf 'storeFile=release.keystore\nstorePassword=%s\nkeyAlias=%s\nkeyPassword=%s\n' \
"$STORE_PASS" "$KEY_ALIAS" "$KEY_PASS" > signing.properties
- name: Assemble signed release APK
if: steps.sign.outputs.ready == 'true'
working-directory: ${{ env.FRONTEND_DIR }}/android
run: |
chmod +x gradlew
./gradlew assembleRelease --no-daemon
APK="app/build/outputs/apk/release/app-release.apk"
if [ ! -f "$APK" ]; then
APK="app/build/outputs/apk/release/app-release-unsigned.apk"
fi
if [ ! -f "$APK" ]; then
echo "::error::Release APK not found"
exit 1
fi
cp "$APK" "$GITHUB_WORKSPACE/fixit-${{ steps.ver.outputs.name }}.apk"
- name: Publish GitHub Release (OTA)
if: steps.sign.outputs.ready == 'true'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.ver.outputs.tag }}
name: FixIt ${{ steps.ver.outputs.name }}
body: |
Auto-built from `${{ github.sha }}` on `${{ github.ref_name }}`.
<!-- version_code:${{ github.run_number }} -->
version_code: ${{ github.run_number }}
Deployed to https://fixit.olgtx.com together with this APK.
Installed apps check `/api/app/latest` for OTA updates.
files: fixit-${{ steps.ver.outputs.name }}.apk
make_latest: true
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}