From 05929a16c7bb5cfa2ac6e1fec32cdf9935a92a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Fri, 19 May 2023 09:44:22 +0200 Subject: [PATCH] ios: replace Diawi Fastlane plugin that disappered MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- ci/Jenkinsfile.android | 3 +- ci/Jenkinsfile.combined | 4 +- ci/Jenkinsfile.ios | 8 +- ci/Jenkinsfile.nix-cache | 2 +- ci/Jenkinsfile.tests | 33 +++-- ci/tests/Jenkinsfile.e2e-nightly | 30 ++++- ci/tests/Jenkinsfile.e2e-prs | 61 ++++++--- ci/tests/Jenkinsfile.e2e-upgrade | 31 ++++- ci/tools/Jenkinsfile.fastlane-clean | 2 +- ci/tools/Jenkinsfile.playstore-meta | 2 +- ci/tools/Jenkinsfile.xcode-clean | 47 +++++++ fastlane/Fastfile | 23 ---- fastlane/Gemfile.lock | 107 +++++++-------- fastlane/Pluginfile | 1 - fastlane/gemset.nix | 195 ++++++++++------------------ scripts/diawi-upload.mjs | 119 +++++++++++++++++ 16 files changed, 404 insertions(+), 264 deletions(-) create mode 100644 ci/tools/Jenkinsfile.xcode-clean create mode 100755 scripts/diawi-upload.mjs diff --git a/ci/Jenkinsfile.android b/ci/Jenkinsfile.android index 012fba4680..88efa8f035 100644 --- a/ci/Jenkinsfile.android +++ b/ci/Jenkinsfile.android @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.6.6' +library 'status-jenkins-lib@v1.7.9' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() @@ -49,7 +49,6 @@ pipeline { stage('Prep') { steps { script { - utils.doGitRebasePR() utils.symlinkEnv() println("Build Number: ${utils.genBuildNumber()}") } diff --git a/ci/Jenkinsfile.combined b/ci/Jenkinsfile.combined index a4e687fe72..51ba0e4b74 100644 --- a/ci/Jenkinsfile.combined +++ b/ci/Jenkinsfile.combined @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.6.6' +library 'status-jenkins-lib@v1.7.9' pipeline { agent { label 'linux' } @@ -19,7 +19,7 @@ pipeline { } /* WARNING: Defining parameters here with the ?: trick causes them to remember last value. */ - parameters { + parameters { choice( name: 'BUILD_TYPE', description: 'Makefile target to build. Optional Parameter.', diff --git a/ci/Jenkinsfile.ios b/ci/Jenkinsfile.ios index 43a7c1be62..b5516e8ae3 100644 --- a/ci/Jenkinsfile.ios +++ b/ci/Jenkinsfile.ios @@ -1,10 +1,10 @@ -library 'status-jenkins-lib@v1.6.6' +library 'status-jenkins-lib@v1.7.9' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() pipeline { - agent { label 'macos && arm64 && nix-2.11 && xcode-14.2' } + agent { label 'macos && arm64 && nix-2.11 && xcode-14.3' } parameters { string( @@ -48,7 +48,6 @@ pipeline { stage('Prep') { steps { script { - utils.doGitRebasePR() utils.symlinkEnv() println("Build Number: ${utils.genBuildNumber()}") } @@ -63,6 +62,9 @@ pipeline { steps { script { api = ios.bundle() } } + post { + failure { archiveArtifacts 'ios/logs/*' } + } } stage('Parallel Upload') { parallel { diff --git a/ci/Jenkinsfile.nix-cache b/ci/Jenkinsfile.nix-cache index d6e13c4014..43c4a78cfb 100644 --- a/ci/Jenkinsfile.nix-cache +++ b/ci/Jenkinsfile.nix-cache @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.5.5' +library 'status-jenkins-lib@v1.7.9' pipeline { agent { label params.AGENT_LABEL } diff --git a/ci/Jenkinsfile.tests b/ci/Jenkinsfile.tests index 4e4c2e9cdd..fe5591c1d0 100644 --- a/ci/Jenkinsfile.tests +++ b/ci/Jenkinsfile.tests @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.5.5' +library 'status-jenkins-lib@v1.7.9' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() @@ -9,7 +9,7 @@ pipeline { options { timestamps() /* Prevent Jenkins jobs from running forever */ - timeout(time: 10, unit: 'MINUTES') + timeout(time: 15, unit: 'MINUTES') /* Limit builds retained */ buildDiscarder(logRotator( numToKeepStr: '10', @@ -41,23 +41,34 @@ pipeline { } stages { - stage('Prep') { - steps { - script { - utils.doGitRebasePR() - } - } - } stage('Checks') { parallel { stage('Lint') { - steps { sh "make lint > ${LOG_FILE}" } + steps { + sh """#!/bin/bash + set -eo pipefail + make lint 2>&1 | tee ${LOG_FILE} + """ + } } stage('Tests') { - steps { sh "make test >> ${LOG_FILE}" } + steps { + sh """#!/bin/bash + set -eo pipefail + make test 2>&1 | tee -a ${LOG_FILE} + """ + } } } } + stage('Component Tests') { + steps { + sh """#!/bin/bash + set -eo pipefail + make component-test 2>&1 | tee -a ${LOG_FILE} + """ + } + } stage('Upload') { steps { script { diff --git a/ci/tests/Jenkinsfile.e2e-nightly b/ci/tests/Jenkinsfile.e2e-nightly index d686c5de54..8cc8d6e21c 100644 --- a/ci/tests/Jenkinsfile.e2e-nightly +++ b/ci/tests/Jenkinsfile.e2e-nightly @@ -1,11 +1,13 @@ +library 'status-jenkins-lib@v1.7.9' + pipeline { agent { label 'linux' } parameters { string( - name: 'APK_NAME', - description: 'Filename of APK uploaded to SauceLabs.', + name: 'APK_URL', + description: 'URL of APK uploaded to SauceLabs.', ) string( name: 'KEYWORD_EXPRESSION', @@ -18,8 +20,20 @@ pipeline { disableConcurrentBuilds() } - stages { + stage('Fetch') { + when { expression { !params.APK_URL } } + steps { script { + copyArtifacts( + projectName: "status-mobile/nightly", + filter: '*-x86.apk', + /* WARNING: This copies the latest available artifact. */ + selector: lastWithArtifacts(), + ) + apk_path = "${env.WORKSPACE}/${utils.findFile('*-x86.apk')}" + } } + } + stage('Setup') { steps { script { dir('test/appium') { @@ -27,6 +41,7 @@ pipeline { } } } } + stage('Test') { steps { withCredentials([ @@ -58,13 +73,13 @@ pipeline { sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py' sh """ python3 -m pytest \ - --numprocesses 9 \ + --numprocesses 4 \ --rerun_count=2 \ --testrail_report=True \ -m testrail_id \ - -m \"not upgrade\" \ + -m \"new_ui_critical or new_ui_medium\" \ -k \"${params.KEYWORD_EXPRESSION}\" \ - --apk=${params.APK_NAME} + --apk=${params.APK_URL ?: apk_path} """ } } @@ -88,5 +103,8 @@ pipeline { ) } } + cleanup { + sh 'make purge' + } } } diff --git a/ci/tests/Jenkinsfile.e2e-prs b/ci/tests/Jenkinsfile.e2e-prs index d50974c671..8f91460b55 100644 --- a/ci/tests/Jenkinsfile.e2e-prs +++ b/ci/tests/Jenkinsfile.e2e-prs @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.5.5' +library 'status-jenkins-lib@v1.7.9' pipeline { @@ -10,20 +10,14 @@ pipeline { description: 'Name of the branch to checkout and build.', defaultValue: 'develop', ) -/* Commented to use TEST_MARKERS values from job params - string( - name: 'TEST_MARKERS', - description: 'Marker expression for matching tests to run.', - defaultValue: 'critical', - ) */ - string( - name: 'APK_NAME', - description: 'Filename of APK uploaded to SauceLabs, path, or URL.', - ) string( name: 'PR_ID', description: 'ID of the Pull Request triggering this build.', ) + string( + name: 'APK_URL', + description: 'Optional, set if job require APK to be downloaded from URL.', + ) string( name: 'KEYWORD_EXPRESSION', description: 'This will run tests which contain names that match the given string expression (Optional)', @@ -34,6 +28,19 @@ pipeline { description: 'IDs of the TestRail case, separated by a comma (Optional)', defaultValue: '', ) + /* FIXME: Remove this no longer relevant argument */ + string( + name: 'APK_NAME', + description: 'OBSOLETE ARGUMENT TO BE REMOVED', + defaultValue: 'DUMMY', + ) + /* Commented to use TEST_MARKERS values from job params + string( + name: 'TEST_MARKERS', + description: 'Marker expression for matching tests to run.', + defaultValue: 'new_ui_critical', + ) + */ } options { @@ -41,12 +48,27 @@ pipeline { } stages { - stage('Checks') { + stage('Prep') { steps { script { - if (params.APK_NAME == null) { error("APK_NAME parameter not set!") } - if (params.PR_ID == null) { error("PR_ID parameter not set!") } + currentBuild.displayName = "PR-${params.PR_ID}" + if (params.PR_ID == null) { + error("PR_ID parameter not set!") + } } } } + + stage('Fetch') { + when { expression { !params.APK_URL } } + steps { script { + copyArtifacts( + projectName: "status-mobile/prs/android-e2e/PR-${params.PR_ID}", + /* WARNING: This copies the latest available artifact. */ + selector: lastWithArtifacts(), + ) + apk_path = "${env.WORKSPACE}/${utils.findFile('result/*.apk')}" + } } + } + stage('Setup') { steps { script { dir('test/appium') { @@ -54,9 +76,9 @@ pipeline { } } } } + stage('Test') { steps { script { - currentBuild.displayName = "PR-${params.PR_ID}" /* for managing optional arguments */ def extraPytestOpts = '' if (params.TR_CASE_IDS != '') { @@ -99,11 +121,11 @@ pipeline { sh 'cp -f $TEST_ETH_ACCOUNTS_FILE users.py' sh """ python3 -m pytest \ - --numprocesses 9 \ + --numprocesses 4 \ --rerun_count=2 \ --testrail_report=True \ -k \"${params.KEYWORD_EXPRESSION}\" \ - --apk=${params.APK_NAME} \ + --apk=${params.APK_URL ?: apk_path} \ --build=PR-${params.PR_ID}-${utils.timestamp()} \ --pr_number=${params.PR_ID} \ ${extraPytestOpts} @@ -113,4 +135,9 @@ pipeline { } } } } + post { + cleanup { + sh 'make purge' + } + } } diff --git a/ci/tests/Jenkinsfile.e2e-upgrade b/ci/tests/Jenkinsfile.e2e-upgrade index 29ba1bfcb7..bc0f417541 100644 --- a/ci/tests/Jenkinsfile.e2e-upgrade +++ b/ci/tests/Jenkinsfile.e2e-upgrade @@ -1,15 +1,17 @@ +library 'status-jenkins-lib@v1.7.9' + pipeline { agent { label 'linux' } parameters { string( - name: 'APK_NAME', - description: 'Filename of APK uploaded to SauceLabs (base for upgrade, usually release build)', + name: 'APK_URL', + description: 'URL of APK to be tested(base for upgrade, usually release build)', ) string( - name: 'APK_NAME_UPGRADE', - description: 'Filename of APK of upgraded application (installed on top of base)', + name: 'APK_URL_UPGRADE', + description: 'URL of APK of upgraded application (installed on top of base)', ) string( name: 'KEYWORD_EXPRESSION', @@ -29,6 +31,17 @@ pipeline { stages { + stage('Prep') { + steps { script { + if (params.APK_URL == null) { + error("APK_URL parameter not set!") + } + if (params.APK_URL_UPGRADE == null) { + error("APK_URL_UPGRADE parameter not set!") + } + } } + } + stage('Setup') { steps { script { dir('test/appium') { @@ -36,6 +49,7 @@ pipeline { } } } } + stage('Test') { steps { script { /* for managing optional arguments */ @@ -74,11 +88,11 @@ pipeline { python3 -m pytest \ -m "upgrade" \ -k \"${params.KEYWORD_EXPRESSION}\" \ - --numprocesses 15 \ + --numprocesses 4 \ --rerun_count=2 \ --testrail_report=True \ - --apk=${params.APK_NAME} \ - --apk_upgrade=${params.APK_NAME_UPGRADE} \ + --apk=${params.APK_URL} \ + --apk_upgrade=${params.APK_URL_UPGRADE} \ ${extraPytestOpts} """ } @@ -103,5 +117,8 @@ pipeline { ) } } + cleanup { + sh 'make purge' + } } } diff --git a/ci/tools/Jenkinsfile.fastlane-clean b/ci/tools/Jenkinsfile.fastlane-clean index e2294af8e9..7fde60f3d9 100644 --- a/ci/tools/Jenkinsfile.fastlane-clean +++ b/ci/tools/Jenkinsfile.fastlane-clean @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.5.5' +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 cff0d30b82..e473da387a 100644 --- a/ci/tools/Jenkinsfile.playstore-meta +++ b/ci/tools/Jenkinsfile.playstore-meta @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.5.5' +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 new file mode 100644 index 0000000000..f63bb9d352 --- /dev/null +++ b/ci/tools/Jenkinsfile.xcode-clean @@ -0,0 +1,47 @@ +library 'status-jenkins-lib@v1.7.9' + +pipeline { + agent { + label 'linux' + } + + triggers { + cron('H 5 * * *') + } + + options { + timestamps() + /* Prevent Jenkins jobs from running forever */ + timeout(time: 15, unit: 'MINUTES') + /* Disable concurrent jobs */ + disableConcurrentBuilds() + /* Don't keep more than 50 builds */ + buildDiscarder(logRotator(numToKeepStr: '10')) + } + + stages { + stage('Get Nodes') { + steps { script { + stagePerNode = nodesByLabel('macos').collectEntries { + ["${it}" : generateNodeCleanupStage(it)] + } + } } + } + + stage('Clean Xcode') { + steps { script { + parallel stagePerNode + } } + } + } +} + +def generateNodeCleanupStage(nodeLabel) { + return { stage(nodeLabel) { + node(nodeLabel) { + dir('/Users/jenkins/Library/Developer/Xcode') { + sh 'rm -fr Archives DerivedData' + } + } + } } +} diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 93a1f92644..996433b9f2 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -199,17 +199,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.' @@ -281,18 +270,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 cfde318c06..ab11018f01 100644 --- a/fastlane/Gemfile.lock +++ b/fastlane/Gemfile.lock @@ -1,27 +1,27 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.5) + CFPropertyList (3.0.6) rexml - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + 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.579.0) - aws-sdk-core (3.130.2) + aws-partitions (1.766.0) + aws-sdk-core (3.173.0) aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.525.0) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.64.0) + aws-sdk-core (~> 3, >= 3.165.0) aws-sigv4 (~> 1.1) - jmespath (~> 1.0) - aws-sdk-kms (1.56.0) - aws-sdk-core (~> 3, >= 3.127.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.113.1) - aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-s3 (1.122.0) + aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.0) + aws-sigv4 (1.5.2) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -34,10 +34,10 @@ GEM rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.6) + dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.92.2) - faraday (1.10.0) + excon (0.99.0) + faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -56,8 +56,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.3) - multipart-post (>= 1.2, < 3) + faraday-multipart (1.0.4) + multipart-post (~> 2) faraday-net_http (1.0.1) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) @@ -66,7 +66,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.6) - fastlane (2.205.2) + fastlane (2.212.2) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -106,12 +106,10 @@ 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.19.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-core (0.4.2) + 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) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -120,27 +118,27 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.10.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-playcustomapp_v1 (0.7.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-storage_v1 (0.13.0) - google-apis-core (>= 0.4, < 2.a) + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.2.0) - google-cloud-storage (1.36.2) + google-cloud-errors (1.3.1) + google-cloud-storage (1.44.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.1.3) + googleauth (1.5.2) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) @@ -148,50 +146,40 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-accept (1.7.0) - http-cookie (1.0.4) + http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - jmespath (1.6.1) - json (2.6.1) - jwt (2.3.0) + jmespath (1.6.2) + 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.2022.0105) - mini_magick (4.11.0) + 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.6.0) - public_suffix (4.0.7) + plist (3.7.0) + public_suffix (5.0.1) rake (13.0.6) - representable (3.1.1) + representable (3.2.0) 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) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.16.1) + signet (0.17.0) addressable (~> 2.8) - faraday (>= 0.17.5, < 3.0) + faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simctl (1.6.8) + simctl (1.6.10) CFPropertyList naturally terminal-notifier (2.0.0) @@ -205,11 +193,11 @@ GEM uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.8.1) + unf_ext (0.0.8.2) unicode-display_width (1.8.0) - webrick (1.7.0) + webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.21.0) + xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) @@ -227,7 +215,6 @@ PLATFORMS DEPENDENCIES fastlane (>= 2.131.0) fastlane-plugin-clean_testflight_testers - fastlane-plugin-diawi BUNDLED WITH - 2.1.4 + 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 31fa036a8a..22872a41de 100644 --- a/fastlane/gemset.nix +++ b/fastlane/gemset.nix @@ -5,10 +5,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "022r3m9wdxljpbya69y2i3h9g3dhhfaqzidf95m6qjzms792jvgp"; + sha256 = "15s8van7r2ad3dq6i03l3z4hqnvxcq75a3h72kxvf9an53sqma20"; type = "gem"; }; - version = "2.8.0"; + version = "2.8.4"; }; artifactory = { groups = ["default"]; @@ -45,10 +45,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1ilhspsph7icrrz94f3qngjkj585hsyv9bnxr44iabcqqwymr79w"; + sha256 = "0x7v4v8hj0pbzw3x1iv07x8v93fcs74svlhzv7vl6laxm4mc6858"; type = "gem"; }; - version = "1.579.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 = "0hajbavfngn99hcz6n20162jygvwdflldvnlrza7z32hizawaaan"; + sha256 = "10djgbz4k9w3axka8xrhf97h9yh9svi5g5xvncfwnkg6h22w2177"; type = "gem"; }; - version = "3.130.2"; + version = "3.173.0"; }; aws-sdk-kms = { dependencies = ["aws-sdk-core" "aws-sigv4"]; @@ -67,10 +67,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "14dcfqqdx1dy7qwrdyqdvqjs53kswm4njvg34f61jpl9xi3h2yf3"; + sha256 = "1bcm0c9f7xy5qj5f0z3gddqslhb2vzrj9smc39pgqyq4jmn5kpj0"; type = "gem"; }; - version = "1.56.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 = "0kxcc3abjxld66ryrivfq9wxxpik8ngr2b2dr7shgrsgf5zmrkh8"; + sha256 = "01cryf8kfkmlsxb327szcwcagsp7lss5gmk6zxlgap65lv8bc7rx"; type = "gem"; }; - version = "1.113.1"; + version = "1.122.0"; }; aws-sigv4 = { dependencies = ["aws-eventstream"]; @@ -89,10 +89,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0xp7diwq7nv4vvxrl9x3lis2l4x6bissrfzbfyy6rv5bmj5w109z"; + sha256 = "11hkna2av47bl0yprgp8k4ya70rc3m2ib5w10fn0piplgkkmhz7m"; type = "gem"; }; - version = "1.5.0"; + version = "1.5.2"; }; babosa = { groups = ["default"]; @@ -110,10 +110,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "193l8r1ycd3dcxa7lsb4pqcghbk56dzc5244m6y8xmv88z6m31d7"; + sha256 = "1a36zn77yyibqsfpka0i8vgf3yv98ic2b9wwlbc29566y8wpa2bq"; type = "gem"; }; - version = "3.0.5"; + version = "3.0.6"; }; claide = { groups = ["default"]; @@ -193,10 +193,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0iym172c5337sm1x2ykc2i3f961vj3wdclbyg1x6sxs3irgfsl94"; + sha256 = "1n0pi8x8ql5h1mijvm8lgn6bhq4xjb5a500p5r1krq4s6j9lg565"; type = "gem"; }; - version = "2.7.6"; + version = "2.8.1"; }; emoji_regex = { groups = ["default"]; @@ -213,10 +213,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "01pcl1vx60x3f28rs6iw1lgqxycgb2yxq2p45k7b4a8liadykhba"; + sha256 = "0j826kfvzn7nc5pv950n270r0sx1702k988ad11cdlav3dcxxw09"; type = "gem"; }; - version = "0.92.2"; + version = "0.99.0"; }; faraday = { dependencies = ["faraday-em_http" "faraday-em_synchrony" "faraday-excon" "faraday-httpclient" "faraday-multipart" "faraday-net_http" "faraday-net_http_persistent" "faraday-patron" "faraday-rack" "faraday-retry" "ruby2_keywords"]; @@ -224,10 +224,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "00palwawk897p5gypw5wjrh93d4p0xz2yl9w93yicb4kq7amh8d4"; + sha256 = "1c760q0ks4vj4wmaa7nh1dgvgqiwaw0mjr7v8cymy7i3ffgjxx90"; type = "gem"; }; - version = "1.10.0"; + version = "1.10.3"; }; faraday-cookie_jar = { dependencies = ["faraday" "http-cookie"]; @@ -286,10 +286,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "03qfi9020ynf7hkdiaq01sd2mllvw7fg4qiin3pk028b4wv23j3j"; + sha256 = "09871c4hd7s5ws1wl4gs7js1k2wlby6v947m2bbzg43pnld044lh"; type = "gem"; }; - version = "1.0.3"; + version = "1.0.4"; }; faraday-net_http = { groups = ["default"]; @@ -368,10 +368,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "091l4vl909rv6alydwlzhbk0lfmfphb7n2sjybdfy2azr07b6a0d"; + sha256 = "15sa3v3aaslympg9nmadmpxpbzykdiybzxn3navc7mf0iscb3q7s"; type = "gem"; }; - version = "2.205.2"; + 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 = "0qc501qhgks10qr7dm42bjcsm6yrbg1lxy28akpxindvjk61zh9i"; + sha256 = "0ks2ak4fcvlflhyinykvd88g2ybxwsbc347aww349zhn1mqprbvg"; type = "gem"; }; - version = "0.19.0"; + version = "0.42.0"; }; google-apis-core = { dependencies = ["addressable" "googleauth" "httpclient" "mini_mime" "representable" "retriable" "rexml" "webrick"]; @@ -421,10 +410,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "19v15vkgg86k79l51gfs7fab4h7fkv8358ckmkyp33jgsx3zr17b"; + sha256 = "184zkm5agi7r5fl79hgahjpydsc4d23nd2ynh2sr9z8gs2w4h82f"; type = "gem"; }; - version = "0.4.2"; + version = "0.11.0"; }; google-apis-iamcredentials_v1 = { dependencies = ["google-apis-core"]; @@ -432,10 +421,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1yibminaffzz5npq605m0vqc024dcybiw7xk5vr0jxzlsh8nxvhn"; + sha256 = "0ysil0bkh755kmf9xvw5szhk1yyh3gqzwfsrbwsrl77gsv7jarcs"; type = "gem"; }; - version = "0.10.0"; + version = "0.17.0"; }; google-apis-playcustomapp_v1 = { dependencies = ["google-apis-core"]; @@ -443,10 +432,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "15wnkbn6kzijbyqkqrh7s6apjf5630yvf2v8zy93zk0x87n2drcd"; + sha256 = "1mlgwiid5lgg41y7qk8ca9lzhwx5njs25hz5fbf1mdal0kwm37lm"; type = "gem"; }; - version = "0.7.0"; + version = "0.13.0"; }; google-apis-storage_v1 = { dependencies = ["google-apis-core"]; @@ -454,10 +443,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0lcb9jkjipz1kgg8zyp8a6741andads55bxbldg3x8qmzkv9pv31"; + sha256 = "17qamcjnf22zvw1g169g8a2gkzdsxx4ij3a4ganihyrcf9r62asj"; type = "gem"; }; - version = "0.13.0"; + version = "0.19.0"; }; google-cloud-core = { dependencies = ["google-cloud-env" "google-cloud-errors"]; @@ -486,10 +475,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0nakfswnck6grjpyhckzl40qccyys3sy999h5axk0rldx96fnivd"; + sha256 = "0flpj7v196c3xsqx4yjb7rjcj8p0by4rhj6qf5zanw4p1i41ssf0"; type = "gem"; }; - version = "1.2.0"; + version = "1.3.1"; }; google-cloud-storage = { dependencies = ["addressable" "digest-crc" "google-apis-iamcredentials_v1" "google-apis-storage_v1" "google-cloud-core" "googleauth" "mini_mime"]; @@ -497,10 +486,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "09d1bvxma4czbgay9lhcqsrhh6pd8s9i5djflzpsn00h4isdilw3"; + sha256 = "1skhlpcykxxzw3050cwngdyc3n746wfx443w1w9chxwjbh2ix6i9"; type = "gem"; }; - version = "1.36.2"; + version = "1.44.0"; }; googleauth = { dependencies = ["faraday" "jwt" "memoist" "multi_json" "os" "signet"]; @@ -508,10 +497,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1y80y72bpz04piiskfn93i5rzfy02mjchp3ym77yf2811gzz33d9"; + sha256 = "1lj5haarpn7rybbq9s031zcn9ji3rlz5bk64bwa2j34q5s1h5gis"; type = "gem"; }; - version = "1.1.3"; + version = "1.5.2"; }; highline = { groups = ["default"]; @@ -523,26 +512,16 @@ }; 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"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "19370bc97gsy2j4hanij246hv1ddc85hw0xjb6sj7n1ykqdlx9l9"; + sha256 = "13rilvlv8kwbzqfb644qp6hrbsj82cbqmnzcvqip1p6vqx36sxbk"; type = "gem"; }; - version = "1.0.4"; + version = "1.0.5"; }; httpclient = { groups = ["default"]; @@ -559,30 +538,30 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1mnvb80cdg7fzdcs3xscv21p28w4igk5sj5m7m81xp8v2ks87jj0"; + sha256 = "1cdw9vw2qly7q7r41s7phnac264rbsdqgj4l0h4nqgbjb157g393"; type = "gem"; }; - version = "1.6.1"; + version = "1.6.2"; }; json = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1z9grvjyfz16ag55hg522d3q4dh07hf391sf9s96npc0vfi85xkz"; + sha256 = "0nalhin1gda4v8ybk6lq8f407cgfrj6qzn234yra4ipkmlbfmal6"; type = "gem"; }; - version = "2.6.1"; + version = "2.6.3"; }; jwt = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0bg8pjx0mpvl10k6d8a6gc8dzlv2z5jkqcjbjcirnk032iriq838"; + sha256 = "09yj3z5snhaawh2z1w45yyihzmh57m6m7dp8ra8gxavhj5kbiq5p"; type = "gem"; }; - version = "2.3.0"; + version = "2.7.0"; }; memoist = { groups = ["default"]; @@ -594,36 +573,15 @@ }; 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 = "003gd7mcay800k2q4pb2zn8lwwgci4bhi42v2jvlidm8ksx03i6q"; - type = "gem"; - }; - version = "3.2022.0105"; - }; mini_magick = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1aj604x11d9pksbljh0l38f70b558rhdgji1s9i763hiagvvx2hs"; + sha256 = "0slh78f9z6n0l1i2km7m48yz7l4fjrk88sj1f4mh1wb39sl2yc37"; type = "gem"; }; - version = "4.11.0"; + version = "4.12.0"; }; mini_mime = { groups = ["default"]; @@ -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 = []; @@ -710,20 +658,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1whhr897z6z6av85x2cipyjk46bwh6s4wx6nbrcd3iifnzvbqs7l"; + sha256 = "0wzhnbzraz60paxhm48c50fp9xi7cqka4gfhxmiq43mhgh5ajg3h"; type = "gem"; }; - version = "3.6.0"; + version = "3.7.0"; }; public_suffix = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1f3knlwfwm05sfbaihrxm4g772b79032q14c16q4b38z8bi63qcb"; + sha256 = "0hz0bx2qs2pwb0bwazzsah03ilpf3aai8b7lk7s35jsfzwbkjq35"; type = "gem"; }; - version = "4.0.7"; + version = "5.0.1"; }; rake = { groups = ["default"]; @@ -741,21 +689,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "09xwzz94ryp57wyjrqysiz1sslnxd4r4m9wayy63jb7f8qfx1kys"; + sha256 = "1kms3r6w6pnryysnaqqa9fsn0v73zx1ilds9d1c565n3xdzbyafc"; type = "gem"; }; - version = "3.1.1"; - }; - 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"; + version = "3.2.0"; }; retriable = { groups = ["default"]; @@ -823,10 +760,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1jwyggz80xb3yi2hycmmw214c4072g8i56y0b0gsmpkiyk5d0vh1"; + sha256 = "0100rclkhagf032rg3r0gf3f4znrvvvqrimy6hpa73f21n9k2a0x"; type = "gem"; }; - version = "0.16.1"; + version = "0.17.0"; }; simctl = { dependencies = ["CFPropertyList" "naturally"]; @@ -834,10 +771,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1v9rsdmg5c5kkf8ps47xnrfbvjnq11sbaifr186jwkh4npawz00x"; + sha256 = "0sr3z4kmp6ym7synicyilj9vic7i9nxgaszqx6n1xn1ss7s7g45r"; type = "gem"; }; - version = "1.6.8"; + version = "1.6.10"; }; terminal-notifier = { groups = ["default"]; @@ -927,10 +864,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0bf120xbq23zjyf8zi8h1576d71g58srr8rndig0whn10w72vrxz"; + sha256 = "1yj2nz2l101vr1x9w2k83a0fag1xgnmjwp8w8rw4ik2rwcz65fch"; type = "gem"; }; - version = "0.0.8.1"; + version = "0.0.8.2"; }; unicode-display_width = { groups = ["default"]; @@ -947,10 +884,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1d4cvgmxhfczxiq5fr534lmizkhigd15bsx5719r5ds7k7ivisc7"; + sha256 = "13qm7s0gr2pmfcl7dxrmq38asaza4w0i2n9my4yzs499j731wh8r"; type = "gem"; }; - version = "1.7.0"; + version = "1.8.1"; }; word_wrap = { groups = ["default"]; @@ -968,10 +905,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0xmzb1mdsnkpf7v07whz0n2wc8kg6785sc7i5zyawd8dl8517rp4"; + sha256 = "1s7hxaqd1fi4rlmm2jbrglyvka1r95frlxan61vfcnd8n6pxynpi"; type = "gem"; }; - version = "1.21.0"; + version = "1.22.0"; }; xcpretty = { dependencies = ["rouge"]; 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()