From 1906fb798bf2f5b6d160a37f876776dccdd0af1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20G=C3=B6drei?= Date: Wed, 1 Jun 2022 15:01:45 +0200 Subject: [PATCH] Step 1818 xcconfig (#37) * Update step.yml * Add fallback_provisioning_profile_url_list input * Update e2e tests * Restore e2e test secrets * Add fallback profile test * Update bitrise.yml * Update bitrise.yml * Update bitrise.yml * Update go-xcode/v2 to pull latest xcconfig package * Update step.yml * Update step.yml * Remove fallback_provisioning_profile_url_list input and related feature * Remove test_api_key_signing_manual_fallback_on_error e2e test case * Update step.yml * Update e2e test bitrise.yml and regenerate README * Update step.go --- README.md | 11 +- codesign.go | 20 +-- e2e/bitrise.yml | 53 ++++---- go.mod | 24 ++-- go.sum | 44 +++--- main.go | 20 +-- step.go | 108 ++++++++------- step.yml | 44 +++--- .../command/rubycommand/rubycommand.go | 3 +- .../go-steputils/v2/ruby/environment.go | 7 +- .../go-utils/errorutil/errorutil.go | 6 +- vendor/github.com/bitrise-io/go-xcode/LICENSE | 21 +++ .../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 | 125 ++++++++++++++---- .../go-xcode/v2/codesign/inputparse.go | 101 ++++++++++++-- .../bitrise-io/go-xcode/v2/xcarchive/ios.go | 2 + .../go-xcode/v2/xcconfig/xcconfig.go | 41 +++++- .../go-xcode/v2/xcpretty/xcpretty.go | 16 ++- .../xcodebuild/resolve_package_deps.go | 89 +++++++++++++ .../xcodebuild/show_build_settings.go | 15 ++- .../xcodeproj/recreate_schemes.go | 2 +- .../go-xcode/xcodeproject/xcodeproj/target.go | 46 ++----- .../xcodeproj/target_dependency.go | 15 +-- .../xcodeproject/xcodeproj/xcodeproj.go | 41 +++++- .../xcodeproject/xcscheme/xcscheme.go | 19 +++ 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 | 27 ++-- 64 files changed, 1467 insertions(+), 548 deletions(-) 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 ca474f2..a53bb48 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,7 @@ To configure the Step: 4. **Device destination specifier**: Destination specifier describes the device to use as a destination. The input value sets xcodebuild's `-destination` option. Under **xcodebuild configuration** -5. **Build settings (xcconfig)**: Build settings to override the project's build settings. The build settings must be separated by newline character (`\n`). For example: - ``` - COMPILER_INDEX_STORE_ENABLE = NO - ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES - ``` -The input value sets xcodebuild's `-xcconfig` option. +5. **Build settings (xcconfig)**: Build settings to override the project's build settings. Can be the contents, file path or empty. 6. **Additional options for the xcodebuild command**: Additional options to be added to the executed xcodebuild command. Under **Xcode build log formatting**: @@ -71,8 +66,8 @@ You can also run this step directly with [Bitrise CLI](https://github.com/bitris | `scheme` | Xcode Scheme name. The input value sets xcodebuild's `-scheme` option. | required | `$BITRISE_SCHEME` | | `configuration` | Xcode Build Configuration. If not specified, the default Build Configuration will be used. The input value sets xcodebuild's `-configuration` option. | required | `Debug` | | `destination` | Destination specifier describes the device to use as a destination. The input value sets xcodebuild's `-destination` option. | required | `generic/platform=iOS` | -| `xcconfig_content` | Build settings to override the project's build settings. Build settings must be separated by newline character (`\n`). Example: ``` COMPILER_INDEX_STORE_ENABLE = NO ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES ``` The input value sets xcodebuild's `-xcconfig` option. | | `COMPILER_INDEX_STORE_ENABLE = NO` | -| `xcodebuild_options` | Additional options to be added to the executed xcodebuild command. | | | +| `xcconfig_content` | Build settings to override the project's build settings, using xcodebuild's `-xcconfig` option. You can't define `-xcconfig` option in `Additional options for the xcodebuild command` if this input is set. If empty, no setting is changed. When set it can be either: 1. Existing `.xcconfig` file path. Example: `./ios-sample/ios-sample/Configurations/Dev.xcconfig` 2. The contents of a newly created temporary `.xcconfig` file. (This is the default.) Build settings must be separated by newline character (`\n`). Example: ``` COMPILER_INDEX_STORE_ENABLE = NO ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES ``` | | `COMPILER_INDEX_STORE_ENABLE = NO` | +| `xcodebuild_options` | Additional options to be added to the executed xcodebuild command. Prefer using `Build settings (xcconfig)` input for specifying `-xcconfig` option. You can't use both. | | | | `log_formatter` | Defines how xcodebuild command's log is formatted. Available options: - `xcpretty`: The xcodebuild command’s output will be prettified by xcpretty. - `xcodebuild`: Only the last 20 lines of raw xcodebuild output will be visible in the build log. The raw xcodebuild log will be exported in both cases. | required | `xcpretty` | | `automatic_code_signing` | This input determines which Bitrise Apple service connection should be used for automatic code signing. Available values: - `off`: Do not do any auto code signing. - `api-key`: [Bitrise Apple Service connection with API Key](https://devcenter.bitrise.io/getting-started/connecting-to-services/setting-up-connection-to-an-apple-service-with-api-key/). - `apple-id`: [Bitrise Apple Service connection with Apple ID](https://devcenter.bitrise.io/getting-started/connecting-to-services/connecting-to-an-apple-service-with-apple-id/). | required | `off` | | `register_test_devices` | If this input is set, the Step will register the known test devices on Bitrise from team members with the Apple Developer Portal. Note that setting this to yes may cause devices to be registered against your limited quantity of test devices in the Apple Developer Portal, which can only be removed once annually during your renewal window. | required | `no` | diff --git a/codesign.go b/codesign.go index 176a171..1aa33ed 100644 --- a/codesign.go +++ b/codesign.go @@ -13,6 +13,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/autocodesign/projectmanager" "github.com/bitrise-io/go-xcode/v2/codesign" ) @@ -46,12 +47,13 @@ func createCodesignManager(managerOpts CodesignManagerOpts, xcodeMajorVersion in } codesignInputs := codesign.Input{ - AuthType: authType, - DistributionMethod: string(autocodesign.Development), - CertificateURLList: managerOpts.CertificateURLList, - CertificatePassphraseList: managerOpts.CertificatePassphraseList, - KeychainPath: managerOpts.KeychainPath, - KeychainPassword: managerOpts.KeychainPassword, + AuthType: authType, + DistributionMethod: string(autocodesign.Development), + CertificateURLList: managerOpts.CertificateURLList, + CertificatePassphraseList: managerOpts.CertificatePassphraseList, + KeychainPath: managerOpts.KeychainPath, + KeychainPassword: managerOpts.KeychainPassword, + FallbackProvisioningProfiles: "", } codesignConfig, err := codesign.ParseConfig(codesignInputs, cmdFactory) @@ -90,15 +92,17 @@ func createCodesignManager(managerOpts CodesignManagerOpts, xcodeMajorVersion in ConfigurationName: managerOpts.Configuration, }) if err != nil { - return codesign.Manager{}, fmt.Errorf("failed to open project: %w", err) + return codesign.Manager{}, err } + client := retry.NewHTTPClient().StandardClient() return codesign.NewManagerWithProject( opts, appleAuthCredentials, serviceConnection, devPortalClientFactory, - certdownloader.NewDownloader(codesignConfig.CertificatesAndPassphrases, retry.NewHTTPClient().StandardClient()), + certdownloader.NewDownloader(codesignConfig.CertificatesAndPassphrases, client), + profiledownloader.New(codesignConfig.FallbackProvisioningProfiles, client), codesignasset.NewWriter(codesignConfig.Keychain), localcodesignasset.NewManager(localcodesignasset.NewProvisioningProfileProvider(), localcodesignasset.NewProvisioningProfileConverter()), project, diff --git a/e2e/bitrise.yml b/e2e/bitrise.yml index edcd726..fbfea37 100644 --- a/e2e/bitrise.yml +++ b/e2e/bitrise.yml @@ -41,6 +41,8 @@ workflows: - BITRISE_SCHEME: sample swiftpm - CODE_SIGNING_METHOD: apple-id - TEAM_ID: 72SA8V3WYL + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST + - CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST after_run: - _run @@ -52,6 +54,8 @@ workflows: - BITRISE_SCHEME: sample-apps-fastlane-test - BITRISE_CONFIGURATION: Debug - CODE_SIGNING_METHOD: api-key + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST + - CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST after_run: - _run - _run_device_tests @@ -63,6 +67,8 @@ workflows: - BITRISE_PROJECT_PATH: ./ios-simple-objc/ios-simple-objc.xcodeproj - BITRISE_SCHEME: renamed_scheme - CODE_SIGNING_METHOD: "off" + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST + - CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST steps: - certificate-and-profile-installer: { } after_run: @@ -77,6 +83,8 @@ workflows: - BITRISE_CONFIGURATION: Debug - CODE_SIGNING_METHOD: apple-id - TEAM_ID: 72SA8V3WYL + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST + - CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST after_run: - _run @@ -87,6 +95,8 @@ workflows: - BITRISE_PROJECT_PATH: ./ios-simple-objc/ios-simple-objc.xcodeproj - BITRISE_SCHEME: renamed_scheme - CODE_SIGNING_METHOD: api-key + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST + - CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST after_run: - _run @@ -97,6 +107,8 @@ workflows: - BITRISE_PROJECT_PATH: ./ios-simple-objc/ios-simple-objc.xcodeproj - BITRISE_SCHEME: Scheme with spaces - CODE_SIGNING_METHOD: api-key + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST + - CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST after_run: - _run @@ -108,6 +120,8 @@ workflows: - BITRISE_SCHEME: renamed_scheme - XCODE_BUILD_OPTIONS: -derivedDataPath $BITRISE_SOURCE_DIR/_tmp/ddata -destination generic/platform=iOS - CODE_SIGNING_METHOD: api-key + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST + - CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST after_run: - _run @@ -119,32 +133,23 @@ workflows: - BITRISE_SCHEME: Scheme with spaces - XCODE_BUILD_OPTIONS: -derivedDataPath $BITRISE_SOURCE_DIR/_tmp/ddata -destination generic/platform=iOS - CODE_SIGNING_METHOD: api-key + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST + - CERTIFICATE_PASSPHRASE_LIST: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST after_run: - _run test_single_certificate_no_passphrase: - steps: - - script: - inputs: - - content: |- - #!/bin/bash - set -ex - rm -rf "./_tmp" - mkdir -p "./_tmp" - - git::https://github.com/bitrise-steplib/bitrise-step-simple-git-clone.git@master: - inputs: - - repository_url: https://github.com/bitrise-io/sample-apps-ios-simple-objc.git - - branch: bundle_id - - clone_into_dir: ./_tmp - - path::./: - title: Step Test - inputs: - - project_path: ./_tmp/ios-simple-objc/ios-simple-objc.xcodeproj - - scheme: ios-simple-objc - - automatic_code_signing: api-key - - certificate_url_list: $BITFALL_APPLE_IOS_CERTIFICATE_NOPASSPHRASE_URL - - passphrase_list: "" - - apple_team_id: 72SA8V3WYL + envs: + - SAMPLE_APP_URL: https://github.com/bitrise-io/sample-apps-ios-simple-objc.git + - SAMPLE_APP_BRANCH: bundle_id + - BITRISE_PROJECT_PATH: ./ios-simple-objc/ios-simple-objc.xcodeproj + - BITRISE_SCHEME: ios-simple-objc + - CODE_SIGNING_METHOD: api-key + - TEAM_ID: 72SA8V3WYL + - CERTIFICATE_URL_LIST: $BITFALL_APPLE_IOS_CERTIFICATE_NOPASSPHRASE_URL + - CERTIFICATE_PASSPHRASE_LIST: "" + after_run: + - _run _run: steps: @@ -169,8 +174,8 @@ workflows: - output_tool: xcodebuild - xcodebuild_options: $XCODE_BUILD_OPTIONS - automatic_code_signing: $CODE_SIGNING_METHOD - - certificate_url_list: $BITFALL_APPLE_APPLE_CERTIFICATE_URL_LIST - - passphrase_list: $BITFALL_APPLE_APPLE_CERTIFICATE_PASSPHRASE_LIST + - certificate_url_list: $CERTIFICATE_URL_LIST + - passphrase_list: $CERTIFICATE_PASSPHRASE_LIST - apple_team_id: $TEAM_ID - git::https://github.com/bitrise-steplib/bitrise-step-check-step-outputs.git@main: is_always_run: true diff --git a/go.mod b/go.mod index 2661481..1ae47a1 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,17 @@ module github.com/bitrise-steplib/steps-xcode-build-for-test go 1.17 require ( - github.com/bitrise-io/go-steputils v1.0.1 - github.com/bitrise-io/go-utils v1.0.1 - github.com/bitrise-io/go-xcode v1.0.2 + github.com/bitrise-io/go-steputils v1.0.2 + github.com/bitrise-io/go-utils v1.0.2 + github.com/bitrise-io/go-xcode v1.0.6 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 golang.org/x/text v0.3.7 // indirect ) require ( - github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.1 - github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.2 - github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.11 + github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.2 + github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.7 + github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.17 ) require ( @@ -21,15 +21,15 @@ 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/stretchr/objx v0.3.0 // indirect - github.com/stretchr/testify v1.7.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + github.com/stretchr/objx v0.4.0 // indirect + github.com/stretchr/testify v1.7.1 // indirect + gopkg.in/yaml.v3 v3.0.0 // indirect howett.net/plist v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index c83ce10..b33cbd4 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +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 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-utils/v2 v2.0.0-alpha.2 h1:w3fwgLLmxMOpYNa6W5aLtJZE8M8+qGE5VPOcr+st59c= -github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.2/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.7 h1:d0XDESvQwOO+V9afZrI8QGR7bJGDkmE4Q9ezIBB4TLw= +github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.7/go.mod h1:6i0Gt0JRIbXpsrFDJT1YWghFfdN8qF26/fnpc/6d/88= +github.com/bitrise-io/go-xcode v1.0.6 h1:hSKwkDXUn9/gMk6HiJRUvurGWelfQEBWcO7JAvXi+y8= +github.com/bitrise-io/go-xcode v1.0.6/go.mod h1:Y0Wu2dXm0MilJ/4D3+gPHaNMlUcP+1DjIPoLPykq7wY= +github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.17 h1:aLlblow6vgnFKBRJRPz03O/M6x6LYY57wDkRCh66XL0= +github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.17/go.mod h1:oYILBt4j8jn69avylknuqsUO/BSiRx9i+JaxcNOtWMA= 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= @@ -21,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= @@ -33,10 +35,12 @@ 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/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -45,18 +49,21 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn 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= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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= @@ -77,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 1449154..a610b52 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import ( "os" - "github.com/bitrise-io/go-utils/log" + v2log "github.com/bitrise-io/go-utils/v2/log" ) func main() { @@ -11,16 +11,18 @@ func main() { } func run() int { - s := createStep() + logger := v2log.NewLogger() + + s := createStep(logger) cfg, err := s.ProcessConfig() if err != nil { - log.Errorf("Process config: %s", err) + logger.Errorf("Process config: %s", err) return 1 } if err := s.InstallDependencies(cfg.XCPretty); err != nil { - log.Warnf("Install dependencies: %s", err) - log.Printf("Switching to xcodebuild for output tool") + logger.Warnf("Install dependencies: %s", err) + logger.Printf("Switching to xcodebuild for output tool") cfg.XCPretty = false } @@ -31,10 +33,10 @@ func run() int { }) if runErr != nil { - log.Errorf("Run: %s", runErr) + logger.Errorf("Run: %s", runErr) } if exportErr != nil { - log.Errorf("Export outputs: %s", exportErr) + logger.Errorf("Export outputs: %s", exportErr) } if runErr != nil || exportErr != nil { return 1 @@ -43,6 +45,6 @@ func run() int { return 0 } -func createStep() TestBuilder { - return NewTestBuilder() +func createStep(logger v2log.Logger) TestBuilder { + return NewTestBuilder(logger) } diff --git a/step.go b/step.go index a942d16..3446f94 100644 --- a/step.go +++ b/step.go @@ -13,6 +13,7 @@ import ( "github.com/bitrise-io/go-steputils/v2/stepconf" "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" + "github.com/bitrise-io/go-utils/sliceutil" v2command "github.com/bitrise-io/go-utils/v2/command" "github.com/bitrise-io/go-utils/v2/env" v2fileutil "github.com/bitrise-io/go-utils/v2/fileutil" @@ -73,7 +74,7 @@ type Config struct { Scheme string Configuration string Destination string - XCConfigContent string + XCConfig string XcodebuildOptions []string XCPretty bool CodesignManager *codesign.Manager @@ -84,10 +85,13 @@ type Config struct { } type TestBuilder struct { + logger v2log.Logger } -func NewTestBuilder() TestBuilder { - return TestBuilder{} +func NewTestBuilder(logger v2log.Logger) TestBuilder { + return TestBuilder{ + logger: logger, + } } func (b TestBuilder) ProcessConfig() (Config, error) { @@ -96,12 +100,11 @@ func (b TestBuilder) ProcessConfig() (Config, error) { if err := parser.Parse(&input); err != nil { return Config{}, err } - logger := v2log.NewLogger() - logger.EnableDebugLog(input.VerboseLog) + b.logger.EnableDebugLog(input.VerboseLog) log.SetEnableDebugLog(input.VerboseLog) stepconf.Print(input) - fmt.Println() + b.logger.Println() absProjectPath, err := filepath.Abs(input.ProjectPath) if err != nil { @@ -126,7 +129,7 @@ func (b TestBuilder) ProcessConfig() (Config, error) { if err != nil { return Config{}, fmt.Errorf("failed to get xcode version: %w", err) } - log.Infof("Xcode version: %s (%s)", xcodebuildVersion.Version, xcodebuildVersion.BuildVersion) + b.logger.Infof("Xcode version: %s (%s)", xcodebuildVersion.Version, xcodebuildVersion.BuildVersion) var swiftPackagesPath string if xcodebuildVersion.MajorVersion >= 11 { @@ -136,12 +139,20 @@ func (b TestBuilder) ProcessConfig() (Config, error) { } } + if strings.TrimSpace(input.XCConfigContent) == "" { + input.XCConfigContent = "" + } + var customOptions []string if input.XcodebuildOptions != "" { customOptions, err = shellquote.Split(input.XcodebuildOptions) if err != nil { return Config{}, fmt.Errorf("provided additional options (%s) are not valid CLI arguments: %w", input.XcodebuildOptions, err) } + + if sliceutil.IsStringInSlice("-xcconfig", customOptions) && input.XCConfigContent != "" { + return Config{}, fmt.Errorf("`-xcconfig` option found in 'Additional options for the xcodebuild command' input, please clear 'Build settings (xcconfig)' input as only one can be set") + } } var codesignManager *codesign.Manager @@ -161,7 +172,7 @@ func (b TestBuilder) ProcessConfig() (Config, error) { BuildURL: input.BuildURL, BuildAPIToken: input.BuildAPIToken, VerboseLog: input.VerboseLog, - }, xcodebuildVersion.MajorVersion, logger, factory) + }, xcodebuildVersion.MajorVersion, b.logger, factory) if err != nil { return Config{}, err } @@ -173,7 +184,7 @@ func (b TestBuilder) ProcessConfig() (Config, error) { Scheme: input.Scheme, Configuration: input.Configuration, Destination: input.Destination, - XCConfigContent: input.XCConfigContent, + XCConfig: input.XCConfigContent, XcodebuildOptions: customOptions, XCPretty: input.LogFormatter == "xcpretty", CodesignManager: codesignManager, @@ -189,9 +200,9 @@ func (b TestBuilder) InstallDependencies(useXCPretty bool) error { return nil } - fmt.Println() - log.Infof("Checking if output tool (xcpretty) is installed") - formatter := xcpretty.NewXcpretty() + b.logger.Println() + b.logger.Infof("Checking if output tool (xcpretty) is installed") + formatter := xcpretty.NewXcpretty(b.logger) installed, err := formatter.IsInstalled() if err != nil { @@ -199,9 +210,9 @@ func (b TestBuilder) InstallDependencies(useXCPretty bool) error { } if !installed { - log.Warnf("xcpretty is not installed") - fmt.Println() - log.Printf("Installing xcpretty") + b.logger.Warnf("xcpretty is not installed") + b.logger.Println() + b.logger.Printf("Installing xcpretty") cmdModelSlice, err := formatter.Install() if err != nil { @@ -220,7 +231,7 @@ func (b TestBuilder) InstallDependencies(useXCPretty bool) error { return fmt.Errorf("failed to get xcpretty version: %w", err) } - log.Printf("- xcpretty version: %s", xcprettyVersion.String()) + b.logger.Printf("- xcpretty version: %s", xcprettyVersion.String()) return nil } @@ -240,20 +251,14 @@ func (b TestBuilder) Run(cfg Config) (RunOut, error) { defer func() { if authOptions != nil && authOptions.KeyPath != "" { if err := os.Remove(authOptions.KeyPath); err != nil { - log.Warnf("failed to remove private key file: %s", err) + b.logger.Warnf("failed to remove private key file: %s", err) } } }() // Build for testing - fmt.Println() - log.Infof("Running xcodebuild") - - xcconfigWriter := xcconfig.NewWriter(v2pathutil.NewPathProvider(), v2fileutil.NewFileManager()) - xcconfigPath, err := xcconfigWriter.Write(cfg.XCConfigContent) - if err != nil { - return RunOut{}, err - } + b.logger.Println() + b.logger.Infof("Running xcodebuild") xcodeBuildCmd := xcodebuild.NewCommandBuilder(cfg.ProjectPath, xcworkspace.IsWorkspace(cfg.ProjectPath), "") xcodeBuildCmd.SetScheme(cfg.Scheme) @@ -261,7 +266,16 @@ func (b TestBuilder) Run(cfg Config) (RunOut, error) { xcodeBuildCmd.SetCustomBuildAction("build-for-testing") xcodeBuildCmd.SetDestination(cfg.Destination) xcodeBuildCmd.SetCustomOptions(cfg.XcodebuildOptions) - xcodeBuildCmd.SetXCConfigPath(xcconfigPath) + + if cfg.XCConfig != "" { + xcconfigWriter := xcconfig.NewWriter(v2pathutil.NewPathProvider(), v2fileutil.NewFileManager(), v2pathutil.NewPathChecker(), v2pathutil.NewPathModifier()) + xcconfigPath, err := xcconfigWriter.Write(cfg.XCConfig) + if err != nil { + return RunOut{}, err + } + xcodeBuildCmd.SetXCConfigPath(xcconfigPath) + } + if authOptions != nil { xcodeBuildCmd.SetAuthentication(*authOptions) } @@ -281,13 +295,13 @@ func (b TestBuilder) Run(cfg Config) (RunOut, error) { // Cache swift packages if cfg.CacheLevel == "swift_packages" { if err := cache.CollectSwiftPackages(cfg.ProjectPath); err != nil { - log.Warnf("Failed to mark swift packages for caching: %s", err) + b.logger.Warnf("Failed to mark swift packages for caching: %s", err) } } // Find outputs - fmt.Println() - log.Infof("Searching for outputs") + b.logger.Println() + b.logger.Infof("Searching for outputs") testBundle, err := b.findTestBundle(findTestBundleOpts{ ProjectPath: cfg.ProjectPath, Scheme: cfg.Scheme, @@ -312,15 +326,15 @@ type ExportOpts struct { } func (b TestBuilder) ExportOutput(opts ExportOpts) error { - fmt.Println() - log.Infof("Export outputs") + b.logger.Println() + b.logger.Infof("Export outputs") if opts.XcodebuildLog != "" { xcodebuildLogPath := filepath.Join(opts.OutputDir, xcodebuildLogBaseName) if err := output.ExportOutputFileContent(opts.XcodebuildLog, xcodebuildLogPath, xcodebuildLogPathEnvKey); err != nil { - log.Warnf("Failed to export %s, error: %s", xcodebuildLogPathEnvKey, err) + b.logger.Warnf("Failed to export %s, error: %s", xcodebuildLogPathEnvKey, err) } - log.Donef("The xcodebuild command log file path is available in %s env: %s", xcodebuildLogPathEnvKey, xcodebuildLogPath) + b.logger.Donef("The xcodebuild command log file path is available in %s env: %s", xcodebuildLogPathEnvKey, xcodebuildLogPath) } if opts.BuiltTestDir == "" { @@ -332,7 +346,7 @@ func (b TestBuilder) ExportOutput(opts ExportOpts) error { if err := output.ExportOutputDir(opts.BuiltTestDir, outputTestDirPath, "BITRISE_TEST_DIR_PATH"); err != nil { return fmt.Errorf("failed to export BITRISE_TEST_DIR_PATH: %w", err) } - log.Donef("The built test directory is available in BITRISE_TEST_DIR_PATH env: %s", outputTestDirPath) + b.logger.Donef("The built test directory is available in BITRISE_TEST_DIR_PATH env: %s", outputTestDirPath) // Zipped test bundle outputTestBundleZipPath := filepath.Join(opts.OutputDir, "testbundle.zip") @@ -350,27 +364,27 @@ func (b TestBuilder) ExportOutput(opts ExportOpts) error { if err := tools.ExportEnvironmentWithEnvman("BITRISE_TEST_BUNDLE_ZIP_PATH", outputTestBundleZipPath); err != nil { return fmt.Errorf("failed to export BITRISE_TEST_BUNDLE_ZIP_PATH: %w", err) } - log.Donef("The zipped test bundle is available in BITRISE_TEST_BUNDLE_ZIP_PATH env: %s", outputTestBundleZipPath) + b.logger.Donef("The zipped test bundle is available in BITRISE_TEST_BUNDLE_ZIP_PATH env: %s", outputTestBundleZipPath) // xctestrun outputXCTestrunPth := filepath.Join(opts.OutputDir, filepath.Base(opts.XctestrunPth)) if err := output.ExportOutputFile(opts.XctestrunPth, outputXCTestrunPth, "BITRISE_XCTESTRUN_FILE_PATH"); err != nil { return fmt.Errorf("failed to export BITRISE_XCTESTRUN_FILE_PATH: %w", err) } - log.Donef("The built xctestrun file is available in BITRISE_XCTESTRUN_FILE_PATH env: %s", outputXCTestrunPth) + b.logger.Donef("The built xctestrun file is available in BITRISE_XCTESTRUN_FILE_PATH env: %s", outputXCTestrunPth) return nil } func (b TestBuilder) automaticCodeSigning(codesignManager *codesign.Manager) (*xcodebuild.AuthenticationParams, error) { - fmt.Println() + b.logger.Println() if codesignManager == nil { - log.Infof("Automatic code signing is disabled, skipped downloading code sign assets") + b.logger.Infof("Automatic code signing is disabled, skipped downloading code sign assets") return nil, nil } - log.Infof("Preparing code signing assets (certificates, profiles)") + b.logger.Infof("Preparing code signing assets (certificates, profiles)") xcodebuildAuthParams, err := codesignManager.PrepareCodesigning() if err != nil { @@ -413,8 +427,8 @@ func (b TestBuilder) findTestBundle(opts findTestBundleOpts) (testBundle, error) buildSettingsCmd.SetConfiguration(opts.Configuration) buildSettingsCmd.SetCustomOptions(append([]string{"build-for-testing"}, opts.XcodebuildOptions...)) - fmt.Println() - log.Donef("$ %s", buildSettingsCmd.PrintableCmd()) + b.logger.Println() + b.logger.Donef("$ %s", buildSettingsCmd.PrintableCmd()) buildSettings, err := buildSettingsCmd.RunAndReturnSettings() if err != nil { @@ -426,13 +440,13 @@ func (b TestBuilder) findTestBundle(opts findTestBundleOpts) (testBundle, error) if err != nil { return testBundle{}, fmt.Errorf("failed to get SYMROOT build setting: %w", err) } - log.Printf("SYMROOT: %s", symRoot) + b.logger.Printf("SYMROOT: %s", symRoot) configuration, err := buildSettings.String("CONFIGURATION") if err != nil { return testBundle{}, fmt.Errorf("failed to get CONFIGURATION build setting: %w", err) } - log.Printf("CONFIGURATION: %s", configuration) + b.logger.Printf("CONFIGURATION: %s", configuration) // Without better solution the step collects every xctestrun files and filters them for the build time frame xctestrunPthPattern := filepath.Join(symRoot, fmt.Sprintf("%s*.xctestrun", opts.Scheme)) @@ -440,7 +454,7 @@ func (b TestBuilder) findTestBundle(opts findTestBundleOpts) (testBundle, error) if err != nil { return testBundle{}, fmt.Errorf("failed to search for xctestrun file using pattern (%s): %w", xctestrunPthPattern, err) } - log.Printf("xctestrun paths: %s", strings.Join(xctestrunPths, ", ")) + b.logger.Printf("xctestrun paths: %s", strings.Join(xctestrunPths, ", ")) if len(xctestrunPths) == 0 { return testBundle{}, fmt.Errorf("no xctestrun file found with pattern: %s", xctestrunPthPattern) @@ -457,7 +471,7 @@ func (b TestBuilder) findTestBundle(opts findTestBundleOpts) (testBundle, error) if !info.ModTime().Before(buildStartTime) && !info.ModTime().After(buildEndTime) { buildXCTestrunPths = append(buildXCTestrunPths, xctestrunPth) } else { - log.Printf("xctestrun: %s was created at %s, which is outside of the window %s - %s ", xctestrunPth, info.ModTime(), buildStartTime, buildEndTime) + b.logger.Printf("xctestrun: %s was created at %s, which is outside of the window %s - %s ", xctestrunPth, info.ModTime(), buildStartTime, buildEndTime) } } @@ -468,7 +482,7 @@ func (b TestBuilder) findTestBundle(opts findTestBundleOpts) (testBundle, error) } xctestrunPth := buildXCTestrunPths[0] - log.Printf("Built xctestrun path: %s", xctestrunPth) + b.logger.Printf("Built xctestrun path: %s", xctestrunPth) // Without better solution the step determines the build target based on the xctestrun file name // ios-simple-objc_iphonesimulator12.0-x86_64.xctestrun @@ -485,7 +499,7 @@ func (b TestBuilder) findTestBundle(opts findTestBundleOpts) (testBundle, error) } else if !exist { return testBundle{}, fmt.Errorf("built test directory does not exist at: %s", builtTestDir) } - log.Printf("Built test directory: %s", builtTestDir) + b.logger.Printf("Built test directory: %s", builtTestDir) return testBundle{ BuiltTestDir: builtTestDir, diff --git a/step.yml b/step.yml index 4e994c4..2fe3fef 100644 --- a/step.yml +++ b/step.yml @@ -19,12 +19,7 @@ description: |- 4. **Device destination specifier**: Destination specifier describes the device to use as a destination. The input value sets xcodebuild's `-destination` option. Under **xcodebuild configuration** - 5. **Build settings (xcconfig)**: Build settings to override the project's build settings. The build settings must be separated by newline character (`\n`). For example: - ``` - COMPILER_INDEX_STORE_ENABLE = NO - ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES - ``` - The input value sets xcodebuild's `-xcconfig` option. + 5. **Build settings (xcconfig)**: Build settings to override the project's build settings. Can be the contents, file path or empty. 6. **Additional options for the xcodebuild command**: Additional options to be added to the executed xcodebuild command. Under **Xcode build log formatting**: @@ -116,22 +111,30 @@ inputs: opts: category: xcodebuild configuration title: Build settings (xcconfig) - summary: Build settings to override the project's build settings. + summary: Build settings to override the project's build settings, using xcodebuild's `-xcconfig` option. description: |- - Build settings to override the project's build settings. + Build settings to override the project's build settings, using xcodebuild's `-xcconfig` option. - Build settings must be separated by newline character (`\n`). + You can't define `-xcconfig` option in `Additional options for the xcodebuild command` if this input is set. - Example: + If empty, no setting is changed. When set it can be either: + 1. Existing `.xcconfig` file path. - ``` - COMPILER_INDEX_STORE_ENABLE = NO - ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES - ``` + Example: - The input value sets xcodebuild's `-xcconfig` option. + `./ios-sample/ios-sample/Configurations/Dev.xcconfig` -- xcodebuild_options: "" + 2. The contents of a newly created temporary `.xcconfig` file. (This is the default.) + + Build settings must be separated by newline character (`\n`). + + Example: + ``` + COMPILER_INDEX_STORE_ENABLE = NO + ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES + ``` + +- xcodebuild_options: opts: category: xcodebuild configuration title: Additional options for the xcodebuild command @@ -139,6 +142,8 @@ inputs: description: |- Additional options to be added to the executed xcodebuild command. + Prefer using `Build settings (xcconfig)` input for specifying `-xcconfig` option. You can't use both. + # xcodebuild log formatting - log_formatter: xcpretty @@ -266,8 +271,6 @@ inputs: category: Step output configuration title: Output directory path summary: This directory will contain the generated artifacts. - description: |- - This directory will contain the generated artifacts. is_required: true # Caching @@ -295,8 +298,6 @@ inputs: category: Debugging title: Enable verbose logging summary: If this input is set, the Step will print additional logs for debugging. - description: |- - If this input is set, the Step will print additional logs for debugging. value_options: - "yes" - "no" @@ -318,5 +319,4 @@ outputs: - BITRISE_XCODE_RAW_RESULT_TEXT_PATH: opts: title: "`xcodebuild build-for-testing` command log file path" - description: |- - The file path of the raw `xcodebuild build-for-testing` command log. + summary: The file path of the raw `xcodebuild build-for-testing` command log. diff --git a/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go b/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go index 4ce6cde..554497f 100644 --- a/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go +++ b/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" ) @@ -269,7 +270,7 @@ func IsSpecifiedRbenvRubyInstalled(workdir string) (bool, string, error) { cmd := command.New("rbenv", "version").SetDir(absWorkdir) out, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { - return false, "", fmt.Errorf("failed to check installed ruby version, %s error: %s", out, err) + log.Warnf("failed to check installed ruby version, %s error: %s", out, err) } return isSpecifiedRbenvRubyInstalled(out) } 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-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/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..35afd57 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 @@ -6,6 +6,7 @@ import ( "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" @@ -54,6 +55,7 @@ type Manager struct { bitriseConnection *devportalservice.AppleDeveloperConnection devPortalClientFactory devportalclient.Factory certDownloader autocodesign.CertificateProvider + fallbackProfileDownloader autocodesign.ProfileProvider assetInstaller autocodesign.AssetWriter localCodeSignAssetManager autocodesign.LocalCodeSignAssetManager @@ -70,6 +72,7 @@ func NewManagerWithArchive( connection *devportalservice.AppleDeveloperConnection, clientFactory devportalclient.Factory, certDownloader autocodesign.CertificateProvider, + fallbackProfileDownloader autocodesign.ProfileProvider, assetInstaller autocodesign.AssetWriter, localCodeSignAssetManager autocodesign.LocalCodeSignAssetManager, archive Archive, @@ -81,6 +84,7 @@ func NewManagerWithArchive( bitriseConnection: connection, devPortalClientFactory: clientFactory, certDownloader: certDownloader, + fallbackProfileDownloader: fallbackProfileDownloader, assetInstaller: assetInstaller, localCodeSignAssetManager: localCodeSignAssetManager, detailsProvider: archive, @@ -95,6 +99,7 @@ func NewManagerWithProject( connection *devportalservice.AppleDeveloperConnection, clientFactory devportalclient.Factory, certDownloader autocodesign.CertificateProvider, + fallbackProfileDownloader autocodesign.ProfileProvider, assetInstaller autocodesign.AssetWriter, localCodeSignAssetManager autocodesign.LocalCodeSignAssetManager, project projectmanager.Project, @@ -106,6 +111,7 @@ func NewManagerWithProject( bitriseConnection: connection, devPortalClientFactory: clientFactory, certDownloader: certDownloader, + fallbackProfileDownloader: fallbackProfileDownloader, assetInstaller: assetInstaller, localCodeSignAssetManager: localCodeSignAssetManager, detailsProvider: project, @@ -141,8 +147,19 @@ 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 } @@ -250,22 +267,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 +317,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 } @@ -308,7 +342,7 @@ func (m *Manager) registerTestDevices(credentials appleauth.Credentials, devices func (m *Manager) prepareCodeSigningWithBitrise(credentials appleauth.Credentials) 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 +353,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 } + 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: testDevices, + 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 +401,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..997a1c8 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 @@ -2,31 +2,38 @@ package codesign import ( "fmt" + "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-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 } // 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 +48,16 @@ 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 } @@ -92,3 +105,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/v2/xcconfig/xcconfig.go b/vendor/github.com/bitrise-io/go-xcode/v2/xcconfig/xcconfig.go index 24cc426..a372a7e 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/xcconfig/xcconfig.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/xcconfig/xcconfig.go @@ -2,34 +2,63 @@ package xcconfig import ( "fmt" + "path/filepath" + "strings" + "github.com/bitrise-io/go-utils/v2/fileutil" "github.com/bitrise-io/go-utils/v2/pathutil" - "path/filepath" ) // Writer ... type Writer interface { - Write(content string) (string, error) + Write(input string) (string, error) } type writer struct { pathProvider pathutil.PathProvider fileManager fileutil.FileManager + pathChecker pathutil.PathChecker + pathModifier pathutil.PathModifier } // NewWriter ... -func NewWriter(pathProvider pathutil.PathProvider, fileManager fileutil.FileManager) Writer { - return &writer{pathProvider: pathProvider, fileManager: fileManager} +func NewWriter(pathProvider pathutil.PathProvider, fileManager fileutil.FileManager, pathChecker pathutil.PathChecker, pathModifier pathutil.PathModifier) Writer { + return &writer{pathProvider: pathProvider, fileManager: fileManager, pathChecker: pathChecker, pathModifier: pathModifier} } -func (w writer) Write(content string) (string, error) { +// Write writes the contents of input into a xcconfig file if +// the provided content is not already a path to xcconfig file. +// If the content is a valid path to xcconfig, it will validate the path, +// and return the path. It returns error if it cannot finalize a xcconfig +// file and/or its path. +func (w writer) Write(input string) (string, error) { + if w.isPath(input) { + xcconfigPath, err := w.pathModifier.AbsPath(input) + if err != nil { + return "", fmt.Errorf("failed to convert xcconfig file path (%s) to absolute path: %w", input, err) + } + + pathExists, err := w.pathChecker.IsPathExists(xcconfigPath) + if err != nil { + return "", fmt.Errorf(err.Error()) + } + if !pathExists { + return "", fmt.Errorf("provided xcconfig file path doesn't exist: %s", input) + } + return xcconfigPath, nil + } + dir, err := w.pathProvider.CreateTempDir("") if err != nil { return "", fmt.Errorf("unable to create temp dir for writing XCConfig: %v", err) } xcconfigPath := filepath.Join(dir, "temp.xcconfig") - if err = w.fileManager.Write(xcconfigPath, content, 0644); err != nil { + if err = w.fileManager.Write(xcconfigPath, input, 0644); err != nil { return "", fmt.Errorf("unable to write XCConfig content into file: %v", err) } return xcconfigPath, nil } + +func (w writer) isPath(input string) bool { + return strings.HasSuffix(input, ".xcconfig") +} diff --git a/vendor/github.com/bitrise-io/go-xcode/v2/xcpretty/xcpretty.go b/vendor/github.com/bitrise-io/go-xcode/v2/xcpretty/xcpretty.go index be1814f..55ccad4 100644 --- a/vendor/github.com/bitrise-io/go-xcode/v2/xcpretty/xcpretty.go +++ b/vendor/github.com/bitrise-io/go-xcode/v2/xcpretty/xcpretty.go @@ -7,9 +7,10 @@ import ( "os" "github.com/bitrise-io/go-steputils/v2/ruby" - "github.com/bitrise-io/go-utils/log" + loggerV1 "github.com/bitrise-io/go-utils/log" "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/v2/xcodebuild" "github.com/hashicorp/go-version" ) @@ -84,11 +85,11 @@ func (c CommandModel) Run() (string, error) { // Always close xcpretty outputs defer func() { if err := pipeWriter.Close(); err != nil { - log.Warnf("Failed to close xcodebuild-xcpretty pipe, error: %s", err) + loggerV1.Warnf("Failed to close xcodebuild-xcpretty pipe, error: %s", err) } if err := prettyCmd.Wait(); err != nil { - log.Warnf("xcpretty command failed, error: %s", err) + fmt.Printf("xcpretty command failed, error: %s", err) } }() @@ -108,11 +109,14 @@ type Xcpretty interface { } type xcpretty struct { + logger log.Logger } // NewXcpretty ... -func NewXcpretty() Xcpretty { - return &xcpretty{} +func NewXcpretty(logger log.Logger) Xcpretty { + return &xcpretty{ + logger: logger, + } } func (x xcpretty) IsInstalled() (bool, error) { @@ -122,7 +126,7 @@ func (x xcpretty) IsInstalled() (bool, error) { return false, err } - return ruby.NewEnvironment(factory, locator).IsGemInstalled("xcpretty", "") + return ruby.NewEnvironment(factory, locator, x.logger).IsGemInstalled("xcpretty", "") } // Install ... 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..d589334 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/resolve_package_deps.go @@ -0,0 +1,89 @@ +package xcodebuild + +import ( + "fmt" + "path/filepath" + "time" + + "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() + start = time.Now() + ) + + log.Printf("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.Printf("Resolved package dependencies in %s.", time.Since(start).Round(time.Second)) + + 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..8f9ceb0 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 @@ -5,9 +5,11 @@ import ( "fmt" "path/filepath" "strings" + "time" "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 +119,23 @@ func parseBuildSettings(out string) (serialized.Object, error) { // RunAndReturnSettings ... func (c ShowBuildSettingsCommandModel) RunAndReturnSettings() (serialized.Object, error) { - cmd := c.Command() + var ( + cmd = c.Command() + start = time.Now() + ) + + log.Printf("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.Printf("Read target settings in %s.", time.Since(start).Round(time.Second)) + return parseBuildSettings(out) } 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..7105e84 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 @@ -52,7 +52,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) } } 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..e14cdcf 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 @@ -17,6 +17,8 @@ const ( LegacyTargetType TargetType = "PBXLegacyTarget" ) +const appClipProductType = "com.apple.product-type.application.on-demand-install-capable" + // Target ... type Target struct { Type TargetType @@ -29,49 +31,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 +74,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 { 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..255a49c 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,25 @@ 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 + 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...) + } + + return deduplicateTargetList(dependentTargets) +} + // ReadTargetInfoplist ... func (p XcodeProj) ReadTargetInfoplist(target, configuration string) (serialized.Object, int, error) { informationPropertyListPth, err := p.TargetInfoplistPath(target, configuration) @@ -182,7 +201,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 +218,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 { @@ -709,3 +728,17 @@ 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) + } + } + + 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..5656d7a 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 @@ -25,6 +25,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 +66,10 @@ type TestableReference struct { BuildableReference BuildableReference } +func (r TestableReference) isTestable() bool { + return r.Skipped == "NO" && r.BuildableReference.isTestProduct() +} + // MacroExpansion ... type MacroExpansion struct { BuildableReference BuildableReference @@ -230,3 +238,14 @@ 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 +} 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 81fb146..e209078 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,18 +1,18 @@ # 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/cache github.com/bitrise-io/go-steputils/command/rubycommand 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 @@ -29,14 +29,14 @@ 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.2 +# github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.7 ## 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/fileutil github.com/bitrise-io/go-utils/v2/log github.com/bitrise-io/go-utils/v2/pathutil -# github.com/bitrise-io/go-xcode v1.0.2 +# github.com/bitrise-io/go-xcode v1.0.6 ## explicit; go 1.15 github.com/bitrise-io/go-xcode/appleauth github.com/bitrise-io/go-xcode/certificateutil @@ -55,7 +55,7 @@ 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/xcpretty -# github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.11 +# github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.17 ## explicit; go 1.16 github.com/bitrise-io/go-xcode/v2/autocodesign github.com/bitrise-io/go-xcode/v2/autocodesign/certdownloader @@ -67,6 +67,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 @@ -83,8 +84,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 @@ -92,10 +93,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/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 @@ -107,10 +108,10 @@ github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 ## explicit github.com/pmezard/go-difflib/difflib -# 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 @@ -118,7 +119,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