Skip to content

Commit 22ca296

Browse files
committed
ios: upload to Diawi
1 parent efd0e5f commit 22ca296

File tree

3 files changed

+138
-1
lines changed

3 files changed

+138
-1
lines changed

ci/Jenkinsfile.ios

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,21 @@ pipeline {
120120

121121
stage('Parallel Upload') {
122122
parallel {
123-
stage('Upload') {
123+
stage('Upload to S3') {
124124
steps {
125125
script {
126126
env.PKG_URL = s5cmd.upload(env.STATUS_IOS_APP_ARTIFACT)
127+
}
128+
}
129+
}
130+
stage('Upload to Diawi') {
131+
when {
132+
expression { return !isReleaseBranch }
133+
}
134+
steps {
135+
script {
136+
env.DIAWI_URL = app.uploadToDiawi(ipaPath: env.STATUS_IOS_APP_ARTIFACT)
137+
env.PKG_URL = env.DIAWI_URL
127138
jenkins.setBuildDesc(IPA: env.PKG_URL)
128139
}
129140
}

scripts/diawi-upload.mjs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/usr/bin/env node
2+
3+
import https from 'node:https'
4+
import { basename } from 'node:path'
5+
import { promisify } from 'node:util'
6+
import { createReadStream } from 'node:fs'
7+
8+
import log from 'npmlog'
9+
import FormData from 'form-data'
10+
11+
const UPLOAD_URL = 'https://upload.diawi.com/'
12+
const STATUS_URL = 'https://upload.diawi.com/status'
13+
const POLL_MAX_COUNT = 10
14+
const POLL_INTERVAL_MS = 700
15+
16+
const sleep = (ms) => {
17+
return new Promise((resolve, reject) => {
18+
setTimeout(resolve, (ms))
19+
})
20+
}
21+
22+
const getRequest = async (url) => {
23+
return new Promise((resolve, reject) => {
24+
let data = []
25+
https.get(url, res => {
26+
res.on('error', err => reject(err))
27+
res.on('data', chunk => { data.push(chunk) })
28+
res.on('end', () => {
29+
let payload = Buffer.concat(data).toString()
30+
resolve({
31+
code: res.statusCode,
32+
message: res.statusMessage,
33+
payload: payload,
34+
})
35+
})
36+
})
37+
})
38+
}
39+
40+
const uploadIpa = async (ipaPath, comment, token) => {
41+
let form = new FormData()
42+
form.append('token', token)
43+
form.append('file', createReadStream(ipaPath))
44+
form.append('comment', comment || basename(ipaPath))
45+
46+
const formSubmitPromise = promisify(form.submit.bind(form))
47+
48+
const res = await formSubmitPromise(UPLOAD_URL)
49+
if (res.statusCode != 200) {
50+
log.error('uploadIpa', 'Upload failed: %d %s', res.statusCode, res.statusMessage)
51+
process.exit(1)
52+
}
53+
54+
return new Promise((resolve) => {
55+
const jobId = res.on('data', async (data) => {
56+
resolve(JSON.parse(data)['job'])
57+
})
58+
})
59+
}
60+
61+
const checkStatus = async (jobId, token) => {
62+
let params = new URLSearchParams({
63+
token: token, job: jobId,
64+
})
65+
let rval = await getRequest(`${STATUS_URL}?${params.toString()}`)
66+
if (rval.code != 200) {
67+
log.error('checkStatus', 'Check query failed: %d %s', rval.code, rval.message)
68+
process.exit(1)
69+
}
70+
return JSON.parse(rval.payload)
71+
}
72+
73+
const pollStatus = async (jobId, token) => {
74+
let interval = POLL_INTERVAL_MS
75+
for (let i = 0; i <= POLL_MAX_COUNT; i++) {
76+
let json = await checkStatus(jobId, token)
77+
switch (json.status) {
78+
case 2000:
79+
return json
80+
case 2001:
81+
log.verbose('pollStatus', 'Waiting: %s', json.message)
82+
break /* Nothing, just poll again. */
83+
case 4000000:
84+
log.warning('pollStatus', 'Doubling polling interval: %s', json.message)
85+
interval *= 2
86+
break
87+
default:
88+
log.error('pollStatus', `Error in status response: ${json.message}`)
89+
process.exit(1)
90+
}
91+
await sleep(interval)
92+
}
93+
}
94+
95+
const main = async () => {
96+
const token = process.env.DIAWI_TOKEN
97+
const targetFile = process.argv[2]
98+
const comment = process.argv[3]
99+
log.level = process.env.VERBOSE ? 'verbose' : 'info'
100+
101+
if (token === undefined) {
102+
log.error('main', 'No DIAWI_TOKEN env var provided!')
103+
process.exit(1)
104+
}
105+
if (targetFile === undefined) {
106+
log.error('main', 'No file path provided!')
107+
process.exit(1)
108+
}
109+
110+
log.info('main', 'Uploading: %s', targetFile)
111+
let jobId = await uploadIpa(targetFile, comment, token)
112+
113+
log.info('main', 'Polling upload job status: %s', jobId)
114+
let uploadMeta = await pollStatus(jobId, token)
115+
116+
console.log(uploadMeta)
117+
}
118+
119+
main()

shell.nix

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ in pkgs.mkShell {
3232
go_1_22 go-bindata mockgen protobuf3_20 protoc-gen-go
3333
nss pcsclite extra-cmake-modules
3434
xorg.libxcb xorg.libX11 libxkbcommon
35+
nodejs # Required for Diawi upload script
3536
] ++ (with gst_all_1; [
3637
gst-libav gstreamer
3738
gst-plugins-bad gst-plugins-base
@@ -51,6 +52,12 @@ in pkgs.mkShell {
5152
shellHook = ''
5253
export MAKEFLAGS="-j$NIX_BUILD_CORES"
5354
export PATH="${pkgs.lddWrapped}/bin:$PATH"
55+
56+
# Install npm dependencies for Diawi upload if not already present
57+
if ! npm list -g npmlog &> /dev/null || ! npm list -g form-data &> /dev/null; then
58+
echo "Installing npm dependencies for Diawi upload..."
59+
npm install -g npmlog form-data
60+
fi
5461
'';
5562

5663
LIBKRB5_PATH = pkgs.libkrb5;

0 commit comments

Comments
 (0)