ios: replace Diawi Fastlane plugin that disappered

For an unknown reason the original Diawi plugin for Fastlane has been
removed from GitHub and RubyGems pages and can no longer be used.

This replaces it with a Node.js script which does the same job.

I tried using `diawi` and `diawi-nodejs-uploader` but both had issues,
one of them being depending on far too many useless packages.

Resolves: https://github.com/status-im/status-mobile/issues/15951

Signed-off-by: Jakub Sokołowski <jakub@status.im>
This commit is contained in:
Jakub Sokołowski 2023-05-19 09:44:22 +02:00
parent 56d0913d4b
commit 2493b8ad4b
No known key found for this signature in database
GPG Key ID: FE65CD384D5BF7B4
16 changed files with 155 additions and 136 deletions

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
pipeline {
agent { label 'linux' }

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
pipeline {
agent { label params.AGENT_LABEL }

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
/* Options section can't access functions in objects. */
def isPRBuild = utils.isPRBuild()

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
pipeline {

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
pipeline {

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
pipeline {

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
pipeline {
agent { label 'macos' }

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
pipeline {
agent { label 'linux' }

View File

@ -1,4 +1,4 @@
library 'status-jenkins-lib@v1.7.8'
library 'status-jenkins-lib@v1.7.9'
pipeline {
agent {

View File

@ -182,17 +182,6 @@ def build_ios_e2e
)
end
def upload_to_diawi(source)
diawi(
file: source,
timeout: 120,
check_status_delay: 5,
token: ENV['DIAWI_TOKEN']
)
# save the URL to a file for use in CI
File.write('diawi.out', lane_context[SharedValues::UPLOADED_FILE_LINK_TO_DIAWI])
end
platform :ios do
desc '`fastlane ios adhoc` - ad-hoc lane for iOS.'
desc 'This lane is used for PRs, Releases, etc.'
@ -265,18 +254,6 @@ platform :ios do
# In the future we can try using 'oldest_build_allowed'
end
desc '`fastlane ios upload-diawi` - upload .ipa to diawi'
desc 'expects to have an .ipa prepared: `status-ios/StatusIm.ipa`'
desc 'expects to have a diawi token as DIAWI_TOKEN env variable'
desc 'expects to have a github token as GITHUB_TOKEN env variable'
desc "will fails if file isn't there"
desc '---'
desc 'Output: writes `fastlane/diawi.out` file url of the uploded file'
lane :upload_diawi do
ipa = ENV['DIAWI_IPA'] || 'status-ios/StatusIm.ipa'
upload_to_diawi(ipa)
end
desc '`fastlane ios saucelabs` - upload .app to sauce labs'
desc 'also notifies in a GitHub comments'
desc 'expects to have an .apk prepared: `result/app.apk`'

View File

@ -3,21 +3,21 @@ GEM
specs:
CFPropertyList (3.0.6)
rexml
addressable (2.8.1)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.728.0)
aws-sdk-core (3.170.0)
aws-partitions (1.766.0)
aws-sdk-core (3.173.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.63.0)
aws-sdk-kms (1.64.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.119.1)
aws-sdk-s3 (1.122.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@ -66,7 +66,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.212.1)
fastlane (2.212.2)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@ -106,10 +106,8 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-clean_testflight_testers (0.3.0)
fastlane-plugin-diawi (2.1.0)
rest-client (>= 2.0.0)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.36.0)
google-apis-androidpublisher_v3 (0.42.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.0)
addressable (~> 2.5, >= 2.5.1)
@ -140,7 +138,7 @@ GEM
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.3.0)
googleauth (1.5.2)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
@ -148,7 +146,6 @@ GEM
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
http-accept (1.7.0)
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
@ -156,16 +153,12 @@ GEM
json (2.6.3)
jwt (2.7.0)
memoist (0.16.2)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.0218.1)
mini_magick (4.12.0)
mini_mime (1.1.2)
multi_json (1.15.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
naturally (2.2.1)
netrc (0.11.0)
optparse (0.1.1)
os (1.1.4)
plist (3.7.0)
@ -175,11 +168,6 @@ GEM
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
retriable (3.1.2)
rexml (3.2.5)
rouge (2.0.7)
@ -227,7 +215,6 @@ PLATFORMS
DEPENDENCIES
fastlane (>= 2.131.0)
fastlane-plugin-clean_testflight_testers
fastlane-plugin-diawi
BUNDLED WITH
2.4.6
2.3.9

View File

@ -3,4 +3,3 @@
# Ensure this file is checked in to source control!
gem 'fastlane-plugin-clean_testflight_testers'
gem 'fastlane-plugin-diawi'

View File

@ -5,10 +5,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1ypdmpdn20hxp5vwxz3zc04r5xcwqc25qszdlg41h8ghdqbllwmw";
sha256 = "15s8van7r2ad3dq6i03l3z4hqnvxcq75a3h72kxvf9an53sqma20";
type = "gem";
};
version = "2.8.1";
version = "2.8.4";
};
artifactory = {
groups = ["default"];
@ -45,10 +45,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0q3q19insq5ablmr6ypq033qg1gsar5mdphhp7xg80rd615cnq97";
sha256 = "0x7v4v8hj0pbzw3x1iv07x8v93fcs74svlhzv7vl6laxm4mc6858";
type = "gem";
};
version = "1.728.0";
version = "1.766.0";
};
aws-sdk-core = {
dependencies = ["aws-eventstream" "aws-partitions" "aws-sigv4" "jmespath"];
@ -56,10 +56,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0zc4zhv2wq7s5p8c9iaplama1lpg2kwldg81j83c8w4xydf1wd2r";
sha256 = "10djgbz4k9w3axka8xrhf97h9yh9svi5g5xvncfwnkg6h22w2177";
type = "gem";
};
version = "3.170.0";
version = "3.173.0";
};
aws-sdk-kms = {
dependencies = ["aws-sdk-core" "aws-sigv4"];
@ -67,10 +67,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0v87zi28dfmrv7bv91yfldccnpd63n295siirbz7wqv1rajn8n02";
sha256 = "1bcm0c9f7xy5qj5f0z3gddqslhb2vzrj9smc39pgqyq4jmn5kpj0";
type = "gem";
};
version = "1.63.0";
version = "1.64.0";
};
aws-sdk-s3 = {
dependencies = ["aws-sdk-core" "aws-sdk-kms" "aws-sigv4"];
@ -78,10 +78,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1rpnlzsl52znhcki13jkwdshgwf51pn26267481f4fa842gr7xgp";
sha256 = "01cryf8kfkmlsxb327szcwcagsp7lss5gmk6zxlgap65lv8bc7rx";
type = "gem";
};
version = "1.119.1";
version = "1.122.0";
};
aws-sigv4 = {
dependencies = ["aws-eventstream"];
@ -368,10 +368,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0b22m2dkydyv2si55b1jzznzgxf2ycx2aarv1j5p25k861h2gsml";
sha256 = "15sa3v3aaslympg9nmadmpxpbzykdiybzxn3navc7mf0iscb3q7s";
type = "gem";
};
version = "2.212.1";
version = "2.212.2";
};
fastlane-plugin-clean_testflight_testers = {
groups = ["default"];
@ -383,17 +383,6 @@
};
version = "0.3.0";
};
fastlane-plugin-diawi = {
dependencies = ["rest-client"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1sjznx9hwlfa7ndv7av870dvl0cvmh68yk381r55ylw4jjvk5mwl";
type = "gem";
};
version = "2.1.0";
};
gh_inspector = {
groups = ["default"];
platforms = [];
@ -410,10 +399,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1mbnmn36z1cnsd6ar76p9wvqi0ac6wlpm1p1lqczivain16qma76";
sha256 = "0ks2ak4fcvlflhyinykvd88g2ybxwsbc347aww349zhn1mqprbvg";
type = "gem";
};
version = "0.36.0";
version = "0.42.0";
};
google-apis-core = {
dependencies = ["addressable" "googleauth" "httpclient" "mini_mime" "representable" "retriable" "rexml" "webrick"];
@ -508,10 +497,10 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1hpwgwhk0lmnknkw8kbdfxn95qqs6aagpq815l5fkw9w6mi77pai";
sha256 = "1lj5haarpn7rybbq9s031zcn9ji3rlz5bk64bwa2j34q5s1h5gis";
type = "gem";
};
version = "1.3.0";
version = "1.5.2";
};
highline = {
groups = ["default"];
@ -523,16 +512,6 @@
};
version = "2.0.3";
};
http-accept = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "09m1facypsdjynfwrcv19xcb1mqg8z6kk31g8r33pfxzh838c9n6";
type = "gem";
};
version = "1.7.0";
};
http-cookie = {
dependencies = ["domain_name"];
groups = ["default"];
@ -594,27 +573,6 @@
};
version = "0.16.2";
};
mime-types = {
dependencies = ["mime-types-data"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0ipw892jbksbxxcrlx9g5ljq60qx47pm24ywgfbyjskbcl78pkvb";
type = "gem";
};
version = "3.4.1";
};
mime-types-data = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1pky3vzaxlgm9gw5wlqwwi7wsw3jrglrfflrppvvnsrlaiz043z9";
type = "gem";
};
version = "3.2023.0218.1";
};
mini_magick = {
groups = ["default"];
platforms = [];
@ -675,16 +633,6 @@
};
version = "2.2.1";
};
netrc = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0gzfmcywp1da8nzfqsql2zqi648mfnx6qwkig3cv36n9m0yy676y";
type = "gem";
};
version = "0.11.0";
};
optparse = {
groups = ["default"];
platforms = [];
@ -746,17 +694,6 @@
};
version = "3.2.0";
};
rest-client = {
dependencies = ["http-accept" "http-cookie" "mime-types" "netrc"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1qs74yzl58agzx9dgjhcpgmzfn61fqkk33k1js2y5yhlvc5l19im";
type = "gem";
};
version = "2.1.0";
};
retriable = {
groups = ["default"];
platforms = [];

119
scripts/diawi-upload.mjs Executable file
View File

@ -0,0 +1,119 @@
#!/usr/bin/env node
import https from 'node:https'
import { basename } from 'node:path'
import { promisify } from 'node:util'
import { createReadStream } from 'node:fs'
import log from 'npmlog'
import FormData from 'form-data'
const UPLOAD_URL = 'https://upload.diawi.com/'
const STATUS_URL = 'https://upload.diawi.com/status'
const POLL_MAX_COUNT = 10
const POLL_INTERVAL_MS = 700
const sleep = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(resolve, (ms))
})
}
const getRequest = async (url) => {
return new Promise((resolve, reject) => {
let data = []
https.get(url, res => {
res.on('error', err => reject(err))
res.on('data', chunk => { data.push(chunk) })
res.on('end', () => {
let payload = Buffer.concat(data).toString()
resolve({
code: res.statusCode,
message: res.statusMessage,
payload: payload,
})
})
})
})
}
const uploadIpa = async (ipaPath, comment, token) => {
let form = new FormData()
form.append('token', token)
form.append('file', createReadStream(ipaPath))
form.append('comment', comment || basename(ipaPath))
const formSubmitPromise = promisify(form.submit.bind(form))
const res = await formSubmitPromise(UPLOAD_URL)
if (res.statusCode != 200) {
log.error('uploadIpa', 'Upload failed: %d %s', res.statusCode, res.statusMessage)
process.exit(1)
}
return new Promise((resolve) => {
const jobId = res.on('data', async (data) => {
resolve(JSON.parse(data)['job'])
})
})
}
const checkStatus = async (jobId, token) => {
let params = new URLSearchParams({
token: token, job: jobId,
})
let rval = await getRequest(`${STATUS_URL}?${params.toString()}`)
if (rval.code != 200) {
log.error('checkStatus', 'Check query failed: %d %s', rval.code, rval.message)
process.exit(1)
}
return JSON.parse(rval.payload)
}
const pollStatus = async (jobId, token) => {
let interval = POLL_INTERVAL_MS
for (let i = 0; i <= POLL_MAX_COUNT; i++) {
let json = await checkStatus(jobId, token)
switch (json.status) {
case 2000:
return json
case 2001:
log.verbose('pollStatus', 'Waiting: %s', json.message)
break /* Nothing, just poll again. */
case 4000000:
log.warning('pollStatus', 'Doubling polling interval: %s', json.message)
interval *= 2
break
default:
log.error('pollStatus', `Error in status response: ${json.message}`)
process.exit(1)
}
await sleep(interval)
}
}
const main = async () => {
const token = process.env.DIAWI_TOKEN
const targetFile = process.argv[2]
const comment = process.argv[3]
log.level = process.env.VERBOSE ? 'verbose' : 'info'
if (token === undefined) {
log.error('main', 'No DIAWI_TOKEN env var provided!')
process.exit(1)
}
if (targetFile === undefined) {
log.error('main', 'No file path provided!')
process.exit(1)
}
log.info('main', 'Uploading: %s', targetFile)
let jobId = await uploadIpa(targetFile, comment, token)
log.info('main', 'Polling upload job status: %s', jobId)
let uploadMeta = await pollStatus(jobId, token)
console.log(uploadMeta)
}
main()