-
Notifications
You must be signed in to change notification settings - Fork 113
251 lines (223 loc) Β· 10.7 KB
/
appetize.yml
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
name: Appetize
on:
schedule:
- cron: '0 8 * * 1' # Run every week on Monday at 08:00 UTC
workflow_dispatch:
inputs:
appetizeQueue:
type: choice
description: Appetize queue to use
default: all
options:
- all
- main
- embed
sdkPlatform:
type: choice
description: Platform to use
default: all
options:
- all
- android
- ios
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.result }}
config: ${{ steps.config.outputs.result }}
steps:
- name: π Setup repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: π Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: π Download SDK information
run: curl --silent -o ci_versions.json https://exp.host/--/api/v2/versions
- name: π΅οΈ Read Appetize information
run: bun --eval "console.log(JSON.stringify(require('./website/src/client/configs/constants.tsx').default.appetize))" > ci_appetize.json
- name: π Store Appetize config
uses: actions/github-script@v7
id: config
with:
script: return JSON.stringify(require('./ci_appetize.json'))
- name: π·ββοΈ Prepare tasks
uses: actions/github-script@v7
id: matrix
with:
script: |
// Resolve the available SDK versions and configured Appetize instances
const { sdkVersions } = require('./ci_versions.json')
const appetizePerSdk = require('./ci_appetize.json')
// Prepare the Appetize information
const appetizeSdkVersions = Object.keys(appetizePerSdk)
const appetizeSelectedQueue = 'all'
const appetizeQueues = ['main', 'embed'].filter(
name => appetizeSelectedQueue === 'all' || appetizeSelectedQueue === name
)
// Create the matrix or tasks to execute
const matrix = appetizeQueues.map(queue => (
appetizeSdkVersions.map(sdkVersion => {
// Validate that the SDK version exists
const sdkInfo = sdkVersions[sdkVersion];
if (!sdkInfo) throw new Error(`Configured Appetize SDK "${sdkVersion}" does not exist in versions endpoint`);
// Validate that the Appetize configuration is correct
const appetizeInfo = appetizePerSdk[sdkVersion][queue]
if (!appetizeInfo) throw new Error(`Configured Appetize is missing queue "${queue}"`);
if (!appetizeInfo.android) throw new Error(`Configured Appetize queue "${queue}" is missing Android`);
if (!appetizeInfo.android.publicKey) throw new Error(`Configured Appetize queue "${queue}" is missing Android's public key`);
if (!appetizeInfo.ios) throw new Error(`Configured Appetize queue "${queue}" is missing iOS`);
if (!appetizeInfo.ios.publicKey) throw new Error(`Configured Appetize queue "${queue}" is missing iOS's public key`);
return {
sdkVersion: sdkVersion,
appetizeName: queue,
appetizeTokenName: `SNACK_RUNTIME_APPETIZE_${queue.toUpperCase()}_TOKEN`,
androidAppetizeId: appetizeInfo.android.publicKey,
androidUrl: sdkInfo.androidClientUrl,
androidVersion: sdkInfo.androidClientVersion,
iosAppetizeId: appetizeInfo.ios.publicKey,
iosUrl: sdkInfo.iosClientUrl,
iosVersion: sdkInfo.iosClientVersion,
}
})
))
// Return the custom matrix or tasks to execute
return { include: matrix.flat() };
android:
if: contains('all android', github.event.inputs.sdkPlatform)
needs: prepare
name: "android (sdk: ${{ matrix.sdkVersion }}, appetize: ${{ matrix.appetizeName }})"
runs-on: ubuntu-latest
environment:
name: appetize-${{ matrix.appetizeName }}-android-${{ matrix.sdkVersion }}
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }}
steps:
- name: π Download Appetize information
# This step MUST only output `appVersionName`, the endpoint returns the public and private app keys
run: curl --silent --fail -o appetize.json https://[email protected]/v1/apps/$APP > /dev/null
env:
TOKEN: ${{ secrets[matrix.appetizeTokenName] }}
APP: ${{ matrix.androidAppetizeId }}
- name: π Resolve Appetize version
uses: actions/github-script@v7
id: appetize
with:
script: |
const latestAppVersionName = '${{ matrix.androidVersion }}';
const { appVersionName } = require('./appetize.json') || {};
if (!appVersionName) throw new Error('Invalid Appetize response')
if (appVersionName === latestAppVersionName) {
core.info(`Appetize (${{ matrix.appetizeName }}) is running Android ${appVersionName} (latest) for ${{ matrix.sdkVersion }}`)
} else {
core.info(`Appetize (${{ matrix.appetizeName }}) is running Android ${appVersionName} (-> ${latestAppVersionName}) for ${{ matrix.sdkVersion }}`)
}
core.setOutput('oldVersion', appVersionName)
- name: π± Download Android client (${{ matrix.androidVersion }})
if: ${{ steps.appetize.outputs.oldVersion != matrix.androidVersion }}
run: curl -o exponent-android.apk ${{ matrix.androidUrl }}
- name: π Upload to Appetize
if: ${{ steps.appetize.outputs.oldVersion != matrix.androidVersion }}
# This step MUST NOT output anything, the endpoint returns the public and private app keys
run: |
curl --silent --fail --http1.1 https://[email protected]/v1/apps/$APP -F "[email protected]" -F "platform=android" > /dev/null
rm -rf exponent-android.apk appetize.json
env:
TOKEN: ${{ secrets[matrix.appetizeTokenName] }}
APP: ${{ matrix.androidAppetizeId }}
ios:
if: contains('all ios', github.event.inputs.sdkPlatform)
needs: prepare
name: "ios (sdk: ${{ matrix.sdkVersion }}, appetize: ${{ matrix.appetizeName }})"
runs-on: ubuntu-latest
environment:
name: appetize-${{ matrix.appetizeName }}-ios-${{ matrix.sdkVersion }}
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }}
steps:
- name: π Download Appetize information
# This step MUST only output `appVersionName`, the endpoint returns the public and private app keys
run: curl --silent --fail -o appetize.json https://[email protected]/v1/apps/$APP > /dev/null
env:
TOKEN: ${{ secrets[matrix.appetizeTokenName] }}
APP: ${{ matrix.iosAppetizeId }}
- name: π Resolve Appetize version
uses: actions/github-script@v7
id: appetize
with:
script: |
const latestAppVersionName = '${{ matrix.androidVersion }}';
const { appVersionName } = require('./appetize.json') || {};
if (!appVersionName) throw new Error('Invalid Appetize response')
if (appVersionName === latestAppVersionName) {
core.info(`Appetize (${{ matrix.appetizeName }}) is running iOS ${appVersionName} (latest) for ${{ matrix.sdkVersion }}`)
} else {
core.info(`Appetize (${{ matrix.appetizeName }}) is running iOS ${appVersionName} (-> ${latestAppVersionName}) for ${{ matrix.sdkVersion }}`)
}
core.setOutput('oldVersion', appVersionName)
- name: π± Download iOS client (${{ matrix.iosVersion }})
if: ${{ steps.appetize.outputs.oldVersion != matrix.iosVersion }}
run: curl -o exponent-ios.tar.gz ${{ matrix.iosUrl }}
- name: π¦ Prepare iOS package
if: ${{ steps.appetize.outputs.oldVersion != matrix.iosVersion }}
run: |
mkdir exponent-ios.app
tar -xf exponent-ios.tar.gz -C exponent-ios.app
zip -q -r exponent-ios.zip exponent-ios.app
rm -rf exponent-ios.app exponent-ios.tar.gz
- name: π Upload to Appetize
if: ${{ steps.appetize.outputs.oldVersion != matrix.iosVersion }}
# This step MUST NOT output anything, the endpoint returns the public and private app keys
run: |
curl --silent --fail --http1.1 https://[email protected]/v1/apps/$APP -F "[email protected]" -F "platform=ios" > /dev/null
rm -rf exponent-ios.zip appetize.json
env:
TOKEN: ${{ secrets[matrix.appetizeTokenName] }}
APP: ${{ matrix.iosAppetizeId }}
config:
runs-on: ubuntu-latest
needs: prepare
steps:
- name: π Download Appetize devices
run: curl -o appetize-devices.json https://api.appetize.io/v2/service/devices
- name: π Validate default devices
uses: actions/github-script@v7
with:
script: |
// Load the downloaded devices and resolved config
const devices = require('./appetize-devices.json');
const config = JSON.parse(${{ needs.prepare.outputs.config }});
// Iterate over each configured Appetize instance
for (const [sdkVersion, sdkConfig] of Object.entries(config)) {
for (const [queueName, queueConfig] of Object.entries(sdkConfig)) {
for (const [platform, platformConfig] of Object.entries(queueConfig)) {
// Ensure the default device is available on Appetize
const defaultDevice = platformConfig.device;
const foundDevice = devices.find(device => device.id === defaultDevice);
// Throw an error if the default device is not available
if (!foundDevice) {
throw new Error(`Default device "${defaultDevice}" for ${platform} on ${queueName} (${sdkVersion}) is not available on Appetize`);
}
}
}
}
notify:
if: ${{ always() }}
needs: [prepare, android, ios, config]
runs-on: ubuntu-latest
steps:
- name: π’ Notify on Slack
uses: 8398a7/action-slack@v3
if: ${{ needs.prepare.result == 'failure' || needs.android.result == 'failure' || needs.ios.result == 'failure' || needs.config.result == 'failure' }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_SNACK }}
with:
channel: '#snack'
status: failure
author_name: Appetize deployment failed
fields: author,job