1 <Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4 <!-- For the separate package scenario (not BuildTools) we need to pick up the right version of the assembly. -->
5 <!-- This will only work on versions of MSBuild that supply MSBuildRuntimeType (defaults to core in this case. -->
6 <BuildToolsTaskDir Condition="'$(BuildToolsTaskDir)'=='' And '$(MSBuildRuntimeType)' == 'Core'">$(MSBuildThisFileDirectory)</BuildToolsTaskDir>
7 <BuildToolsTaskDir Condition="'$(BuildToolsTaskDir)'=='' And '$(MSBuildRuntimeType)' == 'Full'">$(MSBuildThisFileDirectory)\desktop\</BuildToolsTaskDir>
10 <UsingTask TaskName="CreateAzureContainer" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
11 <UsingTask TaskName="RemoveItemMetadata" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
12 <UsingTask TaskName="SendJobsToHelix" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
13 <UsingTask TaskName="UploadToAzure" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
14 <UsingTask TaskName="ValidateWorkItems" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
15 <UsingTask TaskName="WriteItemsToJson" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
16 <UsingTask TaskName="WriteTestBuildStatsJson" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
17 <UsingTask TaskName="ZipFileCreateFromDirectory" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
18 <UsingTask TaskName="ZipFileCreateFromDependencyLists" AssemblyFile="$(BuildToolsTaskDir)Microsoft.DotNet.Build.CloudTestTasks.dll"/>
20 <!-- See Documentation\Samples\CloudTest.Helix.targets.sampleproject for a sample project.
22 Some helpful Helix environment variables: (Use appropriate-for-OS means to access, i.e. %WINDOWS% or $Linux, $OSX )
23 **********************************************************************************************************************************
24 HELIX_WORKITEM_PAYLOAD - Execution folder of helix workitem, current directory when using relative path.
25 HELIX_CORRELATION_ID - GUID identifier for a helix run.
26 HELIX_PYTHONPATH - Path to python executable
27 HELIX_CORRELATION_PAYLOAD - Correlation payload folder; root of where all correlation payloads are unzipped.
28 HELIX_WORKITEM_FRIENDLYNAME - Friendly name of work item
29 **********************************************************************************************************************************
31 Variables that CloudTest.Helix.Targets cares about:
32 **********************************************************************************************************************************
34 **********************************************************************************************************************************
35 HelixJobType - Job Type formatting string, used for sorting and display of jobs.
36 HelixSource - Job Source formatting string, used for sorting and display of jobs.
37 TargetQueues - Queue(s) to send Jobs to. (TODO: Need discoverability for users)
38 BuildMoniker - Identifying name for build when sending to Helix. Used for labelling runs.
39 CloudDropConnectionString - Azure Storage account connection string used for payloads.
40 CloudResultsConnectionString - Azure Storage account connection string used for results.
41 ArchivesRoot - Relative path for work item payloads to use. Blob Uris will be made relative to this.
43 **********************************************************************************************************************************
45 **********************************************************************************************************************************
46 TestListFilename - File name to use for test list sent to Helix. Default: TestList.json
47 OverwriteOnUpload - Whether to overwrite blobs if they already exist on upload. Default: False
48 ContainerName - Container name for uploaded files. Default: build-<Random GUID>.
49 IsOfficial - Boolean flag for display on Mission Control. Default: False:
50 HelixApiEndpoint - Endpoint to send jobs to. Default: https://helix.dot.net/api/2016-06-28/jobs
51 CloudResultsReadTokenValidDays - Days that result URLs produced will be readble Default: 30
52 CloudResultsWriteTokenValidDays - Days that result URLs produced will be writeable Default: 4
53 SupplementalPayloadDir - Temp (deletable) dir for assembling supplemental payloads Default: Random folder in %TEMP%
54 HelixApiAccessKey - GitHub API Access Key for sending jobs to Helix. Get from https://helix.dot.net/UserProfile/Index/
55 HelixLogFolder - Folder for storing JSON files describing job start and other info Default: <Blank>
56 HelixCorrelationInfoFileName - JSON file containing info on started jobs Default: Helix-correlation-infos.json
57 HelixJobProperties- Must be JSON. String describing Helix MC-specific metadata. Default: <Blank>
58 HelixArchLabel - If HelixJobProperties is not set, we'll use this to fill it out Default: <Blank>
59 HelixConfigLabel - If HelixJobProperties is not set, we'll use this to fill it out Default: <Blank>
60 MaxRetryCount - Max automatic retry of workitems which do not return 0 Default: 0 (no retry)
61 HelixAttempt - A lexically monotonic increasing string distinguishing Default: <Blank>
62 jobs whose results should override previous executions.
64 **********************************************************************************************************************************
65 Re-queuing Properties:
66 **********************************************************************************************************************************
67 UseContinuationRunner - Use runner script that is capable of sending to another queue when finished Default: False
68 SecondaryQueue - When submitting multi-stage tests, queue for secondary jobs Default: <Blank>
69 SecondarySasValidHours - SAS Valid time for token provided for multi-stage tests. Default: 15.0
70 SecondaryPayloadDir - Folder to make into workitem payload for continued execution Default: <Blank>
72 **********************************************************************************************************************************
74 **********************************************************************************************************************************
75 HelixWorkItem - Zip files to be uploaded as payloads.
77 **********************************************************************************************************************************
79 **********************************************************************************************************************************
80 HelixCorrelationPayloadFile - Zip files to be uploaded as correlation payloads (shared by all work items, cached where possible)
83 <!-- Main entry point -->
84 <Target Name="HelixCloudBuild" DependsOnTargets="VerifyInputs;PreCloudBuild;ValidateWorkItems;UploadContent;CreateTestListJson" />
87 <OverwriteOnUpload Condition="'$(OverwriteOnUpload)' == ''">false</OverwriteOnUpload>
88 <ContainerName Condition="'$(ContainerName)'== ''">build-$([System.Guid]::NewGuid().ToString("N"))</ContainerName>
89 <ContainerName>$(ContainerName.ToLower())</ContainerName>
90 <TestListFilename Condition="'$(TestListFilename)'==''">TestList.json</TestListFilename>
91 <SupplementalPayloadDir Condition="'$(SupplementalPayloadDir)' == ''">$([System.IO.Path]::GetTempPath())$([System.IO.Path]::GetRandomFileName())/SupplementalPayload/</SupplementalPayloadDir>
92 <SupplementalPayloadFilename>SupplementalPayload.zip</SupplementalPayloadFilename>
93 <SupplementalPayloadFile>$(ArchivesRoot)$(SupplementalPayloadFilename)</SupplementalPayloadFile>
94 <IsOfficial Condition="'$(IsOfficial)'!=''">false</IsOfficial>
95 <HelixApiEndpoint Condition="'$(HelixApiEndpoint)'==''">https://helix.dot.net/api/2016-06-28/jobs</HelixApiEndpoint>
96 <MaxRetryCount Condition="'$(MaxRetryCount)' == ''">0</MaxRetryCount>
99 <!-- Set Helix environment vars based on target platform -->
100 <!-- This is only used in the case where property 'UseScriptRunner' is true.-->
101 <PropertyGroup Condition="'$(TargetsWindows)' == 'true' AND '$(UseScriptRunner)' == 'true' ">
102 <HelixPythonPath>%HELIX_PYTHONPATH%</HelixPythonPath>
103 <HelixScriptRoot>%HELIX_SCRIPT_ROOT%\</HelixScriptRoot>
104 <RunnerScript>%HELIX_CORRELATION_PAYLOAD%\RunnerScripts\scriptrunner\scriptrunner.py</RunnerScript>
106 <PropertyGroup Condition="'$(TargetsWindows)' == 'true' AND '$(UseContinuationRunner)' == 'true' ">
107 <RunnerScript>%HELIX_CORRELATION_PAYLOAD%\RunnerScripts\scriptrunner\continuationrunner.py --next_queue $(SecondaryQueue) --next_payload_dir $(SecondaryPayloadDir)</RunnerScript>
108 <SecondarySasValidHours Condition="'$(SecondarySasValidHours)' == ''">15.0</SecondarySasValidHours>
110 <PropertyGroup Condition="'$(TargetsWindows)' != 'true' AND '$(UseScriptRunner)' == 'true' ">
111 <HelixPythonPath>$HELIX_PYTHONPATH</HelixPythonPath>
112 <HelixScriptRoot>$HELIX_SCRIPT_ROOT/</HelixScriptRoot>
113 <RunnerScript>$HELIX_CORRELATION_PAYLOAD/RunnerScripts/scriptrunner/scriptrunner.py</RunnerScript>
116 <Target Name="VerifyInputs">
117 <!-- Verify all required properties have been specified. Update the comment above if you update this list! -->
118 <Error Condition="'$(ArchivesRoot)' == ''" Text="Missing required property ArchivesRoot." />
119 <Error Condition="'$(HelixJobType)' == ''" Text="Missing required property HelixJobType." />
120 <Error Condition="'$(HelixSource)' == ''" Text="Missing required property HelixSource." />
121 <Error Condition="'$(TargetQueues)' == ''" Text="Missing required property TargetQueues." />
122 <Error Condition="'$(BuildMoniker)' == ''" Text="Missing required property BuildMoniker." />
123 <Error Condition="'$(CloudDropConnectionString)' == ''" Text="Missing required property CloudDropConnectionString." />
124 <Error Condition="'$(CloudResultsConnectionString)' == ''" Text="Missing required property CloudResultsConnectionString." />
125 <Error Condition="'$(HelixJobProperties)' == '' and ('$(HelixArchLabel)' == '' or '$(HelixConfigLabel)' == '')"
126 Text="HelixJobProperties (JSON), or HelixArchLabel and HelixConfigLabel (string) must be set to start Helix jobs" />
129 <!-- Provided as an extensibility point for targets to run before the real work begins -->
130 <Target Name="PreCloudBuild">
132 <!-- Copy runner scripts so they can be uploaded as supplemental payload -->
134 <RunnerScripts Include="$(ToolsDir)RunnerScripts/**/*.py" />
135 <RunnerScripts Include="$(ToolsDir)RunnerScripts/**/*.sh" />
136 <RunnerScripts Include="$(ToolsDir)RunnerScripts/**/*.txt" />
139 <!-- Split up Target Queues list
140 In order to support all delimiters (commas, plus and semicolons), I do a little hoop-jumping to do a replace first
141 Note that queues will never have ',', '+' or ';' in their name, and this greatly simplifies providing a queue list in *nix.
144 <ProcessedTargetQueues>$([System.String]::Copy('$(TargetQueues)').Replace(',',';').Replace('+',';'))</ProcessedTargetQueues>
148 <!-- This Split() is needed since the semicolon in ProcessedTargetQueues is now a literal -->
149 <TargetQueue Include="$(ProcessedTargetQueues.Split(';'))" />
151 <Message Text="Will Enqueue to @(TargetQueue->Count()) Queue(s) : @(TargetQueue)" />
153 <!-- Compress the supplemental payload directory for upload -->
154 <!-- We might not have RunnerScripts, so skip the tasks in that case -->
155 <MakeDir Directories="$(SupplementalPayloadDir)"/>
156 <Copy Condition="'@(RunnerScripts->Count())'!='0'"
157 SourceFiles="@(RunnerScripts)"
158 DestinationFiles="@(RunnerScripts->'$(SupplementalPayloadDir)RunnerScripts/%(RecursiveDir)%(Filename)%(Extension)')"
159 SkipUnchangedFiles="true" />
160 <ZipFileCreateFromDirectory Condition="'@(RunnerScripts->Count())'!='0'"
161 SourceDirectory="$(SupplementalPayloadDir)"
162 DestinationArchive="$(SupplementalPayloadFile)"
163 OverwriteDestination="true" />
164 <RemoveDir Directories="$(SupplementalPayloadDir)"/>
166 <SupplementalPayload Condition="'@(RunnerScripts->Count())'!='0'" Include="$(SupplementalPayloadFile)">
167 <RelativeBlobPath>$(SupplementalPayloadFilename)</RelativeBlobPath>
168 </SupplementalPayload>
172 <!-- Make sure the work items included contain all the required fields, calculate relative blob paths -->
173 <Target Name="ValidateWorkItems">
174 <ValidateWorkItems WorkItems="@(HelixWorkItem)" WorkItemArchiveRoot="$(ArchivesRoot)">
175 <Output TaskParameter="ProcessedWorkItems" ItemName="HelixProcessedWorkItem"/>
179 <!-- Create Azure containers and file shares -->
180 <Target Name="CreateAzureStorage">
181 <CreateAzureContainer
182 ConnectionString="$(CloudDropConnectionString)"
183 ContainerName="$(ContainerName)"
184 ReadOnlyTokenDaysValid="30">
185 <Output TaskParameter="StorageUri" PropertyName="DropUri" />
186 <Output TaskParameter="ReadOnlyToken" PropertyName="DropUriReadOnlyToken" />
187 </CreateAzureContainer>
190 <CloudResultsReadTokenValidDays Condition="'$(CloudResultsReadTokenValidDays)' == ''">30</CloudResultsReadTokenValidDays>
191 <CloudResultsWriteTokenValidDays Condition="'$(CloudResultsWriteTokenValidDays)' == ''">4</CloudResultsWriteTokenValidDays>
194 <CreateAzureContainer
195 ConnectionString="$(CloudResultsConnectionString)"
196 ContainerName="$(ContainerName)"
197 ReadOnlyTokenDaysValid ="$(CloudResultsReadTokenValidDays)"
198 WriteOnlyTokenDaysValid="$(CloudResultsWriteTokenValidDays)">
200 <Output TaskParameter="StorageUri" PropertyName="ResultsUri" />
201 <Output TaskParameter="ReadOnlyToken" PropertyName="ResultsReadOnlyToken" />
202 <Output TaskParameter="WriteOnlyToken" PropertyName="ResultsWriteOnlyToken" />
203 </CreateAzureContainer>
206 <!-- Upload content to Azure (Everything except test list) -->
207 <Target Name="UploadContent" DependsOnTargets="CreateAzureStorage">
209 <LocalFileForUpload Include="@(HelixProcessedWorkItem->Metadata('PayloadFile'))">
210 <RelativeBlobPath>%(RelativeBlobPath)</RelativeBlobPath>
211 </LocalFileForUpload>
212 <!-- For now assume these all go in the root of the container -->
213 <LocalPayloadFileForUpload Include="@(HelixCorrelationPayloadFile)">
214 <RelativeBlobPath>%(FileName)%(Extension)</RelativeBlobPath>
215 </LocalPayloadFileForUpload>
218 <!-- Debug output of work items, and a warning if there are none. -->
219 <Message Text="Files for upload :: @(LocalFileForUpload)" Importance="Low" />
221 <!-- Verify the test archives were created -->
222 <Warning Condition="'@(LocalFileForUpload->Count())' == '0'" Text="Didn't find any archives in supplied HelixWorkItem(s)." />
224 <!-- Work Item payloads -->
226 Condition="'@(LocalFileForUpload->Count())' != '0'"
227 ConnectionString="$(CloudDropConnectionString)"
228 ContainerName="$(ContainerName)"
229 Items="@(LocalFileForUpload->Distinct())"
230 Overwrite="$(OverwriteOnUpload)" />
232 <!-- Correlation payload(s) -->
234 Condition="'@(LocalPayloadFileForUpload->Count())' != '0'"
235 ConnectionString="$(CloudDropConnectionString)"
236 ContainerName="$(ContainerName)"
237 Items="@(LocalPayloadFileForUpload->Distinct())"
238 Overwrite="$(OverwriteOnUpload)" />
240 <!-- Supplemental payload. TODO: This could be combined with Correlation Payload items, there's not much(any?) difference -->
242 ConnectionString="$(CloudDropConnectionString)"
243 ContainerName="$(ContainerName)"
244 Items="@(SupplementalPayload)"
245 Overwrite="$(OverwriteOnUpload)"
246 Condition="'@(SupplementalPayload)' != ''" />
250 <Target Name="CreateTestListJson">
251 <!-- We always bring the supplemental payload folder.
252 This contains whatever's in src\Microsoft.DotNet.Build.CloudTestTasks\RunnerScripts,
253 but can also contain various other stuff.
256 <CorrelationPayloadUri Include="@(SupplementalPayload->'$(DropUri)%(RelativeBlobPath)$(DropUriReadOnlyToken)')" />
257 <CorrelationPayloadUri Include="@(LocalPayloadFileForUpload->'$(DropUri)%(RelativeBlobPath)$(DropUriReadOnlyToken)')" />
261 <!-- Flatten it into a property as msbuild chokes on @(CorrelationPayloadUri) in CorrelationPayloadUris -->
262 <CorrelationPayloadUris>@(CorrelationPayloadUri)</CorrelationPayloadUris>
263 <SecondaryQueuesJson Condition="'$(SecondaryQueue)' != ''">{ "QueueId":"$(SecondaryQueue)","SasValidHours": $(SecondarySasValidHours), "EnqueueSAS" : null, "DropContainerUri" : null,"DropContainerRsas" : null,"DropContainerWsas" : null }</SecondaryQueuesJson>
267 <HelixProcessedWorkItem>
268 <Command Condition="'$(UseScriptRunner)'!='true'">%(Command)</Command>
269 <!-- When UseScriptRunner is set, we'll wrap commands provided with special Helix-y goo for telemetry-->
270 <Command Condition="'$(UseScriptRunner)'=='true' AND '$(TargetsWindows)' == 'true'">$(HelixPythonPath) $(RunnerScript) --script %(Command)</Command>
271 <Command Condition="'$(UseScriptRunner)'=='true' AND '$(TargetsWindows)' != 'true'">chmod +x $HELIX_WORKITEM_PAYLOAD/*.sh && $(HelixPythonPath) $(RunnerScript) --script %(Command)</Command>
272 <CorrelationPayloadUris>[$(CorrelationPayloadUris)]</CorrelationPayloadUris>
273 <PayloadUri>$(DropUri)%(RelativeBlobPath)$(DropUriReadOnlyToken)</PayloadUri>
274 <WorkItemId>%(WorkItemId)</WorkItemId>
275 <TimeoutInSeconds>%(TimeoutInSeconds)</TimeoutInSeconds>
276 <SecondaryQueues Condition="'$(SecondaryQueue)' != ''">[$(SecondaryQueuesJson)]</SecondaryQueues>
277 </HelixProcessedWorkItem>
280 <!-- I'd love a built-in way to do this, but I'm compromising here since this lets us use
281 arbitrary extra metadata in the future to compose work items, then strip out extra stuff used along the way.
282 It lets us use a single item to bring along everything we might possibly need in the future -->
283 <RemoveItemMetadata Items="@(HelixProcessedWorkItem)" FieldsToRemove="RelativeBlobPath;PayloadFile">
284 <Output TaskParameter="ProcessedItems" ItemName="HelixProcessedWorkItemForList"/>
285 </RemoveItemMetadata>
287 <WriteItemsToJson JsonFileName="$(HelixLogFolder)$(TestListFilename)" Items="@(HelixProcessedWorkItemForList)" ForceJsonArray="true" />
289 <HelixWorkItemList Include="$(HelixLogFolder)$(TestListFilename)">
290 <RelativeBlobPath>$(TestListFilename)</RelativeBlobPath>
291 <BuildCompleteJson>$(HelixLogFolder)BuildComplete.json</BuildCompleteJson>
292 <OfficialBuildJson>$(HelixLogFolder)OfficialBuild.json</OfficialBuildJson>
293 <HelixJobUploadCompletePath>$(HelixLogFolder)helixjobuploadcomplete.sem</HelixJobUploadCompletePath>
298 ConnectionString="$(CloudDropConnectionString)"
299 ContainerName="$(ContainerName)"
300 Items="@(HelixWorkItemList)"
301 Overwrite="$(OverwriteOnUpload)" />
304 <!-- Write event hub notification JSON files -->
305 <Target Name="WriteCompletionEvent"
306 AfterTargets="CreateTestListJson"
307 Inputs="%(HelixWorkItemList.Identity)"
308 Outputs="%(HelixWorkItemList.BuildCompleteJson)">
310 <CreateItem Include="@(TargetQueue)" AdditionalMetadata="ResultsUri=$(ResultsUri)%(TargetQueue.Identity)/;QueueId=%(TargetQueue.Identity)">
311 <Output TaskParameter="Include" ItemName="BuildCompleteTemplateV2" />
314 <!-- If the user didn't provide HelixJobProperties, generate them from HelixArchLabel, HelixConfigLabel, and QueueId -->
315 <ItemGroup Condition="'$(HelixJobProperties)' == ''">
316 <BuildCompleteTemplateV2>
317 <Properties>{ "architecture" : "$(HelixArchLabel)", "configuration": "$(HelixConfigLabel)", "operatingSystem" : "%(QueueId)" }</Properties>
318 </BuildCompleteTemplateV2>
320 <ItemGroup Condition="'$(HelixJobProperties)' != ''">
321 <BuildCompleteTemplateV2>
322 <Properties>$(HelixJobProperties)</Properties>
323 </BuildCompleteTemplateV2>
326 <ItemGroup Condition="'$(HelixCreator)' != ''">
327 <BuildCompleteTemplateV2>
328 <Creator>$(HelixCreator)</Creator>
329 </BuildCompleteTemplateV2>
332 <ItemGroup Condition="'$(HelixPullRequestId)' != ''">
333 <BuildCompleteTemplateV2>
334 <PullRequestId>$(HelixPullRequestId)</PullRequestId>
335 </BuildCompleteTemplateV2>
339 <!-- V1 is long since deprecated, and not supported here.
340 Keeping the name for clarity. -->
341 <BuildCompleteTemplateV2>
342 <DropContainerSAS>$(DropUriReadOnlyToken)</DropContainerSAS>
343 <ListUri>$(DropUri)%(HelixWorkItemList.Filename)%(HelixWorkItemList.Extension)$(DropUriReadOnlyToken)</ListUri>
344 <ResultsUriRSAS>$(ResultsReadOnlyToken)</ResultsUriRSAS>
345 <ResultsUriWSAS>$(ResultsWriteOnlyToken)</ResultsUriWSAS>
346 <Build>$(BuildMoniker)</Build>
347 <Type>$(HelixJobType)</Type>
348 <Source>$(HelixSource)</Source>
349 <MaxRetryCount>$(MaxRetryCount)</MaxRetryCount>
350 <Attempt>$(HelixAttempt)</Attempt>
351 </BuildCompleteTemplateV2>
352 <BuildComplete Include="@(BuildCompleteTemplateV2)"/>
355 <WriteItemsToJson JsonFileName="%(HelixWorkItemList.BuildCompleteJson)" Items="@(BuildComplete)" />
356 <Message Text="Wrote job-start (build complete) JSON for @(BuildComplete->Count()) Queues." />
357 <Message Condition="$(MaxRetryCount) > 1" Text="Work Items will automatically retry on non-zero exit code up to $(MaxRetryCount) times." />
359 <CreateItem Include="%(HelixWorkItemList.BuildCompleteJson)" AdditionalMetadata="RelativeBlobPath=JobStartJsonMessages.json">
360 <Output TaskParameter="Include" ItemName="JobStartJsons" />
364 ConnectionString="$(CloudDropConnectionString)"
365 ContainerName="$(ContainerName)"
366 Items="@(JobStartJsons)"
367 Overwrite="$(OverwriteOnUpload)" />
368 <Message Text="Uploaded job-start JSON files to $(ContainerName). These can be used for resending the same job for debugging purposes." />
372 <!-- Send completion event to Helix API -->
373 <Target Name="SendCompletionEvent"
374 AfterTargets="WriteCompletionEvent"
375 Inputs="%(HelixWorkItemList.BuildCompleteJson)"
376 Outputs="%(HelixWorkItemList.HelixJobUploadCompletePath)"
377 Condition="'$(SkipSendToHelix)' != 'true'">
379 AccessToken="$(HelixApiAccessKey)"
380 ApiEndpoint="$(HelixApiEndpoint)"
381 EventDataPath="%(HelixWorkItemList.BuildCompleteJson)">
382 <Output TaskParameter="JobIds" ItemName="GeneratedCorrelationId" />
385 <!-- Upload the Correlation Ids generated to the test drop container for tracking purposes-->
387 <HelixCorrelationInfoFileName Condition="'$(HelixCorrelationInfoFileName)'==''">Helix-correlation-infos.json</HelixCorrelationInfoFileName>
390 <Message Text="Writing correlation info to: $(HelixLogFolder)$(HelixCorrelationInfoFileName) " />
391 <WriteItemsToJson JsonFileName="$(HelixLogFolder)$(HelixCorrelationInfoFileName)" Items="@(GeneratedCorrelationId)" ForceJsonArray="true" />
393 <CorrelationFile Include="$(HelixLogFolder)$(HelixCorrelationInfoFileName)">
394 <RelativeBlobPath>Tracking/$(HelixCorrelationInfoFileName)</RelativeBlobPath>
399 ConnectionString="$(CloudDropConnectionString)"
400 ContainerName="$(ContainerName)"
401 Items="@(CorrelationFile)"