def publish(self, application_package_path_patterns: Sequence[pathlib.Path], apple_id: Optional[str] = None, app_specific_password: Optional[ Types.AppSpecificPassword] = None, submit_to_testflight: Optional[bool] = None) -> None: """ Publish application packages to App Store and submit them to Testflight """ if not (apple_id and app_specific_password): self._assert_api_client_credentials( 'Either Apple ID and app specific password or App Store Connect API key information is required.' ) elif submit_to_testflight: self._assert_api_client_credentials( 'It is required for submitting an app to Testflight.') application_packages = self._get_publishing_application_packages( application_package_path_patterns) try: altool = Altool( username=apple_id, password=app_specific_password.value if app_specific_password else None, key_identifier=self._key_identifier, issuer_id=self._issuer_id, private_key=self._private_key, ) except ValueError as ve: raise AppStoreConnectError(str(ve)) failed_packages: List[str] = [] for application_package in application_packages: try: build, pre_release_version = self._publish_application_package( altool, application_package) if submit_to_testflight: self.create_beta_app_review_submission(build.id) except IOError as error: # TODO: Should we fail the whole action on first publishing failure? failed_packages.append(str(application_package.path)) self.logger.error(Colors.RED(error.args[0])) if failed_packages: raise AppStoreConnectError( f'Failed to publish {", ".join(failed_packages)}')
def run_test(self, xcode_project_path: Optional[pathlib.Path] = None, xcode_workspace_path: Optional[pathlib.Path] = None, target_name: Optional[str] = None, configuration_name: Optional[str] = None, scheme_name: Optional[str] = None, clean: bool = False, devices: Optional[List[str]] = None, disable_code_coverage: bool = False, max_concurrent_devices: Optional[int] = TestArgument.MAX_CONCURRENT_DEVICES.get_default(), max_concurrent_simulators: Optional[int] = TestArgument.MAX_CONCURRENT_SIMULATORS.get_default(), test_only: Optional[str] = TestArgument.TEST_ONLY.get_default(), test_sdk: str = TestArgument.TEST_SDK.get_default(), test_xcargs: Optional[str] = XcodeArgument.TEST_XCARGS.get_default(), test_flags: Optional[str] = XcodeArgument.TEST_FLAGS.get_default(), disable_xcpretty: bool = False, xcpretty_options: str = XcprettyArgument.OPTIONS.get_default(), output_dir: pathlib.Path = TestResultArgument.OUTPUT_DIRECTORY.get_default(), output_extension: str = TestResultArgument.OUTPUT_EXTENSION.get_default(), graceful_exit: bool = False): """ Run unit or UI tests for given Xcode project or workspace """ self._ensure_project_or_workspace(xcode_project_path, xcode_workspace_path) simulators = self._get_test_destinations(devices) xcodebuild = self._get_xcodebuild(**locals()) clean and self._clean(xcodebuild) self.echo(Colors.BLUE(f'Run tests for {(xcodebuild.workspace or xcodebuild.xcode_project).name}\n')) xcresult_collector = XcResultCollector() xcresult_collector.ignore_results(Xcode.DERIVED_DATA_PATH) try: xcodebuild.test( test_sdk, simulators, enable_code_coverage=not disable_code_coverage, only_testing=test_only, xcargs=test_xcargs, custom_flags=test_flags, max_concurrent_devices=max_concurrent_devices, max_concurrent_simulators=max_concurrent_simulators, ) except IOError: testing_failed = True self.echo(Colors.RED('\nTest run failed\n')) else: testing_failed = False self.echo(Colors.GREEN('\nTest run completed successfully\n')) xcresult_collector.gather_results(Xcode.DERIVED_DATA_PATH) output_dir.mkdir(parents=True, exist_ok=True) self._copy_simulator_logs(simulators, output_dir) if not xcresult_collector.get_collected_results(): raise XcodeProjectException('Did not find any test results') test_suites, xcresult = self._get_test_suites( xcresult_collector, show_found_result=True, save_xcresult_dir=output_dir) message = ( f'Executed {test_suites.tests} tests with ' f'{test_suites.failures} failures and ' f'{test_suites.errors} errors in ' f'{test_suites.time:.2f} seconds.\n' ) self.echo(Colors.BLUE(message)) TestSuitePrinter(self.echo).print_test_suites(test_suites) self._save_test_suite(xcresult, test_suites, output_dir, output_extension) if not graceful_exit: has_failing_tests = test_suites and (test_suites.failures or test_suites.errors) if testing_failed or has_failing_tests: raise XcodeProjectException('Tests failed')