Skip to content

Commit 535652a

Browse files
authored
Onboard Static Validation Tests (#5065)
1 parent 356f292 commit 535652a

11 files changed

+684
-8
lines changed

build/AzurePipelinesTemplates/WindowsAppSDK-Build-Stage.yml

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ parameters:
1111

1212
stages:
1313
- stage: Build
14+
# Skip the build job if we are reusing the output of a previous build.
15+
# useBuildOutputFromBuildId variable is set on the Pipeline at Queue time.
16+
condition:
17+
eq(variables['useBuildOutputFromBuildId'],'')
1418
dependsOn: []
1519
jobs:
1620
- job: VerifyCopyrightHeaders

build/AzurePipelinesTemplates/WindowsAppSDK-PackTransportPackage-Stage.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ parameters:
1818
stages:
1919
- stage: Pack
2020
dependsOn: Build
21-
condition: not(failed())
21+
condition:
22+
eq(variables['useBuildOutputFromBuildId'],'')
2223
jobs:
2324
- job: NugetPackage
2425
pool:

build/AzurePipelinesTemplates/WindowsAppSDK-Publish-Stage.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ stages:
99
- stage: Publish
1010
dependsOn:
1111
- Test
12-
- Pack
12+
- StaticValidationTest
1313
condition: not(failed())
1414
jobs:
1515
# Publish
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
parameters:
2+
- name: "SignOutput"
3+
type: boolean
4+
default: false
5+
6+
stages:
7+
- stage: StaticValidationTest
8+
dependsOn: Pack
9+
condition: not(failed())
10+
jobs:
11+
- job: StaticValidationTest
12+
pool:
13+
type: windows
14+
isCustom: true
15+
name: 'ProjectReunionESPool-2022' # This stage is purely for ES, hence this custom pool
16+
timeoutInMinutes: 120
17+
steps:
18+
- task: NuGetToolInstaller@1
19+
- task: NuGetAuthenticate@1
20+
21+
- task: powershell@2
22+
displayName: 'DevCheck: Setup/Verify development environment'
23+
inputs:
24+
targetType: filePath
25+
filePath: tools\DevCheck\DevCheck.ps1
26+
arguments: -NoInteractive -Offline -Verbose -CheckTestPfx -Clean -CheckDependencies -ShowSystemInfo
27+
workingDirectory: '$(Build.SourcesDirectory)'
28+
29+
- task: DownloadPipelineArtifact@2
30+
displayName: 'Download Foundation'
31+
inputs:
32+
source: specific
33+
runVersion: specific
34+
project: $(System.TeamProjectId)
35+
pipeline: $(_useBuildOutputFromPipeline)
36+
pipelineId: $(_useBuildOutputFromBuildId)
37+
artifactName: "TransportPackage"
38+
targetPath: $(System.ArtifactsDirectory)
39+
40+
- task: CopyFiles@2
41+
inputs:
42+
SourceFolder: '$(System.ArtifactsDirectory)'
43+
Contents: |
44+
**/*.nupkg
45+
targetFolder: $(Build.SourcesDirectory)\localpackages
46+
47+
- task: PowerShell@2
48+
name: ExtractWindowsAppSDKVersion
49+
displayName: Extract WindowsAppSDKVersion
50+
inputs:
51+
targetType: 'inline'
52+
script: |
53+
$files = Get-ChildItem "$(Build.SourcesDirectory)\localpackages" -Filter "*Microsoft.WindowsAppSDK.Foundation.TransportPackage*.nupkg"
54+
Write-Host $files.Count
55+
if ($files.Count -eq 1)
56+
{
57+
Write-Host "file:" $files.FullName
58+
$version = (($files.FullName -Split "Microsoft.WindowsAppSDK.Foundation.TransportPackage.")[1] -Split ".nupkg")[0]
59+
Write-Host "|$version|"
60+
Write-Host "##vso[task.setvariable variable=FoundationVersion]$version"
61+
}
62+
else
63+
{
64+
Write-Host "Error: Found more than one Foundation TransportPackage Found"
65+
Write-Host "Please make sure only one package is present"
66+
Write-Host "##vso[task.complete result=Failed;]DONE"
67+
}
68+
69+
- task: VSBuild@1
70+
displayName: 'Restore PackageInspectionTest.sln'
71+
inputs:
72+
solution: $(Build.SourcesDirectory)\test\StaticValidationTests\PackageInspectionTest.csproj
73+
msbuildArgs: /t:restore /p:FoundationVersion="$(FoundationVersion)" /p:RestoreAdditionalProjectSources="$(Build.SourcesDirectory)\localpackages"
74+
75+
- task: VSBuild@1
76+
displayName: 'Build PackageInspectionTest.sln'
77+
inputs:
78+
solution: $(Build.SourcesDirectory)\test\StaticValidationTests\PackageInspectionTest.csproj
79+
80+
- script: |
81+
dir /s $(Build.SourcesDirectory)\Packages
82+
83+
- task: PowerShell@2
84+
displayName: 'Run PackageInspectionTests'
85+
inputs:
86+
targetType: 'inline'
87+
ignoreLASTEXITCODE: true
88+
script: |
89+
$KitsRoot10 = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots" -Name KitsRoot10).KitsRoot10
90+
$WindowsSdkBinDir = Join-Path $KitsRoot10 "bin\10.0.22000.0\x86"
91+
92+
$path = "$(Build.SourcesDirectory)\Packages\Microsoft.WindowsAppSDK.Foundation.TransportPackage\$(FoundationVersion)"
93+
$buildtype = '$(channel)'
94+
$log = "$(Build.ArtifactStagingDirectory)\PackageInspectionResults.txt"
95+
$checksigning = ""
96+
if ('${{ parameters.SignOutput }}' -eq 'true')
97+
{
98+
$checksigning = "--checksigning"
99+
}
100+
101+
$testargs = "--packagepath=`"$path`" --buildtype=$buildtype --logfilepath=`"$log`" --windowssdkbindir=`"$WindowsSdkBinDir`" $checksigning"
102+
$cmd = "`"$(Build.SourcesDirectory)\BuildOutput\PackageInspectionTest\PackageInspectionTest.exe`" $testargs"
103+
Write-Host $cmd
104+
cmd /c $cmd
105+
106+
Write-Host "results " $LASTEXITCODE
107+
if ($LASTEXITCODE -ne 0)
108+
{
109+
# Only fail if we are not on the main branch
110+
if ('$(Build.SourceBranch)' -eq 'refs/heads/main')
111+
{
112+
Write-Host "##vso[task.complete result=SucceededWithIssues;]DONE"
113+
}
114+
else
115+
{
116+
Write-Host "##vso[task.complete result=Failed;]DONE"
117+
}
118+
}

build/WindowsAppSDK-Foundation-Nightly.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,17 @@ extends:
109109
SignOutput: ${{ parameters.SignOutput }}
110110
runStaticAnalysis : ${{ parameters.runStaticAnalysis }}
111111

112-
- template: AzurePipelinesTemplates\WindowsAppSDK-Test-Stage.yml@self
113-
114112
- template: AzurePipelinesTemplates\WindowsAppSDK-PackTransportPackage-Stage.yml@self
115113
parameters:
116114
SignOutput: ${{ parameters.SignOutput }}
117115
PublishPackage: true
118116

117+
- template: AzurePipelinesTemplates\WindowsAppSDK-StaticValidationTest-Stage.yml@self
118+
parameters:
119+
SignOutput: ${{ parameters.SignOutput }}
120+
121+
- template: AzurePipelinesTemplates\WindowsAppSDK-Test-Stage.yml@self
122+
119123
- template: AzurePipelinesTemplates\WindowsAppSDK-Publish-Stage.yml@self
120124
parameters:
121125
PublishToMaestro: ${{ parameters.PublishToMaestro }}

build/WindowsAppSDK-Foundation-Official.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,18 @@ extends:
9494
SignOutput: ${{ parameters.SignOutput }}
9595
runStaticAnalysis : ${{ parameters.runStaticAnalysis }}
9696

97-
- template: AzurePipelinesTemplates\WindowsAppSDK-Test-Stage.yml@self
98-
9997
- template: AzurePipelinesTemplates\WindowsAppSDK-PackTransportPackage-Stage.yml@self
10098
parameters:
10199
SignOutput: ${{ parameters.SignOutput }}
102100
PublishPackage: true
103101
IsOfficial: true
104102

103+
- template: AzurePipelinesTemplates\WindowsAppSDK-StaticValidationTest-Stage.yml@self
104+
parameters:
105+
SignOutput: ${{ parameters.SignOutput }}
106+
107+
- template: AzurePipelinesTemplates\WindowsAppSDK-Test-Stage.yml@self
108+
105109
- template: AzurePipelinesTemplates\WindowsAppSDK-Publish-Stage.yml@self
106110
parameters:
107111
PublishToMaestro: ${{ parameters.PublishToMaestro }}

build/WindowsAppSDK-Foundation-PR.yml

+5-2
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,13 @@ extends:
8686
SignOutput: false
8787
runStaticAnalysis : ${{ parameters.runStaticAnalysis }}
8888

89-
- template: AzurePipelinesTemplates\WindowsAppSDK-Test-Stage.yml@self
90-
9189
- template: AzurePipelinesTemplates\WindowsAppSDK-PackTransportPackage-Stage.yml@self
9290
parameters:
9391
SignOutput: false
9492
PublishPackage: false
9593

94+
- template: AzurePipelinesTemplates\WindowsAppSDK-StaticValidationTest-Stage.yml@self
95+
parameters:
96+
SignOutput: false
97+
98+
- template: AzurePipelinesTemplates\WindowsAppSDK-Test-Stage.yml@self
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright (c) Microsoft Corporation and Contributors.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Diagnostics;
7+
using System.Text;
8+
using System.Threading;
9+
10+
namespace StaticValidationCommon
11+
{
12+
public class CommandLineProcess : IDisposable
13+
{
14+
private static char[] lineSeparators = new char[] { '\n', '\r' };
15+
16+
private Process process = null;
17+
private object runLock = new object();
18+
19+
private TimeSpan timeout = TimeSpan.FromMinutes(3);
20+
private string[] standardOut;
21+
private string[] standardError;
22+
23+
private string rawOut;
24+
private int exitCode;
25+
26+
public string Command { get; set; }
27+
28+
public string Arguments { get; set; }
29+
30+
public string OutputAsString
31+
{
32+
get { return rawOut; }
33+
}
34+
public int ExitCode
35+
{
36+
get { return exitCode; }
37+
}
38+
39+
public string[] StandardOut
40+
{
41+
get { return standardOut; }
42+
}
43+
44+
public string[] StandardError
45+
{
46+
get { return standardError; }
47+
}
48+
49+
public CommandLineProcess(string command, string arguments)
50+
{
51+
this.Command = command;
52+
this.Arguments = arguments;
53+
}
54+
55+
public void StdOutputStreamThreadFunc()
56+
{
57+
string output = this.process.StandardOutput.ReadToEnd();
58+
if (!string.IsNullOrEmpty(output) && !string.IsNullOrEmpty(output.Trim()))
59+
{
60+
this.rawOut = output;
61+
this.standardOut = output.Split(CommandLineProcess.lineSeparators, StringSplitOptions.RemoveEmptyEntries);
62+
}
63+
}
64+
65+
public void StdErrorStreamThreadFunc()
66+
{
67+
string output = this.process.StandardError.ReadToEnd();
68+
if (!string.IsNullOrEmpty(output) && !string.IsNullOrEmpty(output.Trim()))
69+
{
70+
this.standardError = output.Split(CommandLineProcess.lineSeparators, StringSplitOptions.RemoveEmptyEntries);
71+
}
72+
}
73+
74+
void StartProcess()
75+
{
76+
this.process = new Process();
77+
this.process.StartInfo = new ProcessStartInfo(this.Command, this.Arguments);
78+
this.process.StartInfo.UseShellExecute = false;
79+
this.process.StartInfo.CreateNoWindow = true;
80+
this.process.StartInfo.RedirectStandardOutput = true;
81+
this.process.StartInfo.RedirectStandardError = true;
82+
this.process.Start();
83+
}
84+
85+
public bool Run()
86+
{
87+
Thread outputStreamThread = null;
88+
Thread errorStreamThread = null;
89+
var outputStreamTimeout = TimeSpan.FromSeconds(5);
90+
bool succeeded = false;
91+
92+
lock(this.runLock)
93+
{
94+
try
95+
{
96+
this.StartProcess();
97+
98+
outputStreamThread = new Thread(new ThreadStart(this.StdOutputStreamThreadFunc));
99+
outputStreamThread.Start();
100+
101+
errorStreamThread = new Thread(new ThreadStart(this.StdErrorStreamThreadFunc));
102+
errorStreamThread.Start();
103+
104+
if (this.process.WaitForExit((int)timeout.TotalMilliseconds))
105+
{
106+
exitCode = this.process.ExitCode;
107+
if (this.process.HasExited && this.process.ExitCode == 0)
108+
{
109+
succeeded = true;
110+
}
111+
}
112+
}
113+
finally
114+
{
115+
if (null != outputStreamThread)
116+
{
117+
outputStreamThread.Join(outputStreamTimeout);
118+
}
119+
if (null != errorStreamThread)
120+
{
121+
errorStreamThread.Join(outputStreamTimeout);
122+
}
123+
}
124+
}
125+
return succeeded;
126+
}
127+
128+
public void Dispose()
129+
{
130+
if (process != null)
131+
{
132+
process.Dispose();
133+
process = null;
134+
}
135+
136+
GC.SuppressFinalize(this);
137+
}
138+
}
139+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
6+
<Platforms>AnyCPU;x64;x86</Platforms>
7+
<!-- For testing purposes -->
8+
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.WindowsAppSDK.Foundation.TransportPackage" Version="$(FoundationVersion)" GeneratePathProperty="true" />
13+
<PackageReference Include="CommandLineParser" Version="2.2.1" />
14+
</ItemGroup>
15+
16+
</Project>

0 commit comments

Comments
 (0)