/// <summary> /// The main method of this MSBuild task which calls the asynchronous execution method and /// collates logged errors in order to determine the success of HelixWorkItems /// </summary> /// <returns>A boolean value indicating the success of HelixWorkItem creation</returns> public bool ExecuteTask( IProvisioningProfileProvider provisioningProfileProvider, IZipArchiveManager zipArchiveManager, IFileSystem fileSystem) { var tasks = AppBundles.Select(bundle => PrepareWorkItem(zipArchiveManager, fileSystem, provisioningProfileProvider, bundle)); WorkItems = Task.WhenAll(tasks).GetAwaiter().GetResult().Where(wi => wi != null).ToArray(); return(!Log.HasLoggedErrors); }
/// <summary> /// Prepares HelixWorkItem that can run on an iOS device using XHarness /// </summary> /// <param name="appFolderPath">Path to application package</param> /// <returns>An ITaskItem instance representing the prepared HelixWorkItem.</returns> private async Task <ITaskItem> PrepareWorkItem( IZipArchiveManager zipArchiveManager, IFileSystem fileSystem, IProvisioningProfileProvider provisioningProfileProvider, ITaskItem appBundleItem) { var(workItemName, appFolderPath) = GetNameAndPath(appBundleItem, MetadataNames.AppBundlePath, fileSystem); appFolderPath = appFolderPath.TrimEnd(Path.DirectorySeparatorChar); bool isAlreadyArchived = appFolderPath.EndsWith(".zip"); if (isAlreadyArchived && workItemName.EndsWith(".app")) { // If someone named the zip something.app.zip, we want both gone workItemName = workItemName.Substring(0, workItemName.Length - 4); } if (!ValidateAppBundlePath(fileSystem, appFolderPath, isAlreadyArchived)) { Log.LogError($"App bundle not found in {appFolderPath}"); return(null); } // If we are re-using one .zip for multiple work items, we need to copy it to a new location // because we will be changing the contents (we assume we don't mind otherwise) if (isAlreadyArchived && appBundleItem.TryGetMetadata(MetadataNames.AppBundlePath, out string metadata) && !string.IsNullOrEmpty(metadata)) { string appFolderDirectory = fileSystem.GetDirectoryName(appFolderPath); string fileName = $"xharness-payload-{workItemName.ToLowerInvariant()}.zip"; string archiveCopyPath = fileSystem.PathCombine(appFolderDirectory, fileName); fileSystem.CopyFile(appFolderPath, archiveCopyPath, overwrite: true); appFolderPath = archiveCopyPath; } var(testTimeout, workItemTimeout, expectedExitCode, customCommands) = ParseMetadata(appBundleItem); // Validation of any metadata specific to iOS stuff goes here if (!appBundleItem.TryGetMetadata(MetadataNames.Target, out string target)) { Log.LogError($"'{MetadataNames.Target}' metadata must be specified - " + "expecting list of target device/simulator platforms to execute tests on (e.g. ios-simulator-64)"); return(null); } target = target.ToLowerInvariant(); // Optional timeout for the how long it takes for the app to be installed, booted and tests start executing TimeSpan launchTimeout = target.Contains("device") ? s_defaultDeviceLaunchTimeout : s_defaultSimulatorLaunchTimeout; if (appBundleItem.TryGetMetadata(MetadataNames.LaunchTimeout, out string launchTimeoutProp)) { if (!TimeSpan.TryParse(launchTimeoutProp, out launchTimeout) || launchTimeout.Ticks < 0) { Log.LogError($"Invalid value \"{launchTimeoutProp}\" provided in <{MetadataNames.LaunchTimeout}>"); return(null); } } bool includesTestRunner = true; if (appBundleItem.TryGetMetadata(MetadataNames.IncludesTestRunner, out string includesTestRunnerProp)) { if (includesTestRunnerProp.ToLowerInvariant() == "false") { includesTestRunner = false; } } if (includesTestRunner && expectedExitCode != 0 && customCommands != null) { Log.LogWarning($"The {MetadataName.ExpectedExitCode} property is ignored in the `apple test` scenario"); } bool resetSimulator = false; if (appBundleItem.TryGetMetadata(MetadataNames.ResetSimulator, out string resetSimulatorRunnerProp)) { if (resetSimulatorRunnerProp.ToLowerInvariant() == "true") { resetSimulator = true; } } if (customCommands == null) { // When no user commands are specified, we add the default `apple test ...` command customCommands = GetDefaultCommand(includesTestRunner, resetSimulator); } string appName = isAlreadyArchived ? $"{fileSystem.GetFileNameWithoutExtension(appFolderPath)}.app" : fileSystem.GetFileName(appFolderPath); string helixCommand = GetHelixCommand(appName, target, workItemTimeout, testTimeout, launchTimeout, includesTestRunner, expectedExitCode, resetSimulator); string payloadArchivePath = await CreatePayloadArchive( zipArchiveManager, fileSystem, workItemName, isAlreadyArchived, isPosix : true, appFolderPath, customCommands, new[] { EntryPointScript, RunnerScript }); provisioningProfileProvider.AddProfileToPayload(payloadArchivePath, target); return(CreateTaskItem(workItemName, payloadArchivePath, helixCommand, workItemTimeout)); }