diff --git a/ci/Jenkinsfile.android b/ci/Jenkinsfile.android index 297762ac69..88efa8f035 100644 --- a/ci/Jenkinsfile.android +++ b/ci/Jenkinsfile.android @@ -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() diff --git a/ci/Jenkinsfile.combined b/ci/Jenkinsfile.combined index ca84009477..51ba0e4b74 100644 --- a/ci/Jenkinsfile.combined +++ b/ci/Jenkinsfile.combined @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.7.8' +library 'status-jenkins-lib@v1.7.9' pipeline { agent { label 'linux' } diff --git a/ci/Jenkinsfile.ios b/ci/Jenkinsfile.ios index 5a5deab523..b5516e8ae3 100644 --- a/ci/Jenkinsfile.ios +++ b/ci/Jenkinsfile.ios @@ -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() diff --git a/ci/Jenkinsfile.nix-cache b/ci/Jenkinsfile.nix-cache index 3b84a5c640..43c4a78cfb 100644 --- a/ci/Jenkinsfile.nix-cache +++ b/ci/Jenkinsfile.nix-cache @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.7.8' +library 'status-jenkins-lib@v1.7.9' pipeline { agent { label params.AGENT_LABEL } diff --git a/ci/Jenkinsfile.tests b/ci/Jenkinsfile.tests index 318cd3ceb8..fe5591c1d0 100644 --- a/ci/Jenkinsfile.tests +++ b/ci/Jenkinsfile.tests @@ -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() diff --git a/ci/tests/Jenkinsfile.e2e-nightly b/ci/tests/Jenkinsfile.e2e-nightly index 6082eb43c4..8cc8d6e21c 100644 --- a/ci/tests/Jenkinsfile.e2e-nightly +++ b/ci/tests/Jenkinsfile.e2e-nightly @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.7.8' +library 'status-jenkins-lib@v1.7.9' pipeline { diff --git a/ci/tests/Jenkinsfile.e2e-prs b/ci/tests/Jenkinsfile.e2e-prs index 638d39f6c9..8f91460b55 100644 --- a/ci/tests/Jenkinsfile.e2e-prs +++ b/ci/tests/Jenkinsfile.e2e-prs @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.7.8' +library 'status-jenkins-lib@v1.7.9' pipeline { diff --git a/ci/tests/Jenkinsfile.e2e-upgrade b/ci/tests/Jenkinsfile.e2e-upgrade index 64b3108aaf..bc0f417541 100644 --- a/ci/tests/Jenkinsfile.e2e-upgrade +++ b/ci/tests/Jenkinsfile.e2e-upgrade @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.7.8' +library 'status-jenkins-lib@v1.7.9' pipeline { diff --git a/ci/tools/Jenkinsfile.fastlane-clean b/ci/tools/Jenkinsfile.fastlane-clean index c633e9b85b..7fde60f3d9 100644 --- a/ci/tools/Jenkinsfile.fastlane-clean +++ b/ci/tools/Jenkinsfile.fastlane-clean @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.7.8' +library 'status-jenkins-lib@v1.7.9' pipeline { agent { label 'macos' } diff --git a/ci/tools/Jenkinsfile.playstore-meta b/ci/tools/Jenkinsfile.playstore-meta index b39108554e..e473da387a 100644 --- a/ci/tools/Jenkinsfile.playstore-meta +++ b/ci/tools/Jenkinsfile.playstore-meta @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.7.8' +library 'status-jenkins-lib@v1.7.9' pipeline { agent { label 'linux' } diff --git a/ci/tools/Jenkinsfile.xcode-clean b/ci/tools/Jenkinsfile.xcode-clean index 0ae05ff855..f63bb9d352 100644 --- a/ci/tools/Jenkinsfile.xcode-clean +++ b/ci/tools/Jenkinsfile.xcode-clean @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.7.8' +library 'status-jenkins-lib@v1.7.9' pipeline { agent { diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 74e0568162..e898643c4b 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -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`' diff --git a/fastlane/Gemfile.lock b/fastlane/Gemfile.lock index dde41ee450..ab11018f01 100644 --- a/fastlane/Gemfile.lock +++ b/fastlane/Gemfile.lock @@ -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 diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile index 9bbffe01ea..0ee9978e51 100644 --- a/fastlane/Pluginfile +++ b/fastlane/Pluginfile @@ -3,4 +3,3 @@ # Ensure this file is checked in to source control! gem 'fastlane-plugin-clean_testflight_testers' -gem 'fastlane-plugin-diawi' diff --git a/fastlane/gemset.nix b/fastlane/gemset.nix index 36d78b16d7..22872a41de 100644 --- a/fastlane/gemset.nix +++ b/fastlane/gemset.nix @@ -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 = []; diff --git a/scripts/diawi-upload.mjs b/scripts/diawi-upload.mjs new file mode 100755 index 0000000000..49e9b49527 --- /dev/null +++ b/scripts/diawi-upload.mjs @@ -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()