From 85912c3ed82c5595b29b231a29d8a6ed25bb0776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliv=C3=A9r=20Falvai?= Date: Fri, 12 Aug 2022 10:27:07 +0200 Subject: [PATCH] Override API connection via step inputs (#43) * Override API connection via step inputs * Update README * Unset and restore envs for testing --- README.md | 5 + e2e/bitrise.yml | 41 ++++ go.mod | 24 +- go.sum | 44 ++-- main.go | 24 +- step.yml | 41 ++++ .../go-steputils/v2/ruby/environment.go | 7 +- .../go-utils/errorutil/errorutil.go | 6 +- .../go-utils/v2/retryhttp/retryhttp.go | 25 ++ vendor/github.com/bitrise-io/go-xcode/LICENSE | 21 ++ .../go-xcode/profileutil/capabilities.go | 3 + .../bitrise-io/go-xcode/profileutil/util.go | 2 +- .../go-xcode/v2/autocodesign/autocodesign.go | 51 ++-- .../go-xcode/v2/autocodesign/certificates.go | 24 +- .../v2/autocodesign/codesignasset/writer.go | 20 +- .../devportalclient/spaceship/certificates.go | 4 + .../devportalclient/spaceship/devices.go | 4 + .../devportalclient/spaceship/profiles.go | 14 ++ .../localcodesignasset/profile.go | 30 +++ .../localcodesignasset/profileconverter.go | 27 +-- .../v2/autocodesign/mock_AssetWriter.go | 16 +- .../profiledownloader/profiledownloader.go | 67 ++++++ .../projectmanager/projecthelper.go | 17 +- .../projectmanager/projectmanager.go | 21 +- .../go-xcode/v2/codesign/codesign.go | 227 ++++++++++++------ .../go-xcode/v2/codesign/inputparse.go | 159 +++++++++++- .../bitrise-io/go-xcode/v2/xcarchive/ios.go | 2 + .../go-xcode/xcarchive/entitlements.go | 3 + .../bitrise-io/go-xcode/xcodebuild/build.go | 88 +++---- .../xcodebuild/resolve_package_deps.go | 85 +++++++ .../xcodebuild/show_build_settings.go | 11 +- .../go-xcode/xcodeproject/xcodeproj/proj.go | 5 + .../xcodeproj/recreate_schemes.go | 6 +- .../go-xcode/xcodeproject/xcodeproj/target.go | 56 ++--- .../xcodeproj/target_dependency.go | 15 +- .../xcodeproject/xcodeproj/xcodeproj.go | 66 ++++- .../xcodeproject/xcscheme/xcscheme.go | 87 ++++++- .../xcodeproject/xcworkspace/xcworkspace.go | 14 +- vendor/github.com/golang-jwt/jwt/v4/README.md | 13 +- vendor/github.com/golang-jwt/jwt/v4/claims.go | 12 +- vendor/github.com/golang-jwt/jwt/v4/errors.go | 48 ++++ .../golang-jwt/jwt/v4/map_claims.go | 3 + .../golang-jwt/jwt/v4/parser_option.go | 4 +- vendor/github.com/golang-jwt/jwt/v4/token.go | 25 +- vendor/github.com/golang-jwt/jwt/v4/types.go | 6 +- .../hashicorp/go-retryablehttp/README.md | 19 ++ .../hashicorp/go-retryablehttp/client.go | 85 +++++-- .../hashicorp/go-version/CHANGELOG.md | 7 + .../github.com/hashicorp/go-version/README.md | 2 +- .../hashicorp/go-version/constraint.go | 108 ++++++++- .../hashicorp/go-version/version.go | 23 +- vendor/github.com/stretchr/objx/.travis.yml | 30 --- vendor/github.com/stretchr/objx/accessors.go | 36 ++- vendor/github.com/stretchr/objx/map.go | 57 ++--- .../stretchr/objx/type_specific_codegen.go | 10 + .../testify/assert/assertion_compare.go | 54 ++++- .../assert/assertion_compare_can_convert.go | 16 ++ .../assert/assertion_compare_legacy.go | 16 ++ .../testify/assert/assertion_format.go | 12 + .../testify/assert/assertion_forward.go | 24 ++ .../testify/assert/assertion_order.go | 8 +- .../stretchr/testify/assert/assertions.go | 112 ++++++--- .../github.com/stretchr/testify/mock/mock.go | 10 +- vendor/gopkg.in/yaml.v3/decode.go | 78 ++++-- vendor/modules.txt | 28 ++- 65 files changed, 1685 insertions(+), 523 deletions(-) create mode 100644 vendor/github.com/bitrise-io/go-utils/v2/retryhttp/retryhttp.go create mode 100644 vendor/github.com/bitrise-io/go-xcode/LICENSE create mode 100644 vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/profiledownloader/profiledownloader.go create mode 100644 vendor/github.com/bitrise-io/go-xcode/xcodebuild/resolve_package_deps.go delete mode 100644 vendor/github.com/stretchr/objx/.travis.yml create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go diff --git a/README.md b/README.md index 96ce3d2..e045647 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ Under **Automatic code signing**: 3. **The minimum days the Provisioning Profile should be valid**: If this input is set to >0, the managed Provisioning Profile will be renewed if it expires within the configured number of days. Otherwise the Step renews the managed Provisioning Profile if it is expired. 4. The **Code signing certificate URL**, the **Code signing certificate passphrase**, the **Keychain path**, and the **Keychain password** inputs are automatically populated if certificates are uploaded to Bitrise's **Code Signing** tab. If you store your files in a private repo, you can manually edit these fields. +If you want to set the Apple service connection credentials on the step-level (instead of using the one configured in the App Settings), use the Step inputs in the **App Store Connect connection override** category. Note that this only works if **Automatic code signing method** is set to `api-key`. + Under **IPA export configuration**: 1. **Developer Portal team**: Add the Developer Portal team's name to use for this export. This input defaults to the team used to build the archive. 2. **Rebuild from bitcode**: For non-App Store exports, should Xcode re-compile the app from bitcode? @@ -85,6 +87,9 @@ steps: | `upload_bitcode` | For __App Store__ exports, should the package include bitcode? | required | `yes` | | `manage_version_and_build_number` | Should Xcode manage the app's build number when uploading to App Store Connect. This will change the version and build numbers of all content in your app only if the is an invalid number (like one that was used previously or precedes your current build number). The input will not work if `export options plist content` input has been set. Default set to No. | required | `no` | | `export_options_plist_content` | Specifies a plist file content that configures archive exporting. If not specified, the Step will auto-generate it. | | | +| `api_key_path` | Local path or remote URL to the private key (p8 file) for App Store Connect API. This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. The input value can be a file path (eg. `$TMPDIR/private_key.p8`) or an HTTPS URL. This input only takes effect if the other two connection override inputs are set too (`api_key_id`, `api_key_issuer_id`). | | | +| `api_key_id` | Private key ID used for App Store Connect authentication. This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. This input only takes effect if the other two connection override inputs are set too (`api_key_path`, `api_key_issuer_id`). | | | +| `api_key_issuer_id` | Private key issuer ID used for App Store Connect authentication. This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. This input only takes effect if the other two connection override inputs are set too (`api_key_path`, `api_key_id`). | | | | `verbose_log` | If this input is set, the Step will print additional logs for debugging. | required | `no` | diff --git a/e2e/bitrise.yml b/e2e/bitrise.yml index f5da65e..953d114 100644 --- a/e2e/bitrise.yml +++ b/e2e/bitrise.yml @@ -10,6 +10,9 @@ app: - BITFALL_APPLE_IOS_CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_IOS_CERTIFICATE_PASSPHRASE_LIST - BITFALL_APPLE_IOS_CERTIFICATE_NOPASSPHRASE_URL: $BITFALL_APPLE_IOS_CERTIFICATE_NOPASSPHRASE_URL - BITFALL_APPLE_PROVISIONING_PROFILE_URL_LIST: $BITFALL_APPLE_PROVISIONING_PROFILE_URL_LIST + - BITFALL_APPSTORECONNECT_API_KEY_URL: $BITFALL_APPSTORECONNECT_API_KEY_URL + - BITFALL_APPSTORECONNECT_API_KEY_ID: $BITFALL_APPSTORECONNECT_API_KEY_ID + - BITFALL_APPSTORECONNECT_API_KEY_ISSUER_ID: $BITFALL_APPSTORECONNECT_API_KEY_ISSUER_ID - SAMPLE_ARTIFACTS_URL: https://github.com/bitrise-io/sample-artifacts.git - SAMPLE_ARTIFACTS_BRANCH: master - TEAM_ID: 72SA8V3WYL @@ -49,6 +52,44 @@ app: workflows: + test_auto_codesign_override: + description: Test automatic codesign with API key and overriding connection params via step inputs + before_run: + - _setup + steps: + - script: + title: Unset Bitrise API connection env vars + inputs: + - content: |- + #!/usr/bin/env bash + set -ex + envman add --key BITRISE_BUILD_URL_BACKUP --value $BITRISE_BUILD_URL + envman add --key BITRISE_BUILD_API_TOKEN_BACKUP --value $BITRISE_BUILD_API_TOKEN + envman unset --key BITRISE_BUILD_URL + envman unset --key BITRISE_BUILD_API_TOKEN + - path::./: + title: Step Test - Multi Target API Key auto signing + inputs: + - distribution_method: development + - archive_path: ./archives/Fruta-managed.xcarchive + - product: app + - automatic_code_signing: api-key + - verbose_log: "yes" + - certificate_url_list: $BITFALL_APPLE_IOS_CERTIFICATE_URL_LIST + - passphrase_list: $BITFALL_APPLE_IOS_CERTIFICATE_PASSPHRASE_LIST + - keychain_path: $BITRISE_KEYCHAIN_PATH + - keychain_password: $BITRISE_KEYCHAIN_PASSWORD + - api_key_path: $BITFALL_APPSTORECONNECT_API_KEY_URL + - api_key_id: $BITFALL_APPSTORECONNECT_API_KEY_ID + - api_key_issuer_id: $BITFALL_APPSTORECONNECT_API_KEY_ISSUER_ID + - script: + title: Restore Bitrise API connection env vars + inputs: + - content: |- + set -ex + envman add --key BITRISE_BUILD_URL --value $BITRISE_BUILD_URL_BACKUP + envman add --key BITRISE_BUILD_API_TOKEN --value $BITRISE_BUILD_API_TOKEN_BACKUP + test_single_certificate_no_passphrase: before_run: - _setup diff --git a/go.mod b/go.mod index 1b9a265..1c40574 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,12 @@ module github.com/bitrise-steplib/steps-export-xcarchive go 1.17 require ( - github.com/bitrise-io/go-steputils v1.0.1 - github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.1 - github.com/bitrise-io/go-utils v1.0.1 - github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.1 - github.com/bitrise-io/go-xcode v1.0.2 - github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.11 + github.com/bitrise-io/go-steputils v1.0.2 + github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.2 + github.com/bitrise-io/go-utils v1.0.2 + github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.11 + github.com/bitrise-io/go-xcode v1.0.9 + github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.20 howett.net/plist v1.0.0 ) @@ -17,16 +17,16 @@ require ( github.com/bitrise-io/pkcs12 v0.0.0-20211108084543-e52728e011c8 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa // indirect - github.com/golang-jwt/jwt/v4 v4.2.0 // indirect + github.com/golang-jwt/jwt/v4 v4.4.1 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.0 // indirect - github.com/hashicorp/go-version v1.3.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.1 // indirect + github.com/hashicorp/go-version v1.5.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/stretchr/objx v0.3.0 // indirect - github.com/stretchr/testify v1.7.0 + github.com/stretchr/objx v0.4.0 // indirect + github.com/stretchr/testify v1.7.1 golang.org/x/text v0.3.7 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.0 // indirect ) diff --git a/go.sum b/go.sum index d4dbcd8..ef17078 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,20 @@ github.com/bitrise-io/go-plist v0.0.0-20210301100253-4b1a112ccd10 h1:/2OyBFI7GjYKexBPcfTPvKFz8Ks7qYzkkz2SQ8aiJgc= github.com/bitrise-io/go-plist v0.0.0-20210301100253-4b1a112ccd10/go.mod h1:pARutiL3kEuRLV3JvswidvfCj+9Y3qMZtji2BDqLFsA= -github.com/bitrise-io/go-steputils v1.0.1 h1:lwPl2W1njfANrBoTCkuqOOYbTha263ZFqoWQH0fwhaY= github.com/bitrise-io/go-steputils v1.0.1/go.mod h1:YIUaQnIAyK4pCvQG0hYHVkSzKNT9uL2FWmkFNW4mfNI= -github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.1 h1:rRttUs9HUZkkK7u+rRsdLh436um2qGvFE5dJeiCoB+o= -github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.1/go.mod h1:OC0mHpjD/bqmsHlhG+FWgTouBbcJvmyx896PDP3dRBs= -github.com/bitrise-io/go-utils v1.0.1 h1:e7mepVBkVN1DXRPESNXb0djEw6bxB6B93p/Q74zzcvk= +github.com/bitrise-io/go-steputils v1.0.2 h1:BEFG87r7uA/Yabk4SmuxP2yOgjjO+YGsDOYXtUH8IJ0= +github.com/bitrise-io/go-steputils v1.0.2/go.mod h1:YIUaQnIAyK4pCvQG0hYHVkSzKNT9uL2FWmkFNW4mfNI= +github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.2 h1:WfhgPqLyg+VPNb6istzlJqalk81kb9Wt9IcQIQTOsxE= +github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.2/go.mod h1:OC0mHpjD/bqmsHlhG+FWgTouBbcJvmyx896PDP3dRBs= github.com/bitrise-io/go-utils v1.0.1/go.mod h1:ZY1DI+fEpZuFpO9szgDeICM4QbqoWVt0RSY3tRI1heY= -github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.1 h1:4PBBhTUl6NthNJCTCexe/22e/crE6FTmYfcMAM/UirY= +github.com/bitrise-io/go-utils v1.0.2 h1:w4Mz2IvrgDzrFJECuHdvsK1LHO30cdtuy9bBa7Lw2c0= +github.com/bitrise-io/go-utils v1.0.2/go.mod h1:ZY1DI+fEpZuFpO9szgDeICM4QbqoWVt0RSY3tRI1heY= github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.1/go.mod h1:sy+Ir1X8P3tAAx/qU/r+hqDjHDcrMjIzDEvId1wqNc4= -github.com/bitrise-io/go-xcode v1.0.1/go.mod h1:Y0Wu2dXm0MilJ/4D3+gPHaNMlUcP+1DjIPoLPykq7wY= -github.com/bitrise-io/go-xcode v1.0.2 h1:Uv/cBOJ/qZpitjOpyS8orafee3wk66OwvRTbqA2fr+4= -github.com/bitrise-io/go-xcode v1.0.2/go.mod h1:Y0Wu2dXm0MilJ/4D3+gPHaNMlUcP+1DjIPoLPykq7wY= -github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.11 h1:g2e1BcYQaF/vJatXQ/IbTWJuEdGVTrnz8dADtSawsdU= -github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.11/go.mod h1:6YbvyYwZgSTt96CQSQ6QlrkcRiv3ssX8zLijh2TPnbU= +github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.11 h1:IacLMHL7hhgVcqtx15Bysq738P8FRCp6ckGk1NvioWo= +github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.11/go.mod h1:SJqGxzwjIAx2LVQxNGS4taN7X//eDPJLrFxJ1MpOuyA= +github.com/bitrise-io/go-xcode v1.0.9 h1:+sbqOYidQ+aiFfCTDpf2LdGSQEM5RfbtDsiG27zJG+s= +github.com/bitrise-io/go-xcode v1.0.9/go.mod h1:Y0Wu2dXm0MilJ/4D3+gPHaNMlUcP+1DjIPoLPykq7wY= +github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.20 h1:MIH3eGNcAsc5VBACiU+EFcmUfqCyT6/fMSi2UjYR9+s= +github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.20/go.mod h1:8WBcRgrVXY8tzR7NcjE4fw6WguOIfB3YcC7ZTcQYUEY= github.com/bitrise-io/pkcs12 v0.0.0-20211108084543-e52728e011c8 h1:kmvU8AxrNTxXsVPKepBHD8W+eCVmeaKyTkRuUJB2K38= github.com/bitrise-io/pkcs12 v0.0.0-20211108084543-e52728e011c8/go.mod h1:UiXKNs0essbC14a2TvGlnUKo9isP9m4guPrp8KJHJpU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -20,8 +22,9 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= -github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU= -github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= +github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -32,16 +35,19 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.5.0 h1:O293SZ2Eg+AAYijkVK3jR786Am1bhDEh2GHT0tIVE5E= +github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -49,18 +55,21 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -75,7 +84,8 @@ gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= diff --git a/main.go b/main.go index 167dbeb..6285d08 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,7 @@ import ( "github.com/bitrise-io/go-utils/v2/command" "github.com/bitrise-io/go-utils/v2/env" "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-utils/v2/retryhttp" "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/models" "github.com/bitrise-io/go-xcode/profileutil" @@ -24,6 +25,7 @@ import ( "github.com/bitrise-io/go-xcode/v2/autocodesign/codesignasset" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient" "github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset" + "github.com/bitrise-io/go-xcode/v2/autocodesign/profiledownloader" "github.com/bitrise-io/go-xcode/v2/codesign" "github.com/bitrise-io/go-xcode/v2/xcarchive" "github.com/bitrise-io/go-xcode/xcodebuild" @@ -62,6 +64,10 @@ type Inputs struct { UploadBitcode bool `env:"upload_bitcode,opt[yes,no]"` ManageVersionAndBuildNumber bool `env:"manage_version_and_build_number"` ExportOptionsPlistContent string `env:"export_options_plist_content"` + // App Store Connect connection override + APIKeyPath stepconf.Secret `env:"api_key_path"` + APIKeyID string `env:"api_key_id"` + APIKeyIssuerID string `env:"api_key_issuer_id"` // Debugging VerboseLog bool `env:"verbose_log,opt[yes,no]"` // Output export @@ -205,13 +211,19 @@ func (s Step) createCodesignManager(inputs Inputs, xcodeMajorVersion int) (codes var serviceConnection *devportalservice.AppleDeveloperConnection = nil devPortalClientFactory := devportalclient.NewFactory(s.logger) - if authType == codesign.APIKeyAuth || authType == codesign.AppleIDAuth { + if inputs.BuildURL != "" && inputs.BuildAPIToken != "" { if serviceConnection, err = devPortalClientFactory.CreateBitriseConnection(inputs.BuildURL, string(inputs.BuildAPIToken)); err != nil { return codesign.Manager{}, err } } - appleAuthCredentials, err := codesign.SelectConnectionCredentials(authType, serviceConnection, s.logger) + connectionInputs := codesign.ConnectionOverrideInputs{ + APIKeyPath: inputs.APIKeyPath, + APIKeyID: inputs.APIKeyID, + APIKeyIssuerID: inputs.APIKeyIssuerID, + } + + appleAuthCredentials, err := codesign.SelectConnectionCredentials(authType, serviceConnection, connectionInputs, s.logger) if err != nil { return codesign.Manager{}, err } @@ -228,12 +240,18 @@ func (s Step) createCodesignManager(inputs Inputs, xcodeMajorVersion int) (codes IsVerboseLog: inputs.VerboseLog, } + var testDevices []devportalservice.TestDevice + if serviceConnection != nil { + testDevices = serviceConnection.TestDevices + } + return codesign.NewManagerWithArchive( opts, appleAuthCredentials, - serviceConnection, + testDevices, devPortalClientFactory, certdownloader.NewDownloader(codesignConfig.CertificatesAndPassphrases, retry.NewHTTPClient().StandardClient()), + profiledownloader.New([]string{}, retryhttp.NewClient(s.logger).StandardClient()), // not supported for now codesignasset.NewWriter(codesignConfig.Keychain), localcodesignasset.NewManager(localcodesignasset.NewProvisioningProfileProvider(), localcodesignasset.NewProvisioningProfileConverter()), archive, diff --git a/step.yml b/step.yml index ddb14c0..843aac1 100755 --- a/step.yml +++ b/step.yml @@ -21,6 +21,8 @@ description: |- 3. **The minimum days the Provisioning Profile should be valid**: If this input is set to >0, the managed Provisioning Profile will be renewed if it expires within the configured number of days. Otherwise the Step renews the managed Provisioning Profile if it is expired. 4. The **Code signing certificate URL**, the **Code signing certificate passphrase**, the **Keychain path**, and the **Keychain password** inputs are automatically populated if certificates are uploaded to Bitrise's **Code Signing** tab. If you store your files in a private repo, you can manually edit these fields. + If you want to set the Apple service connection credentials on the step-level (instead of using the one configured in the App Settings), use the Step inputs in the **App Store Connect connection override** category. Note that this only works if **Automatic code signing method** is set to `api-key`. + Under **IPA export configuration**: 1. **Developer Portal team**: Add the Developer Portal team's name to use for this export. This input defaults to the team used to build the archive. 2. **Rebuild from bitcode**: For non-App Store exports, should Xcode re-compile the app from bitcode? @@ -222,6 +224,45 @@ inputs: If not specified, the Step will auto-generate it. +# App Store Connect connection override + +- api_key_path: + opts: + category: App Store Connect connection override + title: App Store Connect API private key + summary: Local path or remote URL to the private key (p8 file). This overrides the Bitrise-managed API connection. + description: |- + Local path or remote URL to the private key (p8 file) for App Store Connect API. + This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection + on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. + The input value can be a file path (eg. `$TMPDIR/private_key.p8`) or an HTTPS URL. + This input only takes effect if the other two connection override inputs are set too (`api_key_id`, `api_key_issuer_id`). + is_required: false + +- api_key_id: + opts: + category: App Store Connect connection override + title: App Store Connect API key ID + summary: Private key ID used for App Store Connect authentication. This overrides the Bitrise-managed API connection. + description: |- + Private key ID used for App Store Connect authentication. + This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection + on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. + This input only takes effect if the other two connection override inputs are set too (`api_key_path`, `api_key_issuer_id`). + is_required: false + +- api_key_issuer_id: + opts: + category: App Store Connect connection override + title: App Store Connect API issuer ID + summary: Private key issuer ID used for App Store Connect authentication. This overrides the Bitrise-managed API connection. + description: |- + Private key issuer ID used for App Store Connect authentication. + This overrides the Bitrise-managed API connection, only set this input if you want to control the API connection + on a step-level. Most of the time it's easier to set up the connection on the App Settings page on Bitrise. + This input only takes effect if the other two connection override inputs are set too (`api_key_path`, `api_key_id`). + is_required: false + # Debugging - verbose_log: "no" diff --git a/vendor/github.com/bitrise-io/go-steputils/v2/ruby/environment.go b/vendor/github.com/bitrise-io/go-steputils/v2/ruby/environment.go index cc41172..b4376d0 100644 --- a/vendor/github.com/bitrise-io/go-steputils/v2/ruby/environment.go +++ b/vendor/github.com/bitrise-io/go-steputils/v2/ruby/environment.go @@ -10,6 +10,7 @@ import ( "github.com/bitrise-io/go-utils/pathutil" "github.com/bitrise-io/go-utils/v2/command" "github.com/bitrise-io/go-utils/v2/env" + "github.com/bitrise-io/go-utils/v2/log" ) const ( @@ -44,13 +45,15 @@ type Environment interface { type environment struct { factory CommandFactory cmdLocator env.CommandLocator + logger log.Logger } // NewEnvironment ... -func NewEnvironment(factory CommandFactory, cmdLocator env.CommandLocator) Environment { +func NewEnvironment(factory CommandFactory, cmdLocator env.CommandLocator, logger log.Logger) Environment { return environment{ factory: factory, cmdLocator: cmdLocator, + logger: logger, } } @@ -88,7 +91,7 @@ func (m environment) IsSpecifiedRbenvRubyInstalled(workdir string) (bool, string cmd := m.factory.Create("rbenv", []string{"version"}, &command.Opts{Dir: absWorkdir}) out, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { - return false, "", fmt.Errorf("failed to check installed ruby version, %s error: %s", out, err) + m.logger.Warnf("failed to check installed ruby version, %s error: %s", out, err) } return isSpecifiedRbenvRubyInstalled(out) } diff --git a/vendor/github.com/bitrise-io/go-utils/errorutil/errorutil.go b/vendor/github.com/bitrise-io/go-utils/errorutil/errorutil.go index dd5f8d2..d7d8955 100644 --- a/vendor/github.com/bitrise-io/go-utils/errorutil/errorutil.go +++ b/vendor/github.com/bitrise-io/go-utils/errorutil/errorutil.go @@ -2,12 +2,14 @@ package errorutil import ( + "errors" "os/exec" "regexp" ) func exitCode(err error) int { - if exitError, ok := err.(*exec.ExitError); ok { + var exitError *exec.ExitError + if errors.As(err, &exitError) { return exitError.ProcessState.ExitCode() } return -1 @@ -22,7 +24,7 @@ func IsExitStatusError(err error) bool { func IsExitStatusErrorStr(errString string) bool { // https://golang.org/src/os/exec_posix.go?s=2421:2459#L87 // example exit status error string: exit status 1 - var rex = regexp.MustCompile(`^exit status [0-9]{1,3}$`) + var rex = regexp.MustCompile(`^exit status \d{1,3}$`) return rex.MatchString(errString) } diff --git a/vendor/github.com/bitrise-io/go-utils/v2/retryhttp/retryhttp.go b/vendor/github.com/bitrise-io/go-utils/v2/retryhttp/retryhttp.go new file mode 100644 index 0000000..5169ac7 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/v2/retryhttp/retryhttp.go @@ -0,0 +1,25 @@ +package retryhttp + +import ( + "github.com/bitrise-io/go-utils/v2/log" + "github.com/hashicorp/go-retryablehttp" +) + +// NewClient returns a retryable HTTP client with common defaults +func NewClient(logger log.Logger) *retryablehttp.Client { + client := retryablehttp.NewClient() + client.Logger = &httpLogAdaptor{logger: logger} + client.ErrorHandler = retryablehttp.PassthroughErrorHandler + + return client +} + +// httpLogAdaptor adapts the retryablehttp.Logger interface to the go-utils logger. +type httpLogAdaptor struct { + logger log.Logger +} + +// Printf implements the retryablehttp.Logger interface +func (a *httpLogAdaptor) Printf(fmtStr string, vars ...interface{}) { + a.logger.Debugf(fmtStr, vars...) +} diff --git a/vendor/github.com/bitrise-io/go-xcode/LICENSE b/vendor/github.com/bitrise-io/go-xcode/LICENSE new file mode 100644 index 0000000..cdfcf1f --- /dev/null +++ b/vendor/github.com/bitrise-io/go-xcode/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Bitrise + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/bitrise-io/go-xcode/profileutil/capabilities.go b/vendor/github.com/bitrise-io/go-xcode/profileutil/capabilities.go index 7bc709b..3e5b850 100644 --- a/vendor/github.com/bitrise-io/go-xcode/profileutil/capabilities.go +++ b/vendor/github.com/bitrise-io/go-xcode/profileutil/capabilities.go @@ -1,6 +1,7 @@ package profileutil import ( + "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-xcode/plistutil" ) @@ -19,6 +20,8 @@ func MatchTargetAndProfileEntitlements(targetEntitlements plistutil.PlistData, p } } + log.Debugf("Found %v entitlements from %v target", len(missingEntitlements), len(targetEntitlements)) + return missingEntitlements } diff --git a/vendor/github.com/bitrise-io/go-xcode/profileutil/util.go b/vendor/github.com/bitrise-io/go-xcode/profileutil/util.go index c41ac95..015d478 100644 --- a/vendor/github.com/bitrise-io/go-xcode/profileutil/util.go +++ b/vendor/github.com/bitrise-io/go-xcode/profileutil/util.go @@ -15,7 +15,7 @@ type ProfileType string const ProfileTypeIos ProfileType = "ios" // ProfileTypeMacOs ... -const ProfileTypeMacOs ProfileType = "macos" +const ProfileTypeMacOs ProfileType = "osx" // ProfileTypeTvOs ... const ProfileTypeTvOs ProfileType = "tvos" diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/autocodesign.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/autocodesign.go index 452b26b..89776ce 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/autocodesign.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/autocodesign.go @@ -12,6 +12,7 @@ import ( "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-xcode/certificateutil" "github.com/bitrise-io/go-xcode/devportalservice" + "github.com/bitrise-io/go-xcode/profileutil" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" "github.com/bitrise-io/go-xcode/xcodeproject/serialized" ) @@ -88,6 +89,7 @@ type DevPortalClient interface { type AssetWriter interface { Write(codesignAssetsByDistributionType map[DistributionType]AppCodesignAssets) error InstallCertificate(certificate certificateutil.CertificateInfoModel) error + InstallProfile(profile Profile) error } // LocalCodeSignAssetManager ... @@ -107,12 +109,29 @@ type CertificateProvider interface { GetCertificates() ([]certificateutil.CertificateInfoModel, error) } -// CodesignAssetsOpts are codesigning related paramters that are not specified by the project (or archive) +// LocalCertificates is a map from the certificate type (development, distribution) to an array of installed certs +type LocalCertificates map[appstoreconnect.CertificateType][]certificateutil.CertificateInfoModel + +// LocalProfile ... +type LocalProfile struct { + Profile Profile + Info profileutil.ProvisioningProfileInfoModel +} + +// ProfileProvider returns provisioning profiles +type ProfileProvider interface { + IsAvailable() bool + GetProfiles() ([]LocalProfile, error) +} + +// CodesignAssetsOpts are codesigning related parameters that are not specified by the project (or archive) type CodesignAssetsOpts struct { - DistributionType DistributionType - BitriseTestDevices []devportalservice.TestDevice - MinProfileValidityDays int - VerboseLog bool + DistributionType DistributionType + TypeToLocalCertificates LocalCertificates + BitriseTestDevices []devportalservice.TestDevice + MinProfileValidityDays int + FallbackToLocalAssetsOnAPIFailure bool + VerboseLog bool } // CodesignAssetManager ... @@ -122,16 +141,14 @@ type CodesignAssetManager interface { type codesignAssetManager struct { devPortalClient DevPortalClient - certificateProvider CertificateProvider assetWriter AssetWriter localCodeSignAssetManager LocalCodeSignAssetManager } // NewCodesignAssetManager ... -func NewCodesignAssetManager(devPortalClient DevPortalClient, certificateProvider CertificateProvider, assetWriter AssetWriter, localCodeSignAssetManager LocalCodeSignAssetManager) CodesignAssetManager { +func NewCodesignAssetManager(devPortalClient DevPortalClient, assetWriter AssetWriter, localCodeSignAssetManager LocalCodeSignAssetManager) CodesignAssetManager { return codesignAssetManager{ devPortalClient: devPortalClient, - certificateProvider: certificateProvider, assetWriter: assetWriter, localCodeSignAssetManager: localCodeSignAssetManager, } @@ -139,26 +156,10 @@ func NewCodesignAssetManager(devPortalClient DevPortalClient, certificateProvide // EnsureCodesignAssets is the main entry point of the codesigning logic func (m codesignAssetManager) EnsureCodesignAssets(appLayout AppLayout, opts CodesignAssetsOpts) (map[DistributionType]AppCodesignAssets, error) { - fmt.Println() - log.Infof("Downloading certificates") - - certs, err := m.certificateProvider.GetCertificates() - if err != nil { - return nil, fmt.Errorf("failed to download certificates: %w", err) - } - if len(certs) > 0 { - log.Printf("%d certificates downloaded:", len(certs)) - for _, cert := range certs { - log.Printf("- %s", cert.String()) - } - } else { - log.Warnf("No certificates found") - } - signUITestTargets := len(appLayout.UITestTargetBundleIDs) > 0 certsByType, distrTypes, err := selectCertificatesAndDistributionTypes( m.devPortalClient, - certs, + opts.TypeToLocalCertificates, opts.DistributionType, signUITestTargets, opts.VerboseLog, diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/certificates.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/certificates.go index 5d06a69..b3d0402 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/certificates.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/certificates.go @@ -9,7 +9,7 @@ import ( "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" ) -func selectCertificatesAndDistributionTypes(certificateSource DevPortalClient, certs []certificateutil.CertificateInfoModel, distribution DistributionType, signUITestTargets bool, verboseLog bool) (map[appstoreconnect.CertificateType][]Certificate, []DistributionType, error) { +func selectCertificatesAndDistributionTypes(certificateSource DevPortalClient, typeToLocalCerts LocalCertificates, distribution DistributionType, signUITestTargets bool, verboseLog bool) (map[appstoreconnect.CertificateType][]Certificate, []DistributionType, error) { certType, ok := CertificateTypeByDistribution[distribution] if !ok { panic(fmt.Sprintf("no valid certificate provided for distribution type: %s", distribution)) @@ -28,7 +28,7 @@ func selectCertificatesAndDistributionTypes(certificateSource DevPortalClient, c } } - certsByType, err := getValidCertificates(certs, certificateSource, requiredCertTypes, verboseLog) + certsByType, err := getValidCertificates(typeToLocalCerts, certificateSource, requiredCertTypes, verboseLog) if err != nil { if missingCertErr, ok := err.(missingCertificateError); ok { return nil, nil, &DetailedError{ @@ -50,12 +50,7 @@ func selectCertificatesAndDistributionTypes(certificateSource DevPortalClient, c return certsByType, distrTypes, nil } -func getValidCertificates(localCertificates []certificateutil.CertificateInfoModel, client DevPortalClient, requiredCertificateTypes map[appstoreconnect.CertificateType]bool, isDebugLog bool) (map[appstoreconnect.CertificateType][]Certificate, error) { - typeToLocalCerts, err := GetValidLocalCertificates(localCertificates) - if err != nil { - return nil, err - } - +func getValidCertificates(typeToLocalCerts LocalCertificates, client DevPortalClient, requiredCertificateTypes map[appstoreconnect.CertificateType]bool, isDebugLog bool) (map[appstoreconnect.CertificateType][]Certificate, error) { log.Debugf("Certificates required for Development: %t; Distribution: %t", requiredCertificateTypes[appstoreconnect.IOSDevelopment], requiredCertificateTypes[appstoreconnect.IOSDistribution]) for certificateType, required := range requiredCertificateTypes { @@ -73,10 +68,7 @@ func getValidCertificates(localCertificates []certificateutil.CertificateInfoMod validAPICertificates := map[appstoreconnect.CertificateType][]Certificate{} for certificateType, validLocalCertificates := range typeToLocalCerts { - matchingCertificates, err := matchLocalToAPICertificates(client, validLocalCertificates) - if err != nil { - return nil, err - } + matchingCertificates := matchLocalToAPICertificates(client, validLocalCertificates) if len(matchingCertificates) > 0 { log.Debugf("Certificates type %s has matches on Developer Portal:", certificateType) @@ -98,7 +90,7 @@ func getValidCertificates(localCertificates []certificateutil.CertificateInfoMod } // GetValidLocalCertificates returns validated and deduplicated local certificates -func GetValidLocalCertificates(certificates []certificateutil.CertificateInfoModel) (map[appstoreconnect.CertificateType][]certificateutil.CertificateInfoModel, error) { +func GetValidLocalCertificates(certificates []certificateutil.CertificateInfoModel) (LocalCertificates, error) { preFilteredCerts := certificateutil.FilterValidCertificateInfos(certificates) if len(preFilteredCerts.InvalidCertificates) != 0 { @@ -110,7 +102,7 @@ func GetValidLocalCertificates(certificates []certificateutil.CertificateInfoMod log.Debugf("Valid and deduplicated certificates:\n%s", certsToString(preFilteredCerts.ValidCertificates)) - localCertificates := map[appstoreconnect.CertificateType][]certificateutil.CertificateInfoModel{} + localCertificates := LocalCertificates{} for _, certType := range []appstoreconnect.CertificateType{appstoreconnect.IOSDevelopment, appstoreconnect.IOSDistribution} { localCertificates[certType] = filterCertificates(preFilteredCerts.ValidCertificates, certType) } @@ -121,7 +113,7 @@ func GetValidLocalCertificates(certificates []certificateutil.CertificateInfoMod } // matchLocalToAPICertificates ... -func matchLocalToAPICertificates(client DevPortalClient, localCertificates []certificateutil.CertificateInfoModel) ([]Certificate, error) { +func matchLocalToAPICertificates(client DevPortalClient, localCertificates []certificateutil.CertificateInfoModel) []Certificate { var matchingCertificates []Certificate for _, localCert := range localCertificates { @@ -137,7 +129,7 @@ func matchLocalToAPICertificates(client DevPortalClient, localCertificates []cer matchingCertificates = append(matchingCertificates, cert) } - return matchingCertificates, nil + return matchingCertificates } // logAllAPICertificates ... diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/codesignasset/writer.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/codesignasset/writer.go index 7118a28..9a08582 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/codesignasset/writer.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/codesignasset/writer.go @@ -15,6 +15,13 @@ import ( "github.com/bitrise-io/go-xcode/v2/autocodesign/keychain" ) +const ( + // ProfileIOSExtension is the iOS provisioning profile extension + ProfileIOSExtension = ".mobileprovision" + // ProfileMacExtension is the macOS provisioning profile extension + ProfileMacExtension = ".provisionprofile" +) + // Writer ... type Writer struct { keychain keychain.Keychain @@ -41,7 +48,7 @@ func (w Writer) Write(codesignAssetsByDistributionType map[autocodesign.Distribu for _, profile := range codesignAssets.ArchivableTargetProfilesByBundleID { log.Printf("- %s", profile.Attributes().Name) - if err := writeProfile(profile); err != nil { + if err := w.InstallProfile(profile); err != nil { return fmt.Errorf("failed to write profile to file: %s", err) } } @@ -49,7 +56,7 @@ func (w Writer) Write(codesignAssetsByDistributionType map[autocodesign.Distribu for _, profile := range codesignAssets.UITestTargetProfilesByBundleID { log.Printf("- %s", profile.Attributes().Name) - if err := writeProfile(profile); err != nil { + if err := w.InstallProfile(profile); err != nil { return fmt.Errorf("failed to write profile to file: %s", err) } } @@ -69,10 +76,10 @@ func (w Writer) InstallCertificate(certificate certificateutil.CertificateInfoMo return w.keychain.InstallCertificate(certificate, "") } -// writeProfile writes the provided profile under the `$HOME/Library/MobileDevice/Provisioning Profiles` directory. +// InstallProfile writes the provided profile under the `$HOME/Library/MobileDevice/Provisioning Profiles` directory. // Xcode uses profiles located in that directory. // The file extension depends on the profile's platform `IOS` => `.mobileprovision`, `MAC_OS` => `.provisionprofile` -func writeProfile(profile autocodesign.Profile) error { +func (w Writer) InstallProfile(profile autocodesign.Profile) error { homeDir := os.Getenv("HOME") profilesDir := path.Join(homeDir, "Library/MobileDevice/Provisioning Profiles") if exists, err := pathutil.IsDirExists(profilesDir); err != nil { @@ -86,9 +93,9 @@ func writeProfile(profile autocodesign.Profile) error { var ext string switch profile.Attributes().Platform { case appstoreconnect.IOS: - ext = ".mobileprovision" + ext = ProfileIOSExtension case appstoreconnect.MacOS: - ext = ".provisionprofile" + ext = ProfileMacExtension default: return fmt.Errorf("failed to write profile to file, unsupported platform: (%s). Supported platforms: %s, %s", profile.Attributes().Platform, appstoreconnect.IOS, appstoreconnect.MacOS) } @@ -97,5 +104,6 @@ func writeProfile(profile autocodesign.Profile) error { if err := ioutil.WriteFile(name, profile.Attributes().ProfileContent, 0600); err != nil { return fmt.Errorf("failed to write profile to file: %s", err) } + return nil } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/certificates.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/certificates.go index 83bd219..f0bf49f 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/certificates.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/certificates.go @@ -64,11 +64,15 @@ func (s *CertificateSource) downloadAll() error { return err } + fmt.Printf("Fetching developer certificates") + devCerts, err := getCertificates(devCertsCmd) if err != nil { return err } + fmt.Printf("Fetching distribution certificates") + distCers, err := getCertificates(distCertsCommand) if err != nil { return err diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/devices.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/devices.go index dde09fb..a9fe5ad 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/devices.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/devices.go @@ -49,6 +49,8 @@ func newDevice(d DeviceInfo) appstoreconnect.Device { // ListDevices ... func (d *DeviceClient) ListDevices(udid string, platform appstoreconnect.DevicePlatform) ([]appstoreconnect.Device, error) { + log.Debugf("Fetching devices") + cmd, err := d.client.createRequestCommand("list_devices") if err != nil { return nil, err @@ -90,6 +92,8 @@ func (d *DeviceClient) ListDevices(udid string, platform appstoreconnect.DeviceP // RegisterDevice ... func (d *DeviceClient) RegisterDevice(testDevice devportalservice.TestDevice) (*appstoreconnect.Device, error) { + log.Debugf("Registering device") + cmd, err := d.client.createRequestCommand("register_device", "--udid", testDevice.DeviceID, "--name", testDevice.Title, diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/profiles.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/profiles.go index 73df42f..ed496b4 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/profiles.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship/profiles.go @@ -123,6 +123,8 @@ type AppInfo struct { // FindProfile ... func (c *ProfileClient) FindProfile(name string, profileType appstoreconnect.ProfileType) (autocodesign.Profile, error) { + log.Debugf("Locating provision profile") + cmd, err := c.client.createRequestCommand("list_profiles", profileNameArgKey, name, profileTypeArgKey, string(profileType), @@ -160,6 +162,8 @@ func (c *ProfileClient) FindProfile(name string, profileType appstoreconnect.Pro // DeleteProfile ... func (c *ProfileClient) DeleteProfile(id string) error { + log.Debugf("Deleting provisioning profile: %s", id) + cmd, err := c.client.createRequestCommand("delete_profile", "--id", id) if err != nil { return err @@ -175,6 +179,8 @@ func (c *ProfileClient) DeleteProfile(id string) error { // CreateProfile ... func (c *ProfileClient) CreateProfile(name string, profileType appstoreconnect.ProfileType, bundleID appstoreconnect.BundleID, certificateIDs []string, deviceIDs []string) (autocodesign.Profile, error) { + log.Debugf("Creating provisioning profile with name: %s", name) + cmd, err := c.client.createRequestCommand("create_profile", bundleIDIdentifierArgKey, bundleID.Attributes.Identifier, certificateIDArgKey, certificateIDs[0], @@ -211,6 +217,8 @@ func (c *ProfileClient) CreateProfile(name string, profileType appstoreconnect.P // FindBundleID ... func (c *ProfileClient) FindBundleID(bundleIDIdentifier string) (*appstoreconnect.BundleID, error) { + log.Debugf("Locating bundle id: %s", bundleIDIdentifier) + cmd, err := c.client.createRequestCommand("get_app", bundleIDIdentifierArgKey, bundleIDIdentifier, ) @@ -246,6 +254,8 @@ func (c *ProfileClient) FindBundleID(bundleIDIdentifier string) (*appstoreconnec // CreateBundleID ... func (c *ProfileClient) CreateBundleID(bundleIDIdentifier, appIDName string) (*appstoreconnect.BundleID, error) { + log.Debugf("Creating new bundle id with name: %s", bundleIDIdentifier) + cmd, err := c.client.createRequestCommand("create_app", bundleIDIdentifierArgKey, bundleIDIdentifier, bundleIDNameArgKey, appIDName, @@ -277,6 +287,8 @@ func (c *ProfileClient) CreateBundleID(bundleIDIdentifier, appIDName string) (*a // CheckBundleIDEntitlements ... func (c *ProfileClient) CheckBundleIDEntitlements(bundleID appstoreconnect.BundleID, appEntitlements autocodesign.Entitlements) error { + log.Debugf("Vaildating bundle id entitlements: %s", bundleID.ID) + entitlementsBytes, err := json.Marshal(appEntitlements) if err != nil { return err @@ -301,6 +313,8 @@ func (c *ProfileClient) CheckBundleIDEntitlements(bundleID appstoreconnect.Bundl // SyncBundleID ... func (c *ProfileClient) SyncBundleID(bundleID appstoreconnect.BundleID, appEntitlements autocodesign.Entitlements) error { + log.Debugf("Syncing bundle id for: %s", bundleID.ID) + entitlementsBytes, err := json.Marshal(appEntitlements) if err != nil { return err diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset/profile.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset/profile.go index 2b70c64..c685dd8 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset/profile.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset/profile.go @@ -1,8 +1,10 @@ package localcodesignasset import ( + "github.com/bitrise-io/go-xcode/profileutil" "github.com/bitrise-io/go-xcode/v2/autocodesign" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" + "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/time" ) // Profile ... @@ -14,6 +16,23 @@ type Profile struct { certificateIDs []string } +// NewProfile wraps a local profile in the autocodesign.Profile interface +func NewProfile(info profileutil.ProvisioningProfileInfoModel, content []byte) autocodesign.Profile { + return Profile{ + attributes: appstoreconnect.ProfileAttributes{ + Name: info.Name, + UUID: info.UUID, + ProfileContent: content, + Platform: getBundleIDPlatform(info.Type), + ExpirationDate: time.Time(info.ExpirationDate), + }, + id: "", // only in case of Developer Portal Profiles + bundleID: info.BundleID, + certificateIDs: nil, // only in case of Developer Portal Profiles + deviceIDs: nil, // only in case of Developer Portal Profiles + } +} + // ID ... func (p Profile) ID() string { return p.id @@ -49,3 +68,14 @@ func (p Profile) BundleID() (appstoreconnect.BundleID, error) { func (p Profile) Entitlements() (autocodesign.Entitlements, error) { return autocodesign.ParseRawProfileEntitlements(p.attributes.ProfileContent) } + +func getBundleIDPlatform(profileType profileutil.ProfileType) appstoreconnect.BundleIDPlatform { + switch profileType { + case profileutil.ProfileTypeIos, profileutil.ProfileTypeTvOs: + return appstoreconnect.IOS + case profileutil.ProfileTypeMacOs: + return appstoreconnect.MacOS + } + + return "" +} diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset/profileconverter.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset/profileconverter.go index add4296..30a1b4f 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset/profileconverter.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset/profileconverter.go @@ -5,8 +5,6 @@ import ( "github.com/bitrise-io/go-xcode/profileutil" "github.com/bitrise-io/go-xcode/v2/autocodesign" - "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/appstoreconnect" - "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/time" ) // ProvisioningProfileConverter ... @@ -33,28 +31,5 @@ func (c provisioningProfileConverter) ProfileInfoToProfile(info profileutil.Prov return nil, err } - return Profile{ - attributes: appstoreconnect.ProfileAttributes{ - Name: info.Name, - UUID: info.UUID, - ProfileContent: content, - Platform: getBundleIDPlatform(info.Type), - ExpirationDate: time.Time(info.ExpirationDate), - }, - id: "", // only in case of Developer Portal Profiles - bundleID: info.BundleID, - certificateIDs: nil, // only in case of Developer Portal Profiles - deviceIDs: nil, // only in case of Developer Portal Profiles - }, nil -} - -func getBundleIDPlatform(profileType profileutil.ProfileType) appstoreconnect.BundleIDPlatform { - switch profileType { - case profileutil.ProfileTypeIos, profileutil.ProfileTypeTvOs: - return appstoreconnect.IOS - case profileutil.ProfileTypeMacOs: - return appstoreconnect.MacOS - } - - return "" + return NewProfile(info, content), nil } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/mock_AssetWriter.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/mock_AssetWriter.go index a53643f..d95af49 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/mock_AssetWriter.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/mock_AssetWriter.go @@ -1,4 +1,4 @@ -// Code generated by mockery 2.9.4. DO NOT EDIT. +// Code generated by mockery v2.10.0. DO NOT EDIT. package autocodesign @@ -26,6 +26,20 @@ func (_m *MockAssetWriter) InstallCertificate(certificate certificateutil.Certif return r0 } +// InstallProfile provides a mock function with given fields: profile +func (_m *MockAssetWriter) InstallProfile(profile Profile) error { + ret := _m.Called(profile) + + var r0 error + if rf, ok := ret.Get(0).(func(Profile) error); ok { + r0 = rf(profile) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // Write provides a mock function with given fields: codesignAssetsByDistributionType func (_m *MockAssetWriter) Write(codesignAssetsByDistributionType map[DistributionType]AppCodesignAssets) error { ret := _m.Called(codesignAssetsByDistributionType) diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/profiledownloader/profiledownloader.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/profiledownloader/profiledownloader.go new file mode 100644 index 0000000..819c7e2 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/profiledownloader/profiledownloader.go @@ -0,0 +1,67 @@ +package profiledownloader + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/bitrise-io/go-steputils/input" + "github.com/bitrise-io/go-utils/filedownloader" + "github.com/bitrise-io/go-xcode/profileutil" + "github.com/bitrise-io/go-xcode/v2/autocodesign" + "github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset" +) + +type downloader struct { + urls []string + client *http.Client +} + +// New returns an implementation that can download from remote, local file paths +func New(profileURLs []string, client *http.Client) autocodesign.ProfileProvider { + return downloader{ + urls: profileURLs, + client: client, + } +} + +func (d downloader) IsAvailable() bool { + return len(d.urls) != 0 +} + +func (d downloader) GetProfiles() ([]autocodesign.LocalProfile, error) { + var profiles []autocodesign.LocalProfile + + for _, url := range d.urls { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + + downloader := filedownloader.NewWithContext(ctx, d.client) + fileProvider := input.NewFileProvider(downloader) + + content, err := fileProvider.Contents(url) + if err != nil { + return nil, err + } else if content == nil { + return nil, fmt.Errorf("profile (%s) is empty", url) + } + + parsedProfile, err := profileutil.ProvisioningProfileFromContent(content) + if err != nil { + return nil, fmt.Errorf("invalid pkcs7 file format: %w", err) + } + + profileInfo, err := profileutil.NewProvisioningProfileInfo(*parsedProfile) + if err != nil { + return nil, fmt.Errorf("unknown provisioning profile format: %w", err) + } + + profiles = append(profiles, autocodesign.LocalProfile{ + Profile: localcodesignasset.NewProfile(profileInfo, content), + Info: profileInfo, + }) + } + + return profiles, nil +} diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager/projecthelper.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager/projecthelper.go index 821d6f9..99de122 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager/projecthelper.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager/projecthelper.go @@ -54,11 +54,16 @@ func NewProjectHelper(projOrWSPath, schemeName, configurationName string) (*Proj return nil, fmt.Errorf("failed to find the main target of the scheme (%s): %s", schemeName, err) } - dependentTargets := mainTarget.DependentExecutableProductTargets() + var dependentTargets []xcodeproj.Target + for _, target := range xcproj.DependentTargetsOfTarget(mainTarget) { + if target.IsExecutableProduct() { + dependentTargets = append(dependentTargets, target) + } + } var uiTestTargets []xcodeproj.Target for _, target := range xcproj.Proj.Targets { - if target.IsUITestProduct() && target.DependesOn(mainTarget.ID) { + if target.IsUITestProduct() && target.DependsOn(mainTarget.ID) { uiTestTargets = append(uiTestTargets, target) } } @@ -414,6 +419,8 @@ func configuration(configurationName string, scheme xcscheme.Scheme, xcproj xcod // mainTargetOfScheme return the main target func mainTargetOfScheme(proj xcodeproj.XcodeProj, scheme xcscheme.Scheme) (xcodeproj.Target, error) { + log.Debugf("Searching %d for scheme main target: %s", len(scheme.BuildAction.BuildActionEntries), scheme.Name) + var blueIdent string for _, entry := range scheme.BuildAction.BuildActionEntries { if entry.BuildableReference.IsAppReference() { @@ -422,6 +429,8 @@ func mainTargetOfScheme(proj xcodeproj.XcodeProj, scheme xcscheme.Scheme) (xcode } } + log.Debugf("Searching %d targets for: %s", len(proj.Proj.Targets), blueIdent) + // Search for the main target for _, t := range proj.Proj.Targets { if t.ID == blueIdent { @@ -435,6 +444,8 @@ func mainTargetOfScheme(proj xcodeproj.XcodeProj, scheme xcscheme.Scheme) (xcode // findBuiltProject returns the Xcode project which will be built for the provided scheme, plus the scheme. // The scheme is returned as it could be found under the .xcworkspace, and opening based on name from the XcodeProj would fail. func findBuiltProject(pth, schemeName string) (xcodeproj.XcodeProj, xcscheme.Scheme, error) { + log.TInfof("Locating built project for xcode project: %s, scheme: %s", pth, schemeName) + scheme, schemeContainerDir, err := schemeint.Scheme(pth, schemeName) if err != nil { return xcodeproj.XcodeProj{}, xcscheme.Scheme{}, fmt.Errorf("could not get scheme with name %s from path %s", schemeName, pth) @@ -455,5 +466,7 @@ func findBuiltProject(pth, schemeName string) (xcodeproj.XcodeProj, xcscheme.Sch return xcodeproj.XcodeProj{}, xcscheme.Scheme{}, err } + log.TInfof("Located built project for scheme: %s", schemeName) + return xcodeProj, *scheme, nil } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager/projectmanager.go b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager/projectmanager.go index ecb3938..8676396 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager/projectmanager.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager/projectmanager.go @@ -64,7 +64,7 @@ func (p Project) Platform() (autocodesign.Platform, error) { return "", fmt.Errorf("failed to read project platform: %s", err) } - log.Printf("Platform: %s", platform) + log.Debugf("Platform: %s", platform) return platform, nil } @@ -88,7 +88,7 @@ func (p Project) GetAppLayout(uiTestTargets bool) (autocodesign.AppLayout, error return autocodesign.AppLayout{}, fmt.Errorf("failed to read project platform: %s", err) } - log.Printf("Platform: %s", platform) + log.Debugf("Platform: %s", platform) log.Printf("Application and App Extension targets:") for _, target := range p.projHelper.ArchivableTargets() { @@ -127,9 +127,13 @@ func (p Project) GetAppLayout(uiTestTargets bool) (autocodesign.AppLayout, error // ForceCodesignAssets ... func (p Project) ForceCodesignAssets(distribution autocodesign.DistributionType, codesignAssetsByDistributionType map[autocodesign.DistributionType]autocodesign.AppCodesignAssets) error { + archivableTargets := p.projHelper.ArchivableTargets() + var archivableTargetsCounter = 0 + fmt.Println() - log.Infof("Apply Bitrise managed codesigning on the executable targets") - for _, target := range p.projHelper.ArchivableTargets() { + log.TInfof("Apply Bitrise managed codesigning on the executable targets (up to: %d targets)", len(archivableTargets)) + + for _, target := range archivableTargets { fmt.Println() log.Infof(" Target: %s", target.Name) @@ -160,12 +164,17 @@ func (p Project) ForceCodesignAssets(distribution autocodesign.DistributionType, if err := p.projHelper.XcProj.ForceCodeSign(p.projHelper.Configuration, target.Name, teamID, codesignAssets.Certificate.SHA1Fingerprint, profile.Attributes().UUID); err != nil { return fmt.Errorf("failed to apply code sign settings for target (%s): %s", target.Name, err) } + + archivableTargetsCounter++ } + log.TInfof("Applied Bitrise managed codesigning on up to %s targets", archivableTargetsCounter) + devCodesignAssets, isDevelopmentAvailable := codesignAssetsByDistributionType[autocodesign.Development] if isDevelopmentAvailable && len(devCodesignAssets.UITestTargetProfilesByBundleID) != 0 { fmt.Println() - log.Infof("Apply Bitrise managed codesigning on the UITest targets") + log.TInfof("Apply Bitrise managed codesigning on the UITest targets (%d)", len(p.projHelper.UITestTargets)) + for _, uiTestTarget := range p.projHelper.UITestTargets { fmt.Println() log.Infof(" Target: %s", uiTestTarget.Name) @@ -197,6 +206,8 @@ func (p Project) ForceCodesignAssets(distribution autocodesign.DistributionType, return fmt.Errorf("failed to save project: %s", err) } + log.Debugf("Xcode project saved.") + return nil } diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/codesign/codesign.go b/vendor/github.com/bitrise-io/go-xcode/v2/codesign/codesign.go index 24b077a..2519ae3 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/codesign/codesign.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/codesign/codesign.go @@ -1,11 +1,11 @@ package codesign import ( - "errors" "fmt" "github.com/bitrise-io/go-utils/v2/log" "github.com/bitrise-io/go-xcode/appleauth" + "github.com/bitrise-io/go-xcode/certificateutil" "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/v2/autocodesign" "github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient" @@ -51,9 +51,10 @@ type Manager struct { opts Opts appleAuthCredentials appleauth.Credentials - bitriseConnection *devportalservice.AppleDeveloperConnection + bitriseTestDevices []devportalservice.TestDevice devPortalClientFactory devportalclient.Factory certDownloader autocodesign.CertificateProvider + fallbackProfileDownloader autocodesign.ProfileProvider assetInstaller autocodesign.AssetWriter localCodeSignAssetManager autocodesign.LocalCodeSignAssetManager @@ -67,9 +68,10 @@ type Manager struct { func NewManagerWithArchive( opts Opts, appleAuth appleauth.Credentials, - connection *devportalservice.AppleDeveloperConnection, + bitriseTestDevices []devportalservice.TestDevice, clientFactory devportalclient.Factory, certDownloader autocodesign.CertificateProvider, + fallbackProfileDownloader autocodesign.ProfileProvider, assetInstaller autocodesign.AssetWriter, localCodeSignAssetManager autocodesign.LocalCodeSignAssetManager, archive Archive, @@ -78,9 +80,10 @@ func NewManagerWithArchive( return Manager{ opts: opts, appleAuthCredentials: appleAuth, - bitriseConnection: connection, + bitriseTestDevices: bitriseTestDevices, devPortalClientFactory: clientFactory, certDownloader: certDownloader, + fallbackProfileDownloader: fallbackProfileDownloader, assetInstaller: assetInstaller, localCodeSignAssetManager: localCodeSignAssetManager, detailsProvider: archive, @@ -92,9 +95,10 @@ func NewManagerWithArchive( func NewManagerWithProject( opts Opts, appleAuth appleauth.Credentials, - connection *devportalservice.AppleDeveloperConnection, + bitriseTestDevices []devportalservice.TestDevice, clientFactory devportalclient.Factory, certDownloader autocodesign.CertificateProvider, + fallbackProfileDownloader autocodesign.ProfileProvider, assetInstaller autocodesign.AssetWriter, localCodeSignAssetManager autocodesign.LocalCodeSignAssetManager, project projectmanager.Project, @@ -103,9 +107,10 @@ func NewManagerWithProject( return Manager{ opts: opts, appleAuthCredentials: appleAuth, - bitriseConnection: connection, + bitriseTestDevices: bitriseTestDevices, devPortalClientFactory: clientFactory, certDownloader: certDownloader, + fallbackProfileDownloader: fallbackProfileDownloader, assetInstaller: assetInstaller, localCodeSignAssetManager: localCodeSignAssetManager, detailsProvider: project, @@ -141,14 +146,25 @@ func (m *Manager) PrepareCodesigning() (*devportalservice.APIKeyConnection, erro m.logger.Infof("Code signing asset management with xcodebuild") m.logger.Printf("Reason: %s", reason) m.logger.Println() - m.logger.Infof("Downloading certificates from Bitrise") - if err := m.downloadAndInstallCertificates(); err != nil { + m.logger.TInfof("Downloading certificates...") + certificates, err := m.downloadCertificates() + if err != nil { + return nil, err + } + + if err := m.validateCertificatesForXcodeManagedSigning(certificates); err != nil { + return nil, err + } + + m.logger.Println() + m.logger.TInfof("Installing certificates...") + if err := m.installCertificates(certificates); err != nil { return nil, err } needsTestDevices := autocodesign.DistributionTypeRequiresDeviceList([]autocodesign.DistributionType{m.opts.ExportMethod}) - if needsTestDevices && m.opts.RegisterTestDevices && m.bitriseConnection != nil && len(m.bitriseConnection.TestDevices) != 0 { - if err := m.registerTestDevices(m.appleAuthCredentials, m.bitriseConnection.TestDevices); err != nil { + if needsTestDevices && m.opts.RegisterTestDevices && len(m.bitriseTestDevices) != 0 { + if err := m.registerTestDevices(m.appleAuthCredentials, m.bitriseTestDevices); err != nil { return nil, err } } @@ -160,7 +176,7 @@ func (m *Manager) PrepareCodesigning() (*devportalservice.APIKeyConnection, erro m.logger.Println() m.logger.Infof("Code signing asset management by Bitrise") m.logger.Printf("Reason: %s", reason) - if err := m.prepareCodeSigningWithBitrise(m.appleAuthCredentials); err != nil { + if err := m.prepareCodeSigningWithBitrise(m.appleAuthCredentials, m.bitriseTestDevices); err != nil { return nil, err } @@ -171,48 +187,63 @@ func (m *Manager) PrepareCodesigning() (*devportalservice.APIKeyConnection, erro } } -// SelectConnectionCredentials ... -func SelectConnectionCredentials(authType AuthType, conn *devportalservice.AppleDeveloperConnection, logger log.Logger) (appleauth.Credentials, error) { - var authSource appleauth.Source - - switch authType { - case APIKeyAuth: - authSource = &appleauth.ConnectionAPIKeySource{} - case AppleIDAuth: - authSource = &appleauth.ConnectionAppleIDFastlaneSource{} - default: - panic("missing implementation") +// SelectConnectionCredentials selects the final credentials for Apple services based on: +// - connections set up on Bitrise.io (globally for app) +// - step inputs for overriding the global config +func SelectConnectionCredentials( + authType AuthType, + bitriseConnection *devportalservice.AppleDeveloperConnection, + inputs ConnectionOverrideInputs, logger log.Logger) (appleauth.Credentials, error) { + if authType == APIKeyAuth && inputs.APIKeyPath != "" && inputs.APIKeyIssuerID != "" && inputs.APIKeyID != "" { + logger.Infof("Overriding Bitrise Apple Service connection with Step-provided credentials (api_key_path, api_key_id, api_key_issuer_id)") + + config, err := parseConnectionOverrideConfig(inputs.APIKeyPath, inputs.APIKeyID, inputs.APIKeyIssuerID, logger) + if err != nil { + return appleauth.Credentials{}, err + } + return appleauth.Credentials{ + APIKey: config, + AppleID: nil, + }, nil } - authConfig, err := appleauth.Select(conn, []appleauth.Source{authSource}, appleauth.Inputs{}) - if err != nil { - if conn != nil && conn.APIKeyConnection == nil && conn.AppleIDConnection == nil { - fmt.Println() - logger.Warnf("%s", devportalclient.NotConnectedWarning) + if authType == APIKeyAuth { + if bitriseConnection == nil || bitriseConnection.APIKeyConnection == nil { + logger.Errorf(devportalclient.NotConnectedWarning) + return appleauth.Credentials{}, fmt.Errorf("API key authentication is selected in Step inputs, but Bitrise Apple Service connection is unset") } - if errors.Is(err, &appleauth.MissingAuthConfigError{}) { - if authType == AppleIDAuth { - return appleauth.Credentials{}, fmt.Errorf("Apple ID authentication is selected in Step inputs, but Bitrise Apple Service connection is unset") - } + logger.Donef("Using Apple Service connection with API key.") + return appleauth.Credentials{ + APIKey: bitriseConnection.APIKeyConnection, + AppleID: nil, + }, nil + } - return appleauth.Credentials{}, fmt.Errorf("API key authentication is selected in Step inputs, but Bitrise Apple Service connection is unset") + if authType == AppleIDAuth { + if bitriseConnection == nil || bitriseConnection.AppleIDConnection == nil { + logger.Errorf(devportalclient.NotConnectedWarning) + return appleauth.Credentials{}, fmt.Errorf("Apple ID authentication is selected in Step inputs, but Bitrise Apple Service connection is unset") } - return appleauth.Credentials{}, fmt.Errorf("could not select Apple authentication credentials: %w", err) - } + session, err := bitriseConnection.AppleIDConnection.FastlaneLoginSession() + if err != nil { + return appleauth.Credentials{}, err + } - if authConfig.APIKey != nil { - authConfig.AppleID = nil - logger.Donef("Using Apple Service connection with API key.") - } else if authConfig.AppleID != nil { - authConfig.APIKey = nil logger.Donef("Using Apple Service connection with Apple ID.") - } else { - panic("No Apple authentication credentials found.") + return appleauth.Credentials{ + AppleID: &appleauth.AppleID{ + Username: bitriseConnection.AppleIDConnection.AppleID, + Password: bitriseConnection.AppleIDConnection.Password, + Session: session, + AppSpecificPassword: bitriseConnection.AppleIDConnection.AppSpecificPassword, + }, + APIKey: nil, + }, nil } - return authConfig, nil + panic("Unexpected AuthType") } func (m *Manager) selectCodeSigningStrategy(credentials appleauth.Credentials) (codeSigningStrategy, string, error) { @@ -250,22 +281,48 @@ func (m *Manager) selectCodeSigningStrategy(credentials appleauth.Credentials) ( return codeSigningXcode, "Automatically managed signing is enabled in Xcode for the project.", nil } -func (m *Manager) downloadAndInstallCertificates() error { +func (m *Manager) downloadCertificates() ([]certificateutil.CertificateInfoModel, error) { certificates, err := m.certDownloader.GetCertificates() if err != nil { - return fmt.Errorf("failed to download certificates: %s", err) + return nil, fmt.Errorf("failed to download certificates: %s", err) } - certificateType, ok := autocodesign.CertificateTypeByDistribution[m.opts.ExportMethod] - if !ok { - panic(fmt.Sprintf("no valid certificate provided for distribution type: %s", m.opts.ExportMethod)) + if len(certificates) == 0 { + m.logger.Warnf("No certificates are uploaded.") + + return nil, nil + } + + m.logger.Printf("%d certificates downloaded:", len(certificates)) + for _, cert := range certificates { + m.logger.Printf("- %s", cert) + } + + return certificates, nil +} + +func (m *Manager) installCertificates(certificates []certificateutil.CertificateInfoModel) error { + for _, cert := range certificates { + // Empty passphrase provided, as already parsed certificate + private key + if err := m.assetInstaller.InstallCertificate(cert); err != nil { + return err + } } + return nil +} + +func (m *Manager) validateCertificatesForXcodeManagedSigning(certificates []certificateutil.CertificateInfoModel) error { typeToLocalCerts, err := autocodesign.GetValidLocalCertificates(certificates) if err != nil { return err } + certificateType, ok := autocodesign.CertificateTypeByDistribution[m.opts.ExportMethod] + if !ok { + panic(fmt.Sprintf("no valid certificate provided for distribution type: %s", m.opts.ExportMethod)) + } + if len(typeToLocalCerts[certificateType]) == 0 { if certificateType == appstoreconnect.IOSDevelopment { return fmt.Errorf("no valid development type certificate uploaded") @@ -274,15 +331,6 @@ func (m *Manager) downloadAndInstallCertificates() error { m.logger.Warnf("no valid %s type certificate uploaded", certificateType) } - m.logger.Infof("Installing downloaded certificates:") - for _, cert := range certificates { - m.logger.Printf("- %s", cert) - // Empty passphrase provided, as already parsed certificate + private key - if err := m.assetInstaller.InstallCertificate(cert); err != nil { - return err - } - } - return nil } @@ -305,10 +353,10 @@ func (m *Manager) registerTestDevices(credentials appleauth.Credentials, devices return nil } -func (m *Manager) prepareCodeSigningWithBitrise(credentials appleauth.Credentials) error { +func (m *Manager) prepareCodeSigningWithBitrise(credentials appleauth.Credentials, testDevices []devportalservice.TestDevice) error { // Analyze project fmt.Println() - m.logger.Infof("Analyzing project") + m.logger.TDebugf("Analyzing project") appLayout, err := m.detailsProvider.GetAppLayout(m.opts.SignUITests) if err != nil { return err @@ -319,21 +367,44 @@ func (m *Manager) prepareCodeSigningWithBitrise(credentials appleauth.Credential return err } - manager := autocodesign.NewCodesignAssetManager(devPortalClient, m.certDownloader, m.assetInstaller, m.localCodeSignAssetManager) + fmt.Println() + m.logger.TDebugf("Downloading certificates") + certs, err := m.downloadCertificates() + if err != nil { + return err + } + + typeToLocalCerts, err := autocodesign.GetValidLocalCertificates(certs) + if err != nil { + return err + } + + manager := autocodesign.NewCodesignAssetManager(devPortalClient, m.assetInstaller, m.localCodeSignAssetManager) // Fetch and apply codesigning assets - var testDevices []devportalservice.TestDevice - if m.opts.RegisterTestDevices && m.bitriseConnection != nil { - testDevices = m.bitriseConnection.TestDevices + var testDevicesToRegister []devportalservice.TestDevice + if m.opts.RegisterTestDevices { + testDevicesToRegister = testDevices } + codesignAssetsByDistributionType, err := manager.EnsureCodesignAssets(appLayout, autocodesign.CodesignAssetsOpts{ - DistributionType: m.opts.ExportMethod, - BitriseTestDevices: testDevices, - MinProfileValidityDays: m.opts.MinDaysProfileValidity, - VerboseLog: m.opts.IsVerboseLog, + DistributionType: m.opts.ExportMethod, + TypeToLocalCertificates: typeToLocalCerts, + BitriseTestDevices: testDevicesToRegister, + MinProfileValidityDays: m.opts.MinDaysProfileValidity, + VerboseLog: m.opts.IsVerboseLog, }) if err != nil { - return err + if !m.fallbackProfileDownloader.IsAvailable() { + return err + } + + m.logger.Println() + m.logger.Errorf("Automatic code signing failed: %s", err) + m.logger.Println() + m.logger.Infof("Falling back to manually managed codesigning assets.") + + return m.prepareManualAssets(certs) } if m.assetWriter != nil { @@ -344,3 +415,25 @@ func (m *Manager) prepareCodeSigningWithBitrise(credentials appleauth.Credential return nil } + +func (m *Manager) prepareManualAssets(certificates []certificateutil.CertificateInfoModel) error { + if err := m.installCertificates(certificates); err != nil { + return err + } + + profiles, err := m.fallbackProfileDownloader.GetProfiles() + if err != nil { + return fmt.Errorf("failed to fetch profiles: %w", err) + } + + m.logger.Printf("Installing manual profiles:") + for _, profile := range profiles { + m.logger.Printf("%s", profile.Info.String(certificates...)) + + if err := m.assetInstaller.InstallProfile(profile.Profile); err != nil { + return fmt.Errorf("failed to install profile: %w", err) + } + } + + return nil +} diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/codesign/inputparse.go b/vendor/github.com/bitrise-io/go-xcode/v2/codesign/inputparse.go index 82d1902..e29be1e 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/codesign/inputparse.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/codesign/inputparse.go @@ -1,32 +1,53 @@ package codesign import ( + "errors" "fmt" + "io" + "net/http" + "net/url" + "os" + "path/filepath" "strings" "github.com/bitrise-io/go-steputils/v2/stepconf" + "github.com/bitrise-io/go-utils/pathutil" "github.com/bitrise-io/go-utils/sliceutil" "github.com/bitrise-io/go-utils/v2/command" + "github.com/bitrise-io/go-utils/v2/log" + "github.com/bitrise-io/go-utils/v2/retryhttp" + "github.com/bitrise-io/go-xcode/devportalservice" "github.com/bitrise-io/go-xcode/v2/autocodesign" "github.com/bitrise-io/go-xcode/v2/autocodesign/certdownloader" + "github.com/bitrise-io/go-xcode/v2/autocodesign/codesignasset" "github.com/bitrise-io/go-xcode/v2/autocodesign/keychain" ) // Input ... type Input struct { - AuthType AuthType - DistributionMethod string - CertificateURLList string - CertificatePassphraseList stepconf.Secret - KeychainPath string - KeychainPassword stepconf.Secret + AuthType AuthType + DistributionMethod string + CertificateURLList string + CertificatePassphraseList stepconf.Secret + KeychainPath string + KeychainPassword stepconf.Secret + FallbackProvisioningProfiles string +} + +// ConnectionOverrideInputs are used in steps to control the API key based auth credentials +// This overrides the global API connection defined on Bitrise.io +type ConnectionOverrideInputs struct { + APIKeyPath stepconf.Secret + APIKeyID string + APIKeyIssuerID string } // Config ... type Config struct { - CertificatesAndPassphrases []certdownloader.CertificateAndPassphrase - Keychain keychain.Keychain - DistributionMethod autocodesign.DistributionType + CertificatesAndPassphrases []certdownloader.CertificateAndPassphrase + Keychain keychain.Keychain + DistributionMethod autocodesign.DistributionType + FallbackProvisioningProfiles []string } // ParseConfig validates and parses step inputs related to code signing and returns with a Config @@ -41,10 +62,60 @@ func ParseConfig(input Input, cmdFactory command.Factory) (Config, error) { return Config{}, fmt.Errorf("failed to open keychain: %s", err) } + fallbackProfiles, err := validateAndExpandProfilePaths(input.FallbackProvisioningProfiles) + if err != nil { + return Config{}, fmt.Errorf("failed to parse provisioning profiles: %w", err) + } + return Config{ - CertificatesAndPassphrases: certificatesAndPassphrases, - Keychain: *keychainWriter, - DistributionMethod: autocodesign.DistributionType(input.DistributionMethod), + CertificatesAndPassphrases: certificatesAndPassphrases, + Keychain: *keychainWriter, + DistributionMethod: autocodesign.DistributionType(input.DistributionMethod), + FallbackProvisioningProfiles: fallbackProfiles, + }, nil +} + +// parseConnectionOverrideConfig validates and parses the step input-level connection parameters +func parseConnectionOverrideConfig(keyPathOrURL stepconf.Secret, keyID, keyIssuerID string, logger log.Logger) (*devportalservice.APIKeyConnection, error) { + var key []byte + if strings.HasPrefix(string(keyPathOrURL), "https://") { + resp, err := retryhttp.NewClient(logger).Get(string(keyPathOrURL)) + if err != nil { + return nil, fmt.Errorf("API key download error: %s", err) + } + + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + logger.Errorf(err.Error()) + } + }(resp.Body) + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("API key HTTP response %d: %s", resp.StatusCode, resp.Body) + } + + key, err = io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + } else { + trimmedPath := string(keyPathOrURL) + if strings.HasPrefix(string(keyPathOrURL), "file://") { + trimmedPath = strings.TrimPrefix(string(keyPathOrURL), "file://") + } + var err error + key, err = os.ReadFile(trimmedPath) + if errors.Is(err, os.ErrNotExist) { + return nil, fmt.Errorf("private key does not exist at %s", trimmedPath) + } else if err != nil { + return nil, err + } + } + + return &devportalservice.APIKeyConnection{ + KeyID: strings.TrimSpace(keyID), + IssuerID: strings.TrimSpace(keyIssuerID), + PrivateKey: string(key), }, nil } @@ -92,3 +163,67 @@ func validateCertificates(certURLList string, certPassphraseList string) ([]stri func splitAndClean(list string, sep string, omitEmpty bool) (items []string) { return sliceutil.CleanWhitespace(strings.Split(list, sep), omitEmpty) } + +// validateAndExpandProfilePaths validates and expands profilesList. +// profilesList must be a list of paths separated either by `|` or `\n`. +// List items must be a remote (https://) or local (file://) file paths, +// or a local directory (with no scheme). +// For directory list items, the contained profiles' path will be returned. +func validateAndExpandProfilePaths(profilesList string) ([]string, error) { + profiles := splitAndClean(profilesList, "\n", true) + if len(profiles) == 1 { + profiles = splitAndClean(profiles[0], "|", true) + } + + var validProfiles []string + for _, profile := range profiles { + profileURL, err := url.Parse(profile) + if err != nil { + return []string{}, fmt.Errorf("invalid provisioning profile URL (%s): %w", profile, err) + } + + // When file or https scheme provided, will fetch as a file + if profileURL.Scheme != "" { + validProfiles = append(validProfiles, profile) + continue + } + + // If no scheme is provided, assuming it is a local directory + profilesInDir, err := listProfilesInDirectory(profile) + if err != nil { + return []string{}, err + } + + validProfiles = append(validProfiles, profilesInDir...) + } + + return validProfiles, nil +} + +func listProfilesInDirectory(dir string) ([]string, error) { + exists, err := pathutil.IsDirExists(dir) + if err != nil { + return nil, fmt.Errorf("failed to check if provisioning profile path (%s) exists: %w", dir, err) + } else if !exists { + return nil, fmt.Errorf("please provide remote (https://) or local (file://) provisioning profile file paths with a scheme, or a local directory without a scheme: profile directory (%s) does not exist", dir) + } + + dirEntries, err := os.ReadDir(dir) + if err != nil { + return nil, fmt.Errorf("failed to list profile directory: %w", err) + } + + var profiles []string + for _, dirEntry := range dirEntries { + if dirEntry.Type().IsDir() || !dirEntry.Type().IsRegular() { + continue + } + + if strings.HasSuffix(dirEntry.Name(), codesignasset.ProfileIOSExtension) { + profileURL := fmt.Sprintf("file://%s", filepath.Join(dir, dirEntry.Name())) + profiles = append(profiles, profileURL) + } + } + + return profiles, nil +} diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/xcarchive/ios.go b/vendor/github.com/bitrise-io/go-xcode/v2/xcarchive/ios.go index f2766ae..0431550 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/xcarchive/ios.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/xcarchive/ios.go @@ -43,6 +43,8 @@ func (archive IosArchive) ReadCodesignParameters() (*autocodesign.AppLayout, err bundleIDEntitlementsMap := archive.BundleIDEntitlementsMap() + fmt.Printf("Reading %v code sign entitlements", len(bundleIDEntitlementsMap)) + entitlementsMap := map[string]autocodesign.Entitlements{} for bundleID, entitlements := range bundleIDEntitlementsMap { entitlementsMap[bundleID] = autocodesign.Entitlements(entitlements) diff --git a/vendor/github.com/bitrise-io/go-xcode/xcarchive/entitlements.go b/vendor/github.com/bitrise-io/go-xcode/xcarchive/entitlements.go index 806aefa..7908e5c 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcarchive/entitlements.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcarchive/entitlements.go @@ -1,6 +1,7 @@ package xcarchive import ( + "fmt" "path/filepath" "github.com/bitrise-io/go-utils/command" @@ -28,6 +29,8 @@ func getEntitlements(basePath, executableRelativePath string) (plistutil.PlistDa } func entitlementsFromExecutable(basePath, executableRelativePath string) (*plistutil.PlistData, error) { + fmt.Printf("Fetching entitlements from executable") + cmd := command.New("codesign", "--display", "--entitlements", ":-", filepath.Join(basePath, executableRelativePath)) entitlementsString, err := cmd.RunAndReturnTrimmedOutput() if err != nil { diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/build.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/build.go index de4291c..166b7e1 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/build.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/build.go @@ -3,10 +3,16 @@ package xcodebuild import ( "os" "os/exec" + "path/filepath" "github.com/bitrise-io/go-utils/command" ) +const ( + // XCWorkspaceExtension ... + XCWorkspaceExtension = ".xcworkspace" +) + /* xcodebuild [-project ] \ -scheme \ @@ -28,48 +34,32 @@ xcodebuild -workspace \ []... */ -// const ... -const ( - ArchiveAction Action = "archiveAction" - BuildAction Action = "buildAction" - AnalyzeAction Action = "analyzeAction" -) - -// Action ... -type Action string - // CommandBuilder ... type CommandBuilder struct { - projectPath string - isWorkspace bool - scheme string - configuration string - destination string - xcconfigPath string - authentication *AuthenticationParams - - // buildsetting - disableCodesign bool - - // buildaction - customBuildActions []string + actions []string // Options + projectPath string + scheme string + configuration string + destination string + xcconfigPath string + authentication *AuthenticationParams archivePath string customOptions []string sdk string resultBundlePath string + testPlan string - // Archive - action Action + // buildsetting + disableCodesign bool } // NewCommandBuilder ... -func NewCommandBuilder(projectPath string, isWorkspace bool, action Action) *CommandBuilder { +func NewCommandBuilder(projectPath string, actions ...string) *CommandBuilder { return &CommandBuilder{ projectPath: projectPath, - isWorkspace: isWorkspace, - action: action, + actions: actions, } } @@ -103,12 +93,6 @@ func (c *CommandBuilder) SetAuthentication(authenticationParams AuthenticationPa return c } -// SetCustomBuildAction ... -func (c *CommandBuilder) SetCustomBuildAction(buildAction ...string) *CommandBuilder { - c.customBuildActions = buildAction - return c -} - // SetArchivePath ... func (c *CommandBuilder) SetArchivePath(archivePath string) *CommandBuilder { c.archivePath = archivePath @@ -139,11 +123,18 @@ func (c *CommandBuilder) SetDisableCodesign(disable bool) *CommandBuilder { return c } +// SetTestPlan ... +func (c *CommandBuilder) SetTestPlan(testPlan string) *CommandBuilder { + c.testPlan = testPlan + return c +} + func (c *CommandBuilder) cmdSlice() []string { slice := []string{toolName} + slice = append(slice, c.actions...) if c.projectPath != "" { - if c.isWorkspace { + if filepath.Ext(c.projectPath) == XCWorkspaceExtension { slice = append(slice, "-workspace", c.projectPath) } else { slice = append(slice, "-project", c.projectPath) @@ -167,23 +158,8 @@ func (c *CommandBuilder) cmdSlice() []string { slice = append(slice, "-xcconfig", c.xcconfigPath) } - if c.disableCodesign { - slice = append(slice, "CODE_SIGNING_ALLOWED=NO") - } - - slice = append(slice, c.customBuildActions...) - - switch c.action { - case ArchiveAction: - slice = append(slice, "archive") - - if c.archivePath != "" { - slice = append(slice, "-archivePath", c.archivePath) - } - case BuildAction: - slice = append(slice, "build") - case AnalyzeAction: - slice = append(slice, "analyze") + if c.archivePath != "" { + slice = append(slice, "-archivePath", c.archivePath) } if c.sdk != "" { @@ -198,6 +174,14 @@ func (c *CommandBuilder) cmdSlice() []string { slice = append(slice, c.authentication.args()...) } + if c.testPlan != "" { + slice = append(slice, "-testPlan", c.testPlan) + } + + if c.disableCodesign { + slice = append(slice, "CODE_SIGNING_ALLOWED=NO") + } + slice = append(slice, c.customOptions...) return slice diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/resolve_package_deps.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/resolve_package_deps.go new file mode 100644 index 0000000..6e93b77 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/resolve_package_deps.go @@ -0,0 +1,85 @@ +package xcodebuild + +import ( + "fmt" + "path/filepath" + + "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/errorutil" + "github.com/bitrise-io/go-utils/log" +) + +// ResolvePackagesCommandModel is a command builder +// used to create `xcodebuild -resolvePackageDependencies` command +type ResolvePackagesCommandModel struct { + projectPath string + scheme string + configuration string + + customOptions []string +} + +// NewResolvePackagesCommandModel returns a new ResolvePackagesCommandModel +func NewResolvePackagesCommandModel(projectPath, scheme, configuration string) *ResolvePackagesCommandModel { + return &ResolvePackagesCommandModel{ + projectPath: projectPath, + scheme: scheme, + configuration: configuration, + } +} + +// SetCustomOptions sets custom options +func (m *ResolvePackagesCommandModel) SetCustomOptions(customOptions []string) *ResolvePackagesCommandModel { + m.customOptions = customOptions + return m +} + +func (m *ResolvePackagesCommandModel) cmdSlice() []string { + slice := []string{toolName} + + if m.projectPath != "" { + if filepath.Ext(m.projectPath) == ".xcworkspace" { + slice = append(slice, "-workspace", m.projectPath) + } else { + slice = append(slice, "-project", m.projectPath) + } + } + + if m.scheme != "" { + slice = append(slice, "-scheme", m.scheme) + } + + if m.configuration != "" { + slice = append(slice, "-configuration", m.configuration) + } + + slice = append(slice, "-resolvePackageDependencies") + slice = append(slice, m.customOptions...) + + return slice +} + +// Command returns the executable command +func (m *ResolvePackagesCommandModel) command() command.Model { + cmdSlice := m.cmdSlice() + return *command.NewWithStandardOuts(cmdSlice[0], cmdSlice[1:]...) +} + +// Run runs the command and logs elapsed time +func (m *ResolvePackagesCommandModel) Run() error { + var cmd = m.command() + + log.TPrintf("Resolving package dependencies...") + + log.TDonef("$ %s", cmd.PrintableCommandArgs()) + if err := cmd.Run(); err != nil { + if errorutil.IsExitStatusError(err) { + return fmt.Errorf("failed to resolve package dependencies") + } + return fmt.Errorf("failed to run command: %s", err) + } + + log.TPrintf("Resolved package dependencies.") + + return nil +} diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/show_build_settings.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/show_build_settings.go index 32f256b..b548ffc 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/show_build_settings.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/show_build_settings.go @@ -8,6 +8,7 @@ import ( "github.com/bitrise-io/go-utils/command" "github.com/bitrise-io/go-utils/errorutil" + "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-xcode/xcodeproject/serialized" ) @@ -117,14 +118,20 @@ func parseBuildSettings(out string) (serialized.Object, error) { // RunAndReturnSettings ... func (c ShowBuildSettingsCommandModel) RunAndReturnSettings() (serialized.Object, error) { - cmd := c.Command() + var cmd = c.Command() + + log.TPrintf("Reading build settings...") + + log.TDonef("$ %s", cmd.PrintableCommandArgs()) out, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { if errorutil.IsExitStatusError(err) { - return nil, fmt.Errorf("%s command failed: output: %s", cmd.PrintableCommandArgs(), out) + return nil, fmt.Errorf("%s command failed, output: %s", cmd.PrintableCommandArgs(), out) } return nil, fmt.Errorf("failed to run command %s: %s", cmd.PrintableCommandArgs(), err) } + log.TPrintf("Read target settings.") + return parseBuildSettings(out) } diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/proj.go b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/proj.go index 8a49e10..c90c5b4 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/proj.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/proj.go @@ -3,6 +3,7 @@ package xcodeproj import ( "fmt" + "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-xcode/xcodeproject/serialized" ) @@ -15,6 +16,8 @@ type Proj struct { } func parseProj(id string, objects serialized.Object) (Proj, error) { + log.TDebugf("Parsing xcode project file with id: %s", id) + rawPBXProj, err := objects.Object(id) if err != nil { return Proj{}, fmt.Errorf("failed to access object with id %s: %s", id, err) @@ -59,6 +62,8 @@ func parseProj(id string, objects serialized.Object) (Proj, error) { targets = append(targets, target) } + log.TDebugf("Parsed xcode project file with id: %s, found %v targets.", id, len(targets)) + return Proj{ ID: id, BuildConfigurationList: buildConfigurationList, diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/recreate_schemes.go b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/recreate_schemes.go index 23ffaea..527d7d3 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/recreate_schemes.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/recreate_schemes.go @@ -44,6 +44,8 @@ func (p XcodeProj) SaveSharedScheme(scheme xcscheme.Scheme) error { // ReCreateSchemes creates new schemes based on the available Targets func (p XcodeProj) ReCreateSchemes() []xcscheme.Scheme { + fmt.Printf("Recreating xcode scheme") + var schemes []xcscheme.Scheme for _, buildTarget := range p.Proj.Targets { if buildTarget.Type != NativeTargetType || buildTarget.IsTest() { @@ -52,7 +54,7 @@ func (p XcodeProj) ReCreateSchemes() []xcscheme.Scheme { var testTargets []Target for _, testTarget := range p.Proj.Targets { - if testTarget.IsTest() && testTarget.DependesOn(buildTarget.ID) { + if testTarget.IsTest() && testTarget.DependsOn(buildTarget.ID) { testTargets = append(testTargets, testTarget) } } @@ -60,6 +62,8 @@ func (p XcodeProj) ReCreateSchemes() []xcscheme.Scheme { schemes = append(schemes, newScheme(buildTarget, testTargets, filepath.Base(p.Path))) } + fmt.Printf("Recreated %v xcode schemes", len(schemes)) + return schemes } diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/target.go b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/target.go index 31cdb6b..4b34e9e 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/target.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/target.go @@ -4,6 +4,7 @@ import ( "fmt" "path/filepath" + "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-xcode/xcodeproject/serialized" ) @@ -17,6 +18,8 @@ const ( LegacyTargetType TargetType = "PBXLegacyTarget" ) +const appClipProductType = "com.apple.product-type.application.on-demand-install-capable" + // Target ... type Target struct { Type TargetType @@ -29,49 +32,16 @@ type Target struct { buildPhaseIDs []string } -// DependentTargets ... -func (t Target) DependentTargets() []Target { - var targets []Target +// DependsOn ... +func (t Target) DependsOn(targetID string) bool { for _, targetDependency := range t.Dependencies { - childTarget := targetDependency.Target - targets = append(targets, childTarget) - - childDependentTargets := childTarget.DependentTargets() - targets = append(targets, childDependentTargets...) - } - - return targets -} - -// DependesOn ... -func (t Target) DependesOn(targetID string) bool { - for _, targetDependency := range t.Dependencies { - childTarget := targetDependency.Target - if childTarget.ID == targetID { + if targetDependency.TargetID == targetID { return true } } return false } -// DependentExecutableProductTargets ... -func (t Target) DependentExecutableProductTargets() []Target { - var targets []Target - for _, targetDependency := range t.Dependencies { - childTarget := targetDependency.Target - if !childTarget.IsExecutableProduct() { - continue - } - - targets = append(targets, childTarget) - - childDependentTargets := childTarget.DependentExecutableProductTargets() - targets = append(targets, childDependentTargets...) - } - - return targets -} - // IsAppProduct ... func (t Target) IsAppProduct() bool { return filepath.Ext(t.ProductReference.Path) == ".app" @@ -105,6 +75,11 @@ func (t Target) IsUITestProduct() bool { return filepath.Ext(t.ProductType) == ".ui-testing" } +// IsAppClipProduct ... +func (t Target) IsAppClipProduct() bool { + return t.ProductType == appClipProductType +} + func parseTarget(id string, objects serialized.Object) (Target, error) { rawTarget, err := objects.Object(id) if err != nil { @@ -143,17 +118,24 @@ func parseTarget(id string, objects serialized.Object) (Target, error) { return Target{}, err } + log.TDebugf("Parsing build configuration list for target: %s", id) + buildConfigurationList, err := parseConfigurationList(buildConfigurationListID, objects) if err != nil { return Target{}, err } + log.TDebugf("Parsed build configuration list") + dependencyIDs, err := rawTarget.StringSlice("dependencies") if err != nil { return Target{}, err } var dependencies []TargetDependency + + log.TDebugf("Parsing all target dependencies for target: %s", id) + for _, dependencyID := range dependencyIDs { dependency, err := parseTargetDependency(dependencyID, objects) if err != nil { @@ -169,6 +151,8 @@ func parseTarget(id string, objects serialized.Object) (Target, error) { dependencies = append(dependencies, dependency) } + log.TDebugf("Parsed %v target dependencies", len(dependencies)) + var productReference ProductReference productReferenceID, err := rawTarget.String("productReference") if err != nil { diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/target_dependency.go b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/target_dependency.go index bc1cd90..8aaafa2 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/target_dependency.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/target_dependency.go @@ -2,10 +2,10 @@ package xcodeproj import "github.com/bitrise-io/go-xcode/xcodeproject/serialized" -// TargetDependency ... +// TargetDependency is a reference to another Target that is a dependency of a given Target type TargetDependency struct { - ID string - Target Target + id string + TargetID string } func parseTargetDependency(id string, objects serialized.Object) (TargetDependency, error) { @@ -19,13 +19,8 @@ func parseTargetDependency(id string, objects serialized.Object) (TargetDependen return TargetDependency{}, err } - target, err := parseTarget(targetID, objects) - if err != nil { - return TargetDependency{}, err - } - return TargetDependency{ - ID: id, - Target: target, + id: id, + TargetID: targetID, }, nil } diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/xcodeproj.go b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/xcodeproj.go index 34d67df..ceb92ca 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/xcodeproj.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj/xcodeproj.go @@ -106,6 +106,30 @@ func (p XcodeProj) TargetInfoplistPath(target, configuration string) (string, er return p.buildSettingsFilePath(target, configuration, "INFOPLIST_FILE") } +// DependentTargetsOfTarget returns with all dependencies of a given target, including the transitive dependencies. +// The returned list contains each target only once, using the target ID for uniqueness. +func (p XcodeProj) DependentTargetsOfTarget(target Target) []Target { + var dependentTargets []Target + + log.TDebugf("Locating all dependencies of target: %s", target.Name) + + for _, dependency := range target.Dependencies { + childTarget, ok := p.Proj.Target(dependency.TargetID) + if !ok { + log.Warnf("couldn't find dependency %s of target %s (%s), skipping", dependency.TargetID, target.Name, target.ID) + continue + } + dependentTargets = append(dependentTargets, childTarget) + + childDependentTargets := p.DependentTargetsOfTarget(childTarget) + dependentTargets = append(dependentTargets, childDependentTargets...) + } + + log.TDebugf("Located %v dependencies of target: %s", len(dependentTargets), target.Name) + + return deduplicateTargetList(dependentTargets) +} + // ReadTargetInfoplist ... func (p XcodeProj) ReadTargetInfoplist(target, configuration string) (serialized.Object, int, error) { informationPropertyListPth, err := p.TargetInfoplistPath(target, configuration) @@ -182,7 +206,7 @@ func (p XcodeProj) TargetBundleID(target, configuration string) (string, error) } if bundleID != "" { - return Resolve(bundleID, buildSettings) + return resolve(bundleID, buildSettings) } informationPropertyList, _, err := p.ReadTargetInfoplist(target, configuration) @@ -199,16 +223,16 @@ func (p XcodeProj) TargetBundleID(target, configuration string) (string, error) return "", errors.New("no PRODUCT_BUNDLE_IDENTIFIER build settings nor CFBundleIdentifier information property found") } - return Resolve(bundleID, buildSettings) + return resolve(bundleID, buildSettings) } -// Resolve returns the resolved bundleID. We need this, because the bundleID is not exposed in the .pbxproj file ( raw ). +// resolve returns the resolved bundleID. We need this, because the bundleID is not exposed in the .pbxproj file ( raw ). // If the raw BundleID contains an environment variable we have to replace it. // // **Example:** // BundleID in the .pbxproj: Bitrise.Test.$(PRODUCT_NAME:rfc1034identifier).Suffix // BundleID after the env is expanded: Bitrise.Test.Sample.Suffix -func Resolve(bundleID string, buildSettings serialized.Object) (string, error) { +func resolve(bundleID string, buildSettings serialized.Object) (string, error) { resolvedBundleIDs := map[string]bool{} resolved := bundleID for true { @@ -325,7 +349,13 @@ func (p XcodeProj) Scheme(name string) (*xcscheme.Scheme, string, error) { // Schemes ... func (p XcodeProj) Schemes() ([]xcscheme.Scheme, error) { - return xcscheme.FindSchemesIn(p.Path) + log.TDebugf("Locating scheme for project path: %s", p.Path) + + schemes, err := xcscheme.FindSchemesIn(p.Path) + + log.TDebugf("Located %v schemes", len(schemes)) + + return schemes, err } // Open ... @@ -350,6 +380,8 @@ func Open(pth string) (XcodeProj, error) { p.Path = absPth p.Name = strings.TrimSuffix(filepath.Base(absPth), filepath.Ext(absPth)) + log.TDebugf("Opened xcode project") + return *p, nil } @@ -521,7 +553,13 @@ func writeAttributeForAllSDKs(buildSettings serialized.Object, newKey string, ne // // Overrides the project.pbxproj file of the XcodeProj with the contents of `rawProj` func (p XcodeProj) Save() error { - return p.savePBXProj() + log.Debugf("Saving PBX file") + + err := p.savePBXProj() + + log.Debugf("Saved PBX file") + + return err } // savePBXProj overrides the project.pbxproj file of the XcodeProj with the contents of `rawProj` @@ -709,3 +747,19 @@ func (p XcodeProj) perObjectModify() ([]byte, error) { return contentsMod, nil } + +func deduplicateTargetList(targets []Target) []Target { + inResult := make(map[string]bool) + uniqueTargets := []Target{} + + for _, target := range targets { + if _, ok := inResult[target.ID]; !ok { + inResult[target.ID] = true + uniqueTargets = append(uniqueTargets, target) + } + } + + log.Debugf("Deduplicating targets result: %v/%v", len(targets), len(uniqueTargets)) + + return uniqueTargets +} diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcscheme/xcscheme.go b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcscheme/xcscheme.go index 1748a1f..94a0884 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcscheme/xcscheme.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcscheme/xcscheme.go @@ -3,11 +3,14 @@ package xcscheme import ( "encoding/xml" "fmt" + "io" + "os" "path/filepath" "regexp" "strings" + "time" - "github.com/bitrise-io/go-utils/fileutil" + "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" ) @@ -25,6 +28,10 @@ func (r BuildableReference) IsAppReference() bool { return filepath.Ext(r.BuildableName) == ".app" } +func (r BuildableReference) isTestProduct() bool { + return filepath.Ext(r.BuildableName) == ".xctest" +} + // ReferencedContainerAbsPath ... func (r BuildableReference) ReferencedContainerAbsPath(schemeContainerDir string) (string, error) { s := strings.Split(r.ReferencedContainer, ":") @@ -62,6 +69,29 @@ type TestableReference struct { BuildableReference BuildableReference } +func (r TestableReference) isTestable() bool { + return r.Skipped == "NO" && r.BuildableReference.isTestProduct() +} + +// TestPlanReference ... +type TestPlanReference struct { + Reference string `xml:"reference,attr,omitempty"` + Default string `xml:"default,attr,omitempty"` +} + +// IsDefault ... +func (r TestPlanReference) IsDefault() bool { + return r.Default == "YES" +} + +// Name ... +func (r TestPlanReference) Name() string { + // reference = "container:FullTests.xctestplan" + idx := strings.Index(r.Reference, ":") + testPlanFileName := r.Reference[idx+1:] + return strings.TrimSuffix(testPlanFileName, filepath.Ext(testPlanFileName)) +} + // MacroExpansion ... type MacroExpansion struct { BuildableReference BuildableReference @@ -71,6 +101,11 @@ type MacroExpansion struct { type AdditionalOptions struct { } +// TestPlans ... +type TestPlans struct { + TestPlanReferences []TestPlanReference `xml:"TestPlanReference,omitempty"` +} + // TestAction ... type TestAction struct { BuildConfiguration string `xml:"buildConfiguration,attr"` @@ -79,6 +114,7 @@ type TestAction struct { ShouldUseLaunchSchemeArgsEnv string `xml:"shouldUseLaunchSchemeArgsEnv,attr"` Testables []TestableReference `xml:"Testables>TestableReference"` + TestPlans *TestPlans MacroExpansion MacroExpansion AdditionalOptions AdditionalOptions } @@ -146,22 +182,36 @@ type Scheme struct { // Open ... func Open(pth string) (Scheme, error) { - b, err := fileutil.ReadBytesFromFile(pth) + var start = time.Now() + + f, err := os.Open(pth) if err != nil { return Scheme{}, err } + defer func() { + if err := f.Close(); err != nil { + log.Warnf("Failed to close scheme: %s: %s", pth, err) + } + }() - var scheme Scheme - if err := xml.Unmarshal(b, &scheme); err != nil { - return Scheme{}, fmt.Errorf("failed to unmarshal scheme file: %s, error: %s", pth, err) + scheme, err := parse(f) + if err != nil { + return Scheme{}, fmt.Errorf("failed to unmarshal scheme file: %s: %s", pth, err) } scheme.Name = strings.TrimSuffix(filepath.Base(pth), filepath.Ext(pth)) scheme.Path = pth + log.Printf("Read %s scheme in %s.", scheme.Name, time.Since(start).Round(time.Second)) + return scheme, nil } +func parse(reader io.Reader) (scheme Scheme, err error) { + err = xml.NewDecoder(reader).Decode(&scheme) + return +} + // XMLToken ... type XMLToken int @@ -230,3 +280,30 @@ func (s Scheme) AppBuildActionEntry() (BuildActionEntry, bool) { return entry, (entry.BuildableReference.BlueprintIdentifier != "") } + +// IsTestable returns true if Test is a valid action +func (s Scheme) IsTestable() bool { + for _, testEntry := range s.TestAction.Testables { + if testEntry.isTestable() { + return true + } + } + + return false +} + +// DefaultTestPlan ... +func (s Scheme) DefaultTestPlan() *TestPlanReference { + if s.TestAction.TestPlans == nil { + return nil + } + + testPlans := *s.TestAction.TestPlans + + for _, testPlanRef := range testPlans.TestPlanReferences { + if testPlanRef.IsDefault() { + return &testPlanRef + } + } + return nil +} diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcworkspace/xcworkspace.go b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcworkspace/xcworkspace.go index e8d15e0..c2b7e3c 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcworkspace/xcworkspace.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodeproject/xcworkspace/xcworkspace.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/bitrise-io/go-utils/fileutil" + "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" "github.com/bitrise-io/go-xcode/xcodebuild" "github.com/bitrise-io/go-xcode/xcodeproject/serialized" @@ -50,15 +51,24 @@ func (w Workspace) Scheme(name string) (*xcscheme.Scheme, string, error) { // SchemeBuildSettings ... func (w Workspace) SchemeBuildSettings(scheme, configuration string, customOptions ...string) (serialized.Object, error) { + log.TDebugf("Fetching %s scheme build settings", scheme) + commandModel := xcodebuild.NewShowBuildSettingsCommand(w.Path) commandModel.SetScheme(scheme) commandModel.SetConfiguration(configuration) commandModel.SetCustomOptions(customOptions) - return commandModel.RunAndReturnSettings() + + object, err := commandModel.RunAndReturnSettings() + + log.TDebugf("Fetched %s scheme build settings", scheme) + + return object, err } // Schemes ... func (w Workspace) Schemes() (map[string][]xcscheme.Scheme, error) { + log.TDebugf("Looking for schemes in workspace: %s", w.Name) + schemesByContainer := map[string][]xcscheme.Scheme{} workspaceSchemes, err := xcscheme.FindSchemesIn(w.Path) @@ -95,6 +105,8 @@ func (w Workspace) Schemes() (map[string][]xcscheme.Scheme, error) { schemesByContainer[project.Path] = projectSchemes } + log.TDebugf("Found %v workspace schemes", len(schemesByContainer)) + return schemesByContainer, nil } diff --git a/vendor/github.com/golang-jwt/jwt/v4/README.md b/vendor/github.com/golang-jwt/jwt/v4/README.md index 3072d24..01b2164 100644 --- a/vendor/github.com/golang-jwt/jwt/v4/README.md +++ b/vendor/github.com/golang-jwt/jwt/v4/README.md @@ -46,9 +46,16 @@ See [the project documentation](https://pkg.go.dev/github.com/golang-jwt/jwt) fo ## Extensions -This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`. +This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`. -Here's an example of an extension that integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS): https://github.com/someone1/gcp-jwt-go +A common use case would be integrating with different 3rd party signature providers, like key management services from various cloud providers or Hardware Security Modules (HSMs). + +| Extension | Purpose | Repo | +|-----------|----------------------------------------------------------------------------------------------|--------------------------------------------| +| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go | +| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms | + +*Disclaimer*: Unless otherwise specified, these integrations are maintained by third parties and should not be considered as a primary offer by any of the mentioned cloud providers ## Compliance @@ -112,3 +119,5 @@ This library uses descriptive error messages whenever possible. If you are not g Documentation can be found [on pkg.go.dev](https://pkg.go.dev/github.com/golang-jwt/jwt). The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation. + +[golang-jwt](https://github.com/orgs/golang-jwt) incorporates a modified version of the JWT logo, which is distributed under the terms of the [MIT License](https://github.com/jsonwebtoken/jsonwebtoken.github.io/blob/master/LICENSE.txt). diff --git a/vendor/github.com/golang-jwt/jwt/v4/claims.go b/vendor/github.com/golang-jwt/jwt/v4/claims.go index 41cc826..9d95cad 100644 --- a/vendor/github.com/golang-jwt/jwt/v4/claims.go +++ b/vendor/github.com/golang-jwt/jwt/v4/claims.go @@ -56,17 +56,17 @@ func (c RegisteredClaims) Valid() error { // default value in Go, let's not fail the verification for them. if !c.VerifyExpiresAt(now, false) { delta := now.Sub(c.ExpiresAt.Time) - vErr.Inner = fmt.Errorf("token is expired by %v", delta) + vErr.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, delta) vErr.Errors |= ValidationErrorExpired } if !c.VerifyIssuedAt(now, false) { - vErr.Inner = fmt.Errorf("token used before issued") + vErr.Inner = ErrTokenUsedBeforeIssued vErr.Errors |= ValidationErrorIssuedAt } if !c.VerifyNotBefore(now, false) { - vErr.Inner = fmt.Errorf("token is not valid yet") + vErr.Inner = ErrTokenNotValidYet vErr.Errors |= ValidationErrorNotValidYet } @@ -149,17 +149,17 @@ func (c StandardClaims) Valid() error { // default value in Go, let's not fail the verification for them. if !c.VerifyExpiresAt(now, false) { delta := time.Unix(now, 0).Sub(time.Unix(c.ExpiresAt, 0)) - vErr.Inner = fmt.Errorf("token is expired by %v", delta) + vErr.Inner = fmt.Errorf("%s by %s", ErrTokenExpired, delta) vErr.Errors |= ValidationErrorExpired } if !c.VerifyIssuedAt(now, false) { - vErr.Inner = fmt.Errorf("token used before issued") + vErr.Inner = ErrTokenUsedBeforeIssued vErr.Errors |= ValidationErrorIssuedAt } if !c.VerifyNotBefore(now, false) { - vErr.Inner = fmt.Errorf("token is not valid yet") + vErr.Inner = ErrTokenNotValidYet vErr.Errors |= ValidationErrorNotValidYet } diff --git a/vendor/github.com/golang-jwt/jwt/v4/errors.go b/vendor/github.com/golang-jwt/jwt/v4/errors.go index b9d18e4..10ac883 100644 --- a/vendor/github.com/golang-jwt/jwt/v4/errors.go +++ b/vendor/github.com/golang-jwt/jwt/v4/errors.go @@ -9,6 +9,18 @@ var ( ErrInvalidKey = errors.New("key is invalid") ErrInvalidKeyType = errors.New("key is of invalid type") ErrHashUnavailable = errors.New("the requested hash function is unavailable") + + ErrTokenMalformed = errors.New("token is malformed") + ErrTokenUnverifiable = errors.New("token is unverifiable") + ErrTokenSignatureInvalid = errors.New("token signature is invalid") + + ErrTokenInvalidAudience = errors.New("token has invalid audience") + ErrTokenExpired = errors.New("token is expired") + ErrTokenUsedBeforeIssued = errors.New("token used before issued") + ErrTokenInvalidIssuer = errors.New("token has invalid issuer") + ErrTokenNotValidYet = errors.New("token is not valid yet") + ErrTokenInvalidId = errors.New("token has invalid id") + ErrTokenInvalidClaims = errors.New("token has invalid claims") ) // The errors that might occur when parsing and validating a token @@ -62,3 +74,39 @@ func (e *ValidationError) Unwrap() error { func (e *ValidationError) valid() bool { return e.Errors == 0 } + +// Is checks if this ValidationError is of the supplied error. We are first checking for the exact error message +// by comparing the inner error message. If that fails, we compare using the error flags. This way we can use +// custom error messages (mainly for backwards compatability) and still leverage errors.Is using the global error variables. +func (e *ValidationError) Is(err error) bool { + // Check, if our inner error is a direct match + if errors.Is(errors.Unwrap(e), err) { + return true + } + + // Otherwise, we need to match using our error flags + switch err { + case ErrTokenMalformed: + return e.Errors&ValidationErrorMalformed != 0 + case ErrTokenUnverifiable: + return e.Errors&ValidationErrorUnverifiable != 0 + case ErrTokenSignatureInvalid: + return e.Errors&ValidationErrorSignatureInvalid != 0 + case ErrTokenInvalidAudience: + return e.Errors&ValidationErrorAudience != 0 + case ErrTokenExpired: + return e.Errors&ValidationErrorExpired != 0 + case ErrTokenUsedBeforeIssued: + return e.Errors&ValidationErrorIssuedAt != 0 + case ErrTokenInvalidIssuer: + return e.Errors&ValidationErrorIssuer != 0 + case ErrTokenNotValidYet: + return e.Errors&ValidationErrorNotValidYet != 0 + case ErrTokenInvalidId: + return e.Errors&ValidationErrorId != 0 + case ErrTokenInvalidClaims: + return e.Errors&ValidationErrorClaimsInvalid != 0 + } + + return false +} diff --git a/vendor/github.com/golang-jwt/jwt/v4/map_claims.go b/vendor/github.com/golang-jwt/jwt/v4/map_claims.go index e7da633..2700d64 100644 --- a/vendor/github.com/golang-jwt/jwt/v4/map_claims.go +++ b/vendor/github.com/golang-jwt/jwt/v4/map_claims.go @@ -126,16 +126,19 @@ func (m MapClaims) Valid() error { now := TimeFunc().Unix() if !m.VerifyExpiresAt(now, false) { + // TODO(oxisto): this should be replaced with ErrTokenExpired vErr.Inner = errors.New("Token is expired") vErr.Errors |= ValidationErrorExpired } if !m.VerifyIssuedAt(now, false) { + // TODO(oxisto): this should be replaced with ErrTokenUsedBeforeIssued vErr.Inner = errors.New("Token used before issued") vErr.Errors |= ValidationErrorIssuedAt } if !m.VerifyNotBefore(now, false) { + // TODO(oxisto): this should be replaced with ErrTokenNotValidYet vErr.Inner = errors.New("Token is not valid yet") vErr.Errors |= ValidationErrorNotValidYet } diff --git a/vendor/github.com/golang-jwt/jwt/v4/parser_option.go b/vendor/github.com/golang-jwt/jwt/v4/parser_option.go index 0fede4f..6ea6f95 100644 --- a/vendor/github.com/golang-jwt/jwt/v4/parser_option.go +++ b/vendor/github.com/golang-jwt/jwt/v4/parser_option.go @@ -1,6 +1,6 @@ package jwt -// ParserOption is used to implement functional-style options that modify the behaviour of the parser. To add +// ParserOption is used to implement functional-style options that modify the behavior of the parser. To add // new options, just create a function (ideally beginning with With or Without) that returns an anonymous function that // takes a *Parser type as input and manipulates its configuration accordingly. type ParserOption func(*Parser) @@ -13,7 +13,7 @@ func WithValidMethods(methods []string) ParserOption { } } -// WithJSONNumber is an option to configure the underyling JSON parser with UseNumber +// WithJSONNumber is an option to configure the underlying JSON parser with UseNumber func WithJSONNumber() ParserOption { return func(p *Parser) { p.UseJSONNumber = true diff --git a/vendor/github.com/golang-jwt/jwt/v4/token.go b/vendor/github.com/golang-jwt/jwt/v4/token.go index 1234413..09b4cde 100644 --- a/vendor/github.com/golang-jwt/jwt/v4/token.go +++ b/vendor/github.com/golang-jwt/jwt/v4/token.go @@ -74,22 +74,19 @@ func (t *Token) SignedString(key interface{}) (string, error) { // the SignedString. func (t *Token) SigningString() (string, error) { var err error - parts := make([]string, 2) - for i := range parts { - var jsonValue []byte - if i == 0 { - if jsonValue, err = json.Marshal(t.Header); err != nil { - return "", err - } - } else { - if jsonValue, err = json.Marshal(t.Claims); err != nil { - return "", err - } - } + var jsonValue []byte + + if jsonValue, err = json.Marshal(t.Header); err != nil { + return "", err + } + header := EncodeSegment(jsonValue) - parts[i] = EncodeSegment(jsonValue) + if jsonValue, err = json.Marshal(t.Claims); err != nil { + return "", err } - return strings.Join(parts, "."), nil + claim := EncodeSegment(jsonValue) + + return strings.Join([]string{header, claim}, "."), nil } // Parse parses, validates, verifies the signature and returns the parsed token. diff --git a/vendor/github.com/golang-jwt/jwt/v4/types.go b/vendor/github.com/golang-jwt/jwt/v4/types.go index 80b1b96..2c647fd 100644 --- a/vendor/github.com/golang-jwt/jwt/v4/types.go +++ b/vendor/github.com/golang-jwt/jwt/v4/types.go @@ -49,9 +49,13 @@ func newNumericDateFromSeconds(f float64) *NumericDate { // MarshalJSON is an implementation of the json.RawMessage interface and serializes the UNIX epoch // represented in NumericDate to a byte array, using the precision specified in TimePrecision. func (date NumericDate) MarshalJSON() (b []byte, err error) { + var prec int + if TimePrecision < time.Second { + prec = int(math.Log10(float64(time.Second) / float64(TimePrecision))) + } f := float64(date.Truncate(TimePrecision).UnixNano()) / float64(time.Second) - return []byte(strconv.FormatFloat(f, 'f', -1, 64)), nil + return []byte(strconv.FormatFloat(f, 'f', prec, 64)), nil } // UnmarshalJSON is an implementation of the json.RawMessage interface and deserializses a diff --git a/vendor/github.com/hashicorp/go-retryablehttp/README.md b/vendor/github.com/hashicorp/go-retryablehttp/README.md index 8943bec..09f5eaf 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/README.md +++ b/vendor/github.com/hashicorp/go-retryablehttp/README.md @@ -45,6 +45,25 @@ The returned response object is an `*http.Response`, the same thing you would usually get from `net/http`. Had the request failed one or more times, the above call would block and retry with exponential backoff. +## Retrying cases that fail after a seeming success + +It's possible for a request to succeed in the sense that the expected response headers are received, but then to encounter network-level errors while reading the response body. In go-retryablehttp's most basic usage, this error would not be retryable, due to the out-of-band handling of the response body. In some cases it may be desirable to handle the response body as part of the retryable operation. + +A toy example (which will retry the full request and succeed on the second attempt) is shown below: + +```go +c := retryablehttp.NewClient() +r := retryablehttp.NewRequest("GET", "://foo", nil) +handlerShouldRetry := true +r.SetResponseHandler(func(*http.Response) error { + if !handlerShouldRetry { + return nil + } + handlerShouldRetry = false + return errors.New("retryable error") +}) +``` + ## Getting a stdlib `*http.Client` with retries It's possible to convert a `*retryablehttp.Client` directly to a `*http.Client`. diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go index adbdd92..57116e9 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/client.go +++ b/vendor/github.com/hashicorp/go-retryablehttp/client.go @@ -69,11 +69,21 @@ var ( // scheme specified in the URL is invalid. This error isn't typed // specifically so we resort to matching on the error string. schemeErrorRe = regexp.MustCompile(`unsupported protocol scheme`) + + // A regular expression to match the error returned by net/http when the + // TLS certificate is not trusted. This error isn't typed + // specifically so we resort to matching on the error string. + notTrustedErrorRe = regexp.MustCompile(`certificate is not trusted`) ) // ReaderFunc is the type of function that can be given natively to NewRequest type ReaderFunc func() (io.Reader, error) +// ResponseHandlerFunc is a type of function that takes in a Response, and does something with it. +// It only runs if the initial part of the request was successful. +// If an error is returned, the client's retry policy will be used to determine whether to retry the whole request. +type ResponseHandlerFunc func(*http.Response) error + // LenReader is an interface implemented by many in-memory io.Reader's. Used // for automatically sending the right Content-Length header when possible. type LenReader interface { @@ -86,6 +96,8 @@ type Request struct { // used to rewind the request data in between retries. body ReaderFunc + responseHandler ResponseHandlerFunc + // Embed an HTTP request directly. This makes a *Request act exactly // like an *http.Request so that all meta methods are supported. *http.Request @@ -94,8 +106,16 @@ type Request struct { // WithContext returns wrapped Request with a shallow copy of underlying *http.Request // with its context changed to ctx. The provided ctx must be non-nil. func (r *Request) WithContext(ctx context.Context) *Request { - r.Request = r.Request.WithContext(ctx) - return r + return &Request{ + body: r.body, + responseHandler: r.responseHandler, + Request: r.Request.WithContext(ctx), + } +} + +// SetResponseHandler allows setting the response handler. +func (r *Request) SetResponseHandler(fn ResponseHandlerFunc) { + r.responseHandler = fn } // BodyBytes allows accessing the request body. It is an analogue to @@ -252,23 +272,31 @@ func FromRequest(r *http.Request) (*Request, error) { return nil, err } // Could assert contentLength == r.ContentLength - return &Request{bodyReader, r}, nil + return &Request{body: bodyReader, Request: r}, nil } // NewRequest creates a new wrapped request. func NewRequest(method, url string, rawBody interface{}) (*Request, error) { + return NewRequestWithContext(context.Background(), method, url, rawBody) +} + +// NewRequestWithContext creates a new wrapped request with the provided context. +// +// The context controls the entire lifetime of a request and its response: +// obtaining a connection, sending the request, and reading the response headers and body. +func NewRequestWithContext(ctx context.Context, method, url string, rawBody interface{}) (*Request, error) { bodyReader, contentLength, err := getBodyReaderAndContentLength(rawBody) if err != nil { return nil, err } - httpReq, err := http.NewRequest(method, url, nil) + httpReq, err := http.NewRequestWithContext(ctx, method, url, nil) if err != nil { return nil, err } httpReq.ContentLength = contentLength - return &Request{bodyReader, httpReq}, nil + return &Request{body: bodyReader, Request: httpReq}, nil } // Logger interface allows to use other loggers than @@ -435,6 +463,9 @@ func baseRetryPolicy(resp *http.Response, err error) (bool, error) { } // Don't retry if the error was due to TLS cert verification failure. + if notTrustedErrorRe.MatchString(v.Error()) { + return false, v + } if _, ok := v.Err.(x509.UnknownAuthorityError); ok { return false, v } @@ -455,7 +486,7 @@ func baseRetryPolicy(resp *http.Response, err error) (bool, error) { // the server time to recover, as 500's are typically not permanent // errors and may relate to outages on the server side. This will catch // invalid response codes as well, like 0 and 999. - if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) { + if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != http.StatusNotImplemented) { return true, fmt.Errorf("unexpected HTTP status %s", resp.Status) } @@ -555,13 +586,12 @@ func (c *Client) Do(req *Request) (*http.Response, error) { var resp *http.Response var attempt int var shouldRetry bool - var doErr, checkErr error + var doErr, respErr, checkErr error for i := 0; ; i++ { + doErr, respErr = nil, nil attempt++ - var code int // HTTP response code - // Always rewind the request body when non-nil. if req.body != nil { body, err := req.body() @@ -589,19 +619,24 @@ func (c *Client) Do(req *Request) (*http.Response, error) { // Attempt the request resp, doErr = c.HTTPClient.Do(req.Request) - if resp != nil { - code = resp.StatusCode - } // Check if we should continue with retries. shouldRetry, checkErr = c.CheckRetry(req.Context(), resp, doErr) + if !shouldRetry && doErr == nil && req.responseHandler != nil { + respErr = req.responseHandler(resp) + shouldRetry, checkErr = c.CheckRetry(req.Context(), resp, respErr) + } - if doErr != nil { + err := doErr + if respErr != nil { + err = respErr + } + if err != nil { switch v := logger.(type) { case LeveledLogger: - v.Error("request failed", "error", doErr, "method", req.Method, "url", req.URL) + v.Error("request failed", "error", err, "method", req.Method, "url", req.URL) case Logger: - v.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, doErr) + v.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err) } } else { // Call this here to maintain the behavior of logging all requests, @@ -636,11 +671,11 @@ func (c *Client) Do(req *Request) (*http.Response, error) { } wait := c.Backoff(c.RetryWaitMin, c.RetryWaitMax, i, resp) - desc := fmt.Sprintf("%s %s", req.Method, req.URL) - if code > 0 { - desc = fmt.Sprintf("%s (status: %d)", desc, code) - } if logger != nil { + desc := fmt.Sprintf("%s %s", req.Method, req.URL) + if resp != nil { + desc = fmt.Sprintf("%s (status: %d)", desc, resp.StatusCode) + } switch v := logger.(type) { case LeveledLogger: v.Debug("retrying request", "request", desc, "timeout", wait, "remaining", remain) @@ -648,11 +683,13 @@ func (c *Client) Do(req *Request) (*http.Response, error) { v.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) } } + timer := time.NewTimer(wait) select { case <-req.Context().Done(): + timer.Stop() c.HTTPClient.CloseIdleConnections() return nil, req.Context().Err() - case <-time.After(wait): + case <-timer.C: } // Make shallow copy of http Request so that we can modify its body @@ -662,15 +699,19 @@ func (c *Client) Do(req *Request) (*http.Response, error) { } // this is the closest we have to success criteria - if doErr == nil && checkErr == nil && !shouldRetry { + if doErr == nil && respErr == nil && checkErr == nil && !shouldRetry { return resp, nil } defer c.HTTPClient.CloseIdleConnections() - err := doErr + var err error if checkErr != nil { err = checkErr + } else if respErr != nil { + err = respErr + } else { + err = doErr } if c.ErrorHandler != nil { diff --git a/vendor/github.com/hashicorp/go-version/CHANGELOG.md b/vendor/github.com/hashicorp/go-version/CHANGELOG.md index dbae7f7..0945500 100644 --- a/vendor/github.com/hashicorp/go-version/CHANGELOG.md +++ b/vendor/github.com/hashicorp/go-version/CHANGELOG.md @@ -1,3 +1,10 @@ +# 1.4.0 (January 5, 2022) + +FEATURES: + + - Introduce `MustConstraints()` ([#87](https://github.com/hashicorp/go-version/pull/87)) + - `Constraints`: Introduce `Equals()` and `sort.Interface` methods ([#88](https://github.com/hashicorp/go-version/pull/88)) + # 1.3.0 (March 31, 2021) Please note that CHANGELOG.md does not exist in the source code prior to this release. diff --git a/vendor/github.com/hashicorp/go-version/README.md b/vendor/github.com/hashicorp/go-version/README.md index 851a337..4d25050 100644 --- a/vendor/github.com/hashicorp/go-version/README.md +++ b/vendor/github.com/hashicorp/go-version/README.md @@ -1,5 +1,5 @@ # Versioning Library for Go -[![Build Status](https://circleci.com/gh/hashicorp/go-version/tree/master.svg?style=svg)](https://circleci.com/gh/hashicorp/go-version/tree/master) +[![Build Status](https://circleci.com/gh/hashicorp/go-version/tree/main.svg?style=svg)](https://circleci.com/gh/hashicorp/go-version/tree/main) [![GoDoc](https://godoc.org/github.com/hashicorp/go-version?status.svg)](https://godoc.org/github.com/hashicorp/go-version) go-version is a library for parsing versions and version constraints, diff --git a/vendor/github.com/hashicorp/go-version/constraint.go b/vendor/github.com/hashicorp/go-version/constraint.go index d055759..1d88090 100644 --- a/vendor/github.com/hashicorp/go-version/constraint.go +++ b/vendor/github.com/hashicorp/go-version/constraint.go @@ -4,6 +4,7 @@ import ( "fmt" "reflect" "regexp" + "sort" "strings" ) @@ -11,30 +12,40 @@ import ( // ">= 1.0". type Constraint struct { f constraintFunc + op operator check *Version original string } +func (c *Constraint) Equals(con *Constraint) bool { + return c.op == con.op && c.check.Equal(con.check) +} + // Constraints is a slice of constraints. We make a custom type so that // we can add methods to it. type Constraints []*Constraint type constraintFunc func(v, c *Version) bool -var constraintOperators map[string]constraintFunc +var constraintOperators map[string]constraintOperation + +type constraintOperation struct { + op operator + f constraintFunc +} var constraintRegexp *regexp.Regexp func init() { - constraintOperators = map[string]constraintFunc{ - "": constraintEqual, - "=": constraintEqual, - "!=": constraintNotEqual, - ">": constraintGreaterThan, - "<": constraintLessThan, - ">=": constraintGreaterThanEqual, - "<=": constraintLessThanEqual, - "~>": constraintPessimistic, + constraintOperators = map[string]constraintOperation{ + "": {op: equal, f: constraintEqual}, + "=": {op: equal, f: constraintEqual}, + "!=": {op: notEqual, f: constraintNotEqual}, + ">": {op: greaterThan, f: constraintGreaterThan}, + "<": {op: lessThan, f: constraintLessThan}, + ">=": {op: greaterThanEqual, f: constraintGreaterThanEqual}, + "<=": {op: lessThanEqual, f: constraintLessThanEqual}, + "~>": {op: pessimistic, f: constraintPessimistic}, } ops := make([]string, 0, len(constraintOperators)) @@ -66,6 +77,16 @@ func NewConstraint(v string) (Constraints, error) { return Constraints(result), nil } +// MustConstraints is a helper that wraps a call to a function +// returning (Constraints, error) and panics if error is non-nil. +func MustConstraints(c Constraints, err error) Constraints { + if err != nil { + panic(err) + } + + return c +} + // Check tests if a version satisfies all the constraints. func (cs Constraints) Check(v *Version) bool { for _, c := range cs { @@ -77,6 +98,56 @@ func (cs Constraints) Check(v *Version) bool { return true } +// Equals compares Constraints with other Constraints +// for equality. This may not represent logical equivalence +// of compared constraints. +// e.g. even though '>0.1,>0.2' is logically equivalent +// to '>0.2' it is *NOT* treated as equal. +// +// Missing operator is treated as equal to '=', whitespaces +// are ignored and constraints are sorted before comaparison. +func (cs Constraints) Equals(c Constraints) bool { + if len(cs) != len(c) { + return false + } + + // make copies to retain order of the original slices + left := make(Constraints, len(cs)) + copy(left, cs) + sort.Stable(left) + right := make(Constraints, len(c)) + copy(right, c) + sort.Stable(right) + + // compare sorted slices + for i, con := range left { + if !con.Equals(right[i]) { + return false + } + } + + return true +} + +func (cs Constraints) Len() int { + return len(cs) +} + +func (cs Constraints) Less(i, j int) bool { + if cs[i].op < cs[j].op { + return true + } + if cs[i].op > cs[j].op { + return false + } + + return cs[i].check.LessThan(cs[j].check) +} + +func (cs Constraints) Swap(i, j int) { + cs[i], cs[j] = cs[j], cs[i] +} + // Returns the string format of the constraints func (cs Constraints) String() string { csStr := make([]string, len(cs)) @@ -107,8 +178,11 @@ func parseSingle(v string) (*Constraint, error) { return nil, err } + cop := constraintOperators[matches[1]] + return &Constraint{ - f: constraintOperators[matches[1]], + f: cop.f, + op: cop.op, check: check, original: v, }, nil @@ -138,6 +212,18 @@ func prereleaseCheck(v, c *Version) bool { // Constraint functions //------------------------------------------------------------------- +type operator rune + +const ( + equal operator = '=' + notEqual operator = '≠' + greaterThan operator = '>' + lessThan operator = '<' + greaterThanEqual operator = '≥' + lessThanEqual operator = '≤' + pessimistic operator = '~' +) + func constraintEqual(v, c *Version) bool { return v.Equal(c) } diff --git a/vendor/github.com/hashicorp/go-version/version.go b/vendor/github.com/hashicorp/go-version/version.go index 8068834..e87df69 100644 --- a/vendor/github.com/hashicorp/go-version/version.go +++ b/vendor/github.com/hashicorp/go-version/version.go @@ -64,7 +64,6 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) { } segmentsStr := strings.Split(matches[1], ".") segments := make([]int64, len(segmentsStr)) - si := 0 for i, str := range segmentsStr { val, err := strconv.ParseInt(str, 10, 64) if err != nil { @@ -72,8 +71,7 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) { "Error parsing version: %s", err) } - segments[i] = int64(val) - si++ + segments[i] = val } // Even though we could support more than three segments, if we @@ -92,7 +90,7 @@ func newVersion(v string, pattern *regexp.Regexp) (*Version, error) { metadata: matches[10], pre: pre, segments: segments, - si: si, + si: len(segmentsStr), original: v, }, nil } @@ -390,3 +388,20 @@ func (v *Version) String() string { func (v *Version) Original() string { return v.original } + +// UnmarshalText implements encoding.TextUnmarshaler interface. +func (v *Version) UnmarshalText(b []byte) error { + temp, err := NewVersion(string(b)) + if err != nil { + return err + } + + *v = *temp + + return nil +} + +// MarshalText implements encoding.TextMarshaler interface. +func (v *Version) MarshalText() ([]byte, error) { + return []byte(v.String()), nil +} diff --git a/vendor/github.com/stretchr/objx/.travis.yml b/vendor/github.com/stretchr/objx/.travis.yml deleted file mode 100644 index cde6eb2..0000000 --- a/vendor/github.com/stretchr/objx/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: go -go: - - "1.10.x" - - "1.11.x" - - "1.12.x" - - master - -matrix: - allow_failures: - - go: master -fast_finish: true - -env: - global: - - CC_TEST_REPORTER_ID=68feaa3410049ce73e145287acbcdacc525087a30627f96f04e579e75bd71c00 - -before_script: - - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - - chmod +x ./cc-test-reporter - - ./cc-test-reporter before-build - -install: - - curl -sL https://taskfile.dev/install.sh | sh - -script: - - diff -u <(echo -n) <(./bin/task lint) - - ./bin/task test-coverage - -after_script: - - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT diff --git a/vendor/github.com/stretchr/objx/accessors.go b/vendor/github.com/stretchr/objx/accessors.go index 80ad167..4c60455 100644 --- a/vendor/github.com/stretchr/objx/accessors.go +++ b/vendor/github.com/stretchr/objx/accessors.go @@ -116,9 +116,15 @@ func getKey(s string) (string, string) { func access(current interface{}, selector string, value interface{}, isSet bool) interface{} { thisSel, nextSel := getKey(selector) - index := -1 - if strings.Contains(thisSel, "[") { + indexes := []int{} + for strings.Contains(thisSel, "[") { + prevSel := thisSel + index := -1 index, thisSel = getIndex(thisSel) + indexes = append(indexes, index) + if prevSel == thisSel { + break + } } if curMap, ok := current.(Map); ok { @@ -134,7 +140,11 @@ func access(current interface{}, selector string, value interface{}, isSet bool) } _, ok := curMSI[thisSel].(map[string]interface{}) - if (curMSI[thisSel] == nil || !ok) && index == -1 && isSet { + if !ok { + _, ok = curMSI[thisSel].(Map) + } + + if (curMSI[thisSel] == nil || !ok) && len(indexes) == 0 && isSet { curMSI[thisSel] = map[string]interface{}{} } @@ -144,15 +154,23 @@ func access(current interface{}, selector string, value interface{}, isSet bool) } // do we need to access the item of an array? - if index > -1 { - if array, ok := interSlice(current); ok { - if index < len(array) { - current = array[index] - } else { - current = nil + if len(indexes) > 0 { + num := len(indexes) + for num > 0 { + num-- + index := indexes[num] + indexes = indexes[:num] + if array, ok := interSlice(current); ok { + if index < len(array) { + current = array[index] + } else { + current = nil + break + } } } } + if nextSel != "" { current = access(current, nextSel, value, isSet) } diff --git a/vendor/github.com/stretchr/objx/map.go b/vendor/github.com/stretchr/objx/map.go index 95149c0..a64712a 100644 --- a/vendor/github.com/stretchr/objx/map.go +++ b/vendor/github.com/stretchr/objx/map.go @@ -92,6 +92,18 @@ func MustFromJSON(jsonString string) Map { return o } +// MustFromJSONSlice creates a new slice of Map containing the data specified in the +// jsonString. Works with jsons with a top level array +// +// Panics if the JSON is invalid. +func MustFromJSONSlice(jsonString string) []Map { + slice, err := FromJSONSlice(jsonString) + if err != nil { + panic("objx: MustFromJSONSlice failed with error: " + err.Error()) + } + return slice +} + // FromJSON creates a new Map containing the data specified in the // jsonString. // @@ -102,45 +114,20 @@ func FromJSON(jsonString string) (Map, error) { if err != nil { return Nil, err } - m.tryConvertFloat64() return m, nil } -func (m Map) tryConvertFloat64() { - for k, v := range m { - switch v.(type) { - case float64: - f := v.(float64) - if float64(int(f)) == f { - m[k] = int(f) - } - case map[string]interface{}: - t := New(v) - t.tryConvertFloat64() - m[k] = t - case []interface{}: - m[k] = tryConvertFloat64InSlice(v.([]interface{})) - } - } -} - -func tryConvertFloat64InSlice(s []interface{}) []interface{} { - for k, v := range s { - switch v.(type) { - case float64: - f := v.(float64) - if float64(int(f)) == f { - s[k] = int(f) - } - case map[string]interface{}: - t := New(v) - t.tryConvertFloat64() - s[k] = t - case []interface{}: - s[k] = tryConvertFloat64InSlice(v.([]interface{})) - } +// FromJSONSlice creates a new slice of Map containing the data specified in the +// jsonString. Works with jsons with a top level array +// +// Returns an error if the JSON is invalid. +func FromJSONSlice(jsonString string) ([]Map, error) { + var slice []Map + err := json.Unmarshal([]byte(jsonString), &slice) + if err != nil { + return nil, err } - return s + return slice, nil } // FromBase64 creates a new Obj containing the data specified diff --git a/vendor/github.com/stretchr/objx/type_specific_codegen.go b/vendor/github.com/stretchr/objx/type_specific_codegen.go index 9859b40..4585045 100644 --- a/vendor/github.com/stretchr/objx/type_specific_codegen.go +++ b/vendor/github.com/stretchr/objx/type_specific_codegen.go @@ -385,6 +385,11 @@ func (v *Value) Int(optionalDefault ...int) int { if s, ok := v.data.(int); ok { return s } + if s, ok := v.data.(float64); ok { + if float64(int(s)) == s { + return int(s) + } + } if len(optionalDefault) == 1 { return optionalDefault[0] } @@ -395,6 +400,11 @@ func (v *Value) Int(optionalDefault ...int) int { // // Panics if the object is not a int. func (v *Value) MustInt() int { + if s, ok := v.data.(float64); ok { + if float64(int(s)) == s { + return int(s) + } + } return v.data.(int) } diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go index 41649d2..3bb22a9 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_compare.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -3,6 +3,7 @@ package assert import ( "fmt" "reflect" + "time" ) type CompareType int @@ -30,6 +31,8 @@ var ( float64Type = reflect.TypeOf(float64(1)) stringType = reflect.TypeOf("") + + timeType = reflect.TypeOf(time.Time{}) ) func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { @@ -299,6 +302,27 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { return compareLess, true } } + // Check for known struct types we can check for compare results. + case reflect.Struct: + { + // All structs enter here. We're not interested in most types. + if !canConvert(obj1Value, timeType) { + break + } + + // time.Time can compared! + timeObj1, ok := obj1.(time.Time) + if !ok { + timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) + } + + timeObj2, ok := obj2.(time.Time) + if !ok { + timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time) + } + + return compare(timeObj1.UnixNano(), timeObj2.UnixNano(), reflect.Int64) + } } return compareEqual, false @@ -310,7 +334,10 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { // assert.Greater(t, float64(2), float64(1)) // assert.Greater(t, "b", "a") func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } // GreaterOrEqual asserts that the first element is greater than or equal to the second @@ -320,7 +347,10 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface // assert.GreaterOrEqual(t, "b", "a") // assert.GreaterOrEqual(t, "b", "b") func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } // Less asserts that the first element is less than the second @@ -329,7 +359,10 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in // assert.Less(t, float64(1), float64(2)) // assert.Less(t, "a", "b") func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } // LessOrEqual asserts that the first element is less than or equal to the second @@ -339,7 +372,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) // assert.LessOrEqual(t, "a", "b") // assert.LessOrEqual(t, "b", "b") func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } // Positive asserts that the specified element is positive @@ -347,8 +383,11 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter // assert.Positive(t, 1) // assert.Positive(t, 1.23) func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } zero := reflect.Zero(reflect.TypeOf(e)) - return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs...) } // Negative asserts that the specified element is negative @@ -356,8 +395,11 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { // assert.Negative(t, -1) // assert.Negative(t, -1.23) func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } zero := reflect.Zero(reflect.TypeOf(e)) - return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs...) } func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go new file mode 100644 index 0000000..df22c47 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go @@ -0,0 +1,16 @@ +//go:build go1.17 +// +build go1.17 + +// TODO: once support for Go 1.16 is dropped, this file can be +// merged/removed with assertion_compare_go1.17_test.go and +// assertion_compare_legacy.go + +package assert + +import "reflect" + +// Wrapper around reflect.Value.CanConvert, for compatability +// reasons. +func canConvert(value reflect.Value, to reflect.Type) bool { + return value.CanConvert(to) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go new file mode 100644 index 0000000..1701af2 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go @@ -0,0 +1,16 @@ +//go:build !go1.17 +// +build !go1.17 + +// TODO: once support for Go 1.16 is dropped, this file can be +// merged/removed with assertion_compare_go1.17_test.go and +// assertion_compare_can_convert.go + +package assert + +import "reflect" + +// Older versions of Go does not have the reflect.Value.CanConvert +// method. +func canConvert(value reflect.Value, to reflect.Type) bool { + return false +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index 4dfd122..27e2420 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -123,6 +123,18 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) } +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorContains(t, theError, contains, append([]interface{}{msg}, args...)...) +} + // ErrorIsf asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index 25337a6..d9ea368 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -222,6 +222,30 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. return ErrorAsf(a.t, err, target, msg, args...) } +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) +func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorContains(a.t, theError, contains, msgAndArgs...) +} + +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorContainsf(a.t, theError, contains, msg, args...) +} + // ErrorIs asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool { diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go index 1c3b471..7594487 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_order.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -50,7 +50,7 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT // assert.IsIncreasing(t, []float{1, 2}) // assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) + return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } // IsNonIncreasing asserts that the collection is not increasing @@ -59,7 +59,7 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo // assert.IsNonIncreasing(t, []float{2, 1}) // assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) + return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } // IsDecreasing asserts that the collection is decreasing @@ -68,7 +68,7 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) // assert.IsDecreasing(t, []float{2, 1}) // assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) + return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } // IsNonDecreasing asserts that the collection is not decreasing @@ -77,5 +77,5 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo // assert.IsNonDecreasing(t, []float{1, 2}) // assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) + return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index bcac440..0357b22 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -718,10 +718,14 @@ func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...inte // return (false, false) if impossible. // return (true, false) if element was not found. // return (true, true) if element was found. -func includeElement(list interface{}, element interface{}) (ok, found bool) { +func containsElement(list interface{}, element interface{}) (ok, found bool) { listValue := reflect.ValueOf(list) - listKind := reflect.TypeOf(list).Kind() + listType := reflect.TypeOf(list) + if listType == nil { + return false, false + } + listKind := listType.Kind() defer func() { if e := recover(); e != nil { ok = false @@ -764,7 +768,7 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo h.Helper() } - ok, found := includeElement(s, contains) + ok, found := containsElement(s, contains) if !ok { return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) } @@ -787,7 +791,7 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) h.Helper() } - ok, found := includeElement(s, contains) + ok, found := containsElement(s, contains) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) } @@ -831,7 +835,7 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok for i := 0; i < subsetValue.Len(); i++ { element := subsetValue.Index(i).Interface() - ok, found := includeElement(list, element) + ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) } @@ -852,7 +856,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) h.Helper() } if subset == nil { - return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...) + return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...) } subsetValue := reflect.ValueOf(subset) @@ -875,7 +879,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) for i := 0; i < subsetValue.Len(); i++ { element := subsetValue.Index(i).Interface() - ok, found := includeElement(list, element) + ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) } @@ -1000,27 +1004,21 @@ func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { type PanicTestFunc func() // didPanic returns true if the function passed to it panics. Otherwise, it returns false. -func didPanic(f PanicTestFunc) (bool, interface{}, string) { - - didPanic := false - var message interface{} - var stack string - func() { - - defer func() { - if message = recover(); message != nil { - didPanic = true - stack = string(debug.Stack()) - } - }() - - // call the target function - f() +func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) { + didPanic = true + defer func() { + message = recover() + if didPanic { + stack = string(debug.Stack()) + } }() - return didPanic, message, stack + // call the target function + f() + didPanic = false + return } // Panics asserts that the code inside the specified PanicTestFunc panics. @@ -1161,11 +1159,15 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs bf, bok := toFloat(actual) if !aok || !bok { - return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...) + return Fail(t, "Parameters must be numerical", msgAndArgs...) + } + + if math.IsNaN(af) && math.IsNaN(bf) { + return true } if math.IsNaN(af) { - return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...) + return Fail(t, "Expected must not be NaN", msgAndArgs...) } if math.IsNaN(bf) { @@ -1188,7 +1190,7 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(expected).Kind() != reflect.Slice { - return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + return Fail(t, "Parameters must be slice", msgAndArgs...) } actualSlice := reflect.ValueOf(actual) @@ -1250,8 +1252,12 @@ func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, m func calcRelativeError(expected, actual interface{}) (float64, error) { af, aok := toFloat(expected) - if !aok { - return 0, fmt.Errorf("expected value %q cannot be converted to float", expected) + bf, bok := toFloat(actual) + if !aok || !bok { + return 0, fmt.Errorf("Parameters must be numerical") + } + if math.IsNaN(af) && math.IsNaN(bf) { + return 0, nil } if math.IsNaN(af) { return 0, errors.New("expected value must not be NaN") @@ -1259,10 +1265,6 @@ func calcRelativeError(expected, actual interface{}) (float64, error) { if af == 0 { return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") } - bf, bok := toFloat(actual) - if !bok { - return 0, fmt.Errorf("actual value %q cannot be converted to float", actual) - } if math.IsNaN(bf) { return 0, errors.New("actual value must not be NaN") } @@ -1298,7 +1300,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(expected).Kind() != reflect.Slice { - return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + return Fail(t, "Parameters must be slice", msgAndArgs...) } actualSlice := reflect.ValueOf(actual) @@ -1375,6 +1377,27 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte return true } +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) +func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !Error(t, theError, msgAndArgs...) { + return false + } + + actual := theError.Error() + if !strings.Contains(actual, contains) { + return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...) + } + + return true +} + // matchRegexp return true if a specified regexp matches a string. func matchRegexp(rx interface{}, str interface{}) bool { @@ -1588,12 +1611,17 @@ func diff(expected interface{}, actual interface{}) string { } var e, a string - if et != reflect.TypeOf("") { - e = spewConfig.Sdump(expected) - a = spewConfig.Sdump(actual) - } else { + + switch et { + case reflect.TypeOf(""): e = reflect.ValueOf(expected).String() a = reflect.ValueOf(actual).String() + case reflect.TypeOf(time.Time{}): + e = spewConfigStringerEnabled.Sdump(expected) + a = spewConfigStringerEnabled.Sdump(actual) + default: + e = spewConfig.Sdump(expected) + a = spewConfig.Sdump(actual) } diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ @@ -1625,6 +1653,14 @@ var spewConfig = spew.ConfigState{ MaxDepth: 10, } +var spewConfigStringerEnabled = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, + MaxDepth: 10, +} + type tHelper interface { Helper() } diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go index e2e6a2d..853da6c 100644 --- a/vendor/github.com/stretchr/testify/mock/mock.go +++ b/vendor/github.com/stretchr/testify/mock/mock.go @@ -221,6 +221,14 @@ type Mock struct { mutex sync.Mutex } +// String provides a %v format string for Mock. +// Note: this is used implicitly by Arguments.Diff if a Mock is passed. +// It exists because go's default %v formatting traverses the struct +// without acquiring the mutex, which is detected by go test -race. +func (m *Mock) String() string { + return fmt.Sprintf("%[1]T<%[1]p>", m) +} + // TestData holds any data that might be useful for testing. Testify ignores // this data completely allowing you to do whatever you like with it. func (m *Mock) TestData() objx.Map { @@ -720,7 +728,7 @@ func (f argumentMatcher) Matches(argument interface{}) bool { } func (f argumentMatcher) String() string { - return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).Name()) + return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).String()) } // MatchedBy can be used to match a mock call based on only certain properties diff --git a/vendor/gopkg.in/yaml.v3/decode.go b/vendor/gopkg.in/yaml.v3/decode.go index df36e3a..0173b69 100644 --- a/vendor/gopkg.in/yaml.v3/decode.go +++ b/vendor/gopkg.in/yaml.v3/decode.go @@ -100,7 +100,10 @@ func (p *parser) peek() yaml_event_type_t { if p.event.typ != yaml_NO_EVENT { return p.event.typ } - if !yaml_parser_parse(&p.parser, &p.event) { + // It's curious choice from the underlying API to generally return a + // positive result on success, but on this case return true in an error + // scenario. This was the source of bugs in the past (issue #666). + if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR { p.fail() } return p.event.typ @@ -320,6 +323,8 @@ type decoder struct { decodeCount int aliasCount int aliasDepth int + + mergedFields map[interface{}]bool } var ( @@ -808,6 +813,11 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { } } + mergedFields := d.mergedFields + d.mergedFields = nil + + var mergeNode *Node + mapIsNew := false if out.IsNil() { out.Set(reflect.MakeMap(outt)) @@ -815,11 +825,18 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { } for i := 0; i < l; i += 2 { if isMerge(n.Content[i]) { - d.merge(n.Content[i+1], out) + mergeNode = n.Content[i+1] continue } k := reflect.New(kt).Elem() if d.unmarshal(n.Content[i], k) { + if mergedFields != nil { + ki := k.Interface() + if mergedFields[ki] { + continue + } + mergedFields[ki] = true + } kkind := k.Kind() if kkind == reflect.Interface { kkind = k.Elem().Kind() @@ -833,6 +850,12 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { } } } + + d.mergedFields = mergedFields + if mergeNode != nil { + d.merge(n, mergeNode, out) + } + d.stringMapType = stringMapType d.generalMapType = generalMapType return true @@ -844,7 +867,8 @@ func isStringMap(n *Node) bool { } l := len(n.Content) for i := 0; i < l; i += 2 { - if n.Content[i].ShortTag() != strTag { + shortTag := n.Content[i].ShortTag() + if shortTag != strTag && shortTag != mergeTag { return false } } @@ -861,7 +885,6 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { var elemType reflect.Type if sinfo.InlineMap != -1 { inlineMap = out.Field(sinfo.InlineMap) - inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) elemType = inlineMap.Type().Elem() } @@ -870,6 +893,9 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { d.prepare(n, field) } + mergedFields := d.mergedFields + d.mergedFields = nil + var mergeNode *Node var doneFields []bool if d.uniqueKeys { doneFields = make([]bool, len(sinfo.FieldsList)) @@ -879,13 +905,20 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { for i := 0; i < l; i += 2 { ni := n.Content[i] if isMerge(ni) { - d.merge(n.Content[i+1], out) + mergeNode = n.Content[i+1] continue } if !d.unmarshal(ni, name) { continue } - if info, ok := sinfo.FieldsMap[name.String()]; ok { + sname := name.String() + if mergedFields != nil { + if mergedFields[sname] { + continue + } + mergedFields[sname] = true + } + if info, ok := sinfo.FieldsMap[sname]; ok { if d.uniqueKeys { if doneFields[info.Id] { d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type())) @@ -911,6 +944,11 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type())) } } + + d.mergedFields = mergedFields + if mergeNode != nil { + d.merge(n, mergeNode, out) + } return true } @@ -918,19 +956,29 @@ func failWantMap() { failf("map merge requires map or sequence of maps as the value") } -func (d *decoder) merge(n *Node, out reflect.Value) { - switch n.Kind { +func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) { + mergedFields := d.mergedFields + if mergedFields == nil { + d.mergedFields = make(map[interface{}]bool) + for i := 0; i < len(parent.Content); i += 2 { + k := reflect.New(ifaceType).Elem() + if d.unmarshal(parent.Content[i], k) { + d.mergedFields[k.Interface()] = true + } + } + } + + switch merge.Kind { case MappingNode: - d.unmarshal(n, out) + d.unmarshal(merge, out) case AliasNode: - if n.Alias != nil && n.Alias.Kind != MappingNode { + if merge.Alias != nil && merge.Alias.Kind != MappingNode { failWantMap() } - d.unmarshal(n, out) + d.unmarshal(merge, out) case SequenceNode: - // Step backwards as earlier nodes take precedence. - for i := len(n.Content) - 1; i >= 0; i-- { - ni := n.Content[i] + for i := 0; i < len(merge.Content); i++ { + ni := merge.Content[i] if ni.Kind == AliasNode { if ni.Alias != nil && ni.Alias.Kind != MappingNode { failWantMap() @@ -943,6 +991,8 @@ func (d *decoder) merge(n *Node, out reflect.Value) { default: failWantMap() } + + d.mergedFields = mergedFields } func isMerge(n *Node) bool { diff --git a/vendor/modules.txt b/vendor/modules.txt index 27d1656..a1f5893 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,16 +1,16 @@ # github.com/bitrise-io/go-plist v0.0.0-20210301100253-4b1a112ccd10 ## explicit; go 1.15 github.com/bitrise-io/go-plist -# github.com/bitrise-io/go-steputils v1.0.1 +# github.com/bitrise-io/go-steputils v1.0.2 ## explicit; go 1.15 github.com/bitrise-io/go-steputils/input github.com/bitrise-io/go-steputils/output github.com/bitrise-io/go-steputils/tools -# github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.1 +# github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.2 ## explicit; go 1.16 github.com/bitrise-io/go-steputils/v2/ruby github.com/bitrise-io/go-steputils/v2/stepconf -# github.com/bitrise-io/go-utils v1.0.1 +# github.com/bitrise-io/go-utils v1.0.2 ## explicit; go 1.13 github.com/bitrise-io/go-utils/colorstring github.com/bitrise-io/go-utils/command @@ -27,12 +27,13 @@ github.com/bitrise-io/go-utils/retry github.com/bitrise-io/go-utils/sliceutil github.com/bitrise-io/go-utils/stringutil github.com/bitrise-io/go-utils/ziputil -# github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.1 +# github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.11 ## explicit; go 1.16 github.com/bitrise-io/go-utils/v2/command github.com/bitrise-io/go-utils/v2/env github.com/bitrise-io/go-utils/v2/log -# github.com/bitrise-io/go-xcode v1.0.2 +github.com/bitrise-io/go-utils/v2/retryhttp +# github.com/bitrise-io/go-xcode v1.0.9 ## explicit; go 1.15 github.com/bitrise-io/go-xcode/appleauth github.com/bitrise-io/go-xcode/certificateutil @@ -50,7 +51,7 @@ github.com/bitrise-io/go-xcode/xcodeproject/serialized github.com/bitrise-io/go-xcode/xcodeproject/xcodeproj github.com/bitrise-io/go-xcode/xcodeproject/xcscheme github.com/bitrise-io/go-xcode/xcodeproject/xcworkspace -# github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.11 +# github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.20 ## explicit; go 1.16 github.com/bitrise-io/go-xcode/v2/autocodesign github.com/bitrise-io/go-xcode/v2/autocodesign/certdownloader @@ -62,6 +63,7 @@ github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/spaceship github.com/bitrise-io/go-xcode/v2/autocodesign/devportalclient/time github.com/bitrise-io/go-xcode/v2/autocodesign/keychain github.com/bitrise-io/go-xcode/v2/autocodesign/localcodesignasset +github.com/bitrise-io/go-xcode/v2/autocodesign/profiledownloader github.com/bitrise-io/go-xcode/v2/autocodesign/projectmanager github.com/bitrise-io/go-xcode/v2/codesign github.com/bitrise-io/go-xcode/v2/xcarchive @@ -75,8 +77,8 @@ github.com/davecgh/go-spew/spew # github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa ## explicit github.com/fullsailor/pkcs7 -# github.com/golang-jwt/jwt/v4 v4.2.0 -## explicit; go 1.15 +# github.com/golang-jwt/jwt/v4 v4.4.1 +## explicit; go 1.16 github.com/golang-jwt/jwt/v4 # github.com/google/go-querystring v1.1.0 ## explicit; go 1.10 @@ -84,10 +86,10 @@ github.com/google/go-querystring/query # github.com/hashicorp/go-cleanhttp v0.5.2 ## explicit; go 1.13 github.com/hashicorp/go-cleanhttp -# github.com/hashicorp/go-retryablehttp v0.7.0 +# github.com/hashicorp/go-retryablehttp v0.7.1 ## explicit; go 1.13 github.com/hashicorp/go-retryablehttp -# github.com/hashicorp/go-version v1.3.0 +# github.com/hashicorp/go-version v1.5.0 ## explicit github.com/hashicorp/go-version # github.com/pkg/errors v0.9.1 @@ -99,10 +101,10 @@ github.com/pmezard/go-difflib/difflib # github.com/ryanuber/go-glob v1.0.0 ## explicit github.com/ryanuber/go-glob -# github.com/stretchr/objx v0.3.0 +# github.com/stretchr/objx v0.4.0 ## explicit; go 1.12 github.com/stretchr/objx -# github.com/stretchr/testify v1.7.0 +# github.com/stretchr/testify v1.7.1 ## explicit; go 1.13 github.com/stretchr/testify/assert github.com/stretchr/testify/mock @@ -110,7 +112,7 @@ github.com/stretchr/testify/mock ## explicit; go 1.17 golang.org/x/text/transform golang.org/x/text/unicode/norm -# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b +# gopkg.in/yaml.v3 v3.0.0 ## explicit gopkg.in/yaml.v3 # howett.net/plist v1.0.0