diff --git a/NuGet.Config b/NuGet.Config
new file mode 100644
index 0000000..06b68ea
--- /dev/null
+++ b/NuGet.Config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.proj b/build.proj
deleted file mode 100644
index 9c7399a..0000000
--- a/build.proj
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
-
- Release
- $(MSBuildProjectDirectory)\out
-
- false
- Configuration=$(Configuration);PackageOutputPath=$(PackageOutputPath);GitSkipCache=true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/build/CredScanSuppressions.json b/build/CredScanSuppressions.json
new file mode 100644
index 0000000..0ffa6c2
--- /dev/null
+++ b/build/CredScanSuppressions.json
@@ -0,0 +1,9 @@
+{
+ "tool": "Credential Scanner",
+ "suppressions": [
+ {
+ "file": "src\\IntegrationTests\\AuthenticationSpec.cs",
+ "_justification": "Dummy credentials for testing purposes"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/build/PoliCheckExclusions.xml b/build/PoliCheckExclusions.xml
new file mode 100644
index 0000000..dba1ad4
--- /dev/null
+++ b/build/PoliCheckExclusions.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/build/stages/build.yml b/build/stages/build.yml
new file mode 100644
index 0000000..0196d91
--- /dev/null
+++ b/build/stages/build.yml
@@ -0,0 +1,124 @@
+# Build Stage
+
+stages:
+- stage: Build
+ jobs:
+ - job: Windows
+ timeoutInMinutes: 10
+ pool:
+ name: $(WindowsPoolName)
+
+ steps:
+ - checkout: self
+ clean: true
+
+ - task: UseDotNet@2
+ displayName: 'Use .Net Core SDK $(DotNetCoreVersion)'
+ inputs:
+ version: '$(DotNetCoreVersion)'
+ condition: always()
+
+ - script: 'mkdir "$(Build.ArtifactStagingDirectory)\binlogs"'
+ displayName: 'Create Logs Dir'
+ condition: always()
+
+ # Ensure we clear bot-provided feeds, for reliability
+ - powershell: |
+ $configPath = "$(Build.SourcesDirectory)\NuGet.Config"
+ [xml]$config = get-content $configPath
+ $config.configuration.packageSources.PrependChild($config.CreateElement("clear"))
+ $config.Save($configPath)
+ displayName: 'Ensure Clean NuGet Sources'
+ condition: always()
+
+ - task: NuGetCommand@2
+ displayName: 'Restore Packages'
+ inputs:
+ restoreSolution: '$(Build.SourcesDirectory)/src/Hermes.sln'
+ feedsToUse: config
+ nugetConfigPath: '$(Build.SourcesDirectory)/NuGet.Config'
+ condition: always()
+
+ - task: MSBuild@1
+ displayName: 'Build Solution'
+ inputs:
+ solution: '$(Build.SourcesDirectory)/src/Hermes.sln'
+ msbuildArguments: /t:Build /noautoresponse /bl:"$(Build.ArtifactStagingDirectory)\binlogs\build.binlog"
+ condition: always()
+
+ - task: PublishBuildArtifacts@1
+ displayName: 'Publish Artifact: packages'
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\pack'
+ ArtifactName: packages
+ continueOnError: true
+ condition: always()
+
+ - task: PublishBuildArtifacts@1
+ displayName: 'Publish Artifact: unit-tests'
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\src\Tests\bin\$(Configuration)'
+ ArtifactName: unit-tests
+ continueOnError: true
+ condition: always()
+
+ - task: PublishBuildArtifacts@1
+ displayName: 'Publish Artifact: integration-tests'
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)\src\IntegrationTests\bin\$(Configuration)'
+ ArtifactName: integration-tests
+ continueOnError: true
+ condition: always()
+
+ - task: PublishBuildArtifacts@1
+ displayName: 'Publish Artifact: logs'
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)\binlogs'
+ ArtifactName: logs
+ continueOnError: true
+ condition: always()
+
+ - task: CopyFiles@2
+ displayName: 'Copy Symbols'
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)/src/Server/bin/$(Configuration)'
+ Contents: |
+ **/System.Net.Mqtt.?(dll|pdb)
+ **/System.Net.Mqtt.Server.?(dll|pdb)
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/Symbols'
+ CleanTargetFolder: true
+ FlattenFolders: true
+ OverWrite: true # Check if we should copy to $(TargetFramework) subfolders instead
+ condition: always()
+
+ - task: PublishBuildArtifacts@1
+ displayName: 'Publish Artifact: symbols'
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/Symbols'
+ ArtifactName: symbols
+ condition: always()
+
+ - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
+ displayName: 'Component Governance'
+ condition: and(succeeded(), eq(variables['Build.SourceBranch'], variables['MainBranch']))
+
+ - powershell: |
+ $complianceEnabled = if ($env:COMPLIANCEENABLED) { $env:COMPLIANCEENABLED } else { '' }
+
+ if ($complianceEnabled -eq '') {
+ $branch = '$(Build.SourceBranch)'
+ $reason = '$(Build.Reason)'
+
+ if($branch -eq '$(MainBranch)' -or $reason -eq 'PullRequest') {
+ $complianceEnabled = 'true'
+ } else {
+ $complianceEnabled = 'false'
+ }
+ }
+
+ Write-Host "Source Branch: $branch, Build Reason: $reason"
+ Write-Host "Requires Compliance Stage: $complianceEnabled"
+ Write-Host "##vso[task.setvariable variable=Xamarin.ComplianceEnabled;isOutput=true]$complianceEnabled"
+ name: 'SetComplianceNeed'
+ displayName: 'Evaluate Compliance Need'
+ condition: always()
diff --git a/build/stages/compliance.yml b/build/stages/compliance.yml
new file mode 100644
index 0000000..6b9041b
--- /dev/null
+++ b/build/stages/compliance.yml
@@ -0,0 +1,101 @@
+# Compliance Stage
+
+stages:
+- stage : Compliance
+ dependsOn: Build
+ condition: eq(stageDependencies.Build.outputs['Windows.SetComplianceNeed.Xamarin.ComplianceEnabled'], 'true')
+ jobs:
+ - job: CodeAnalysis
+ displayName: Security & Analysis
+ pool: $(WindowsPoolName)
+ timeoutInMinutes: 60
+ cancelTimeoutInMinutes: 5
+ steps:
+ - checkout: self
+ clean: true
+ submodules: recursive
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Symbols
+ inputs:
+ artifactName: symbols
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+ - task: AntiMalware@3
+ displayName: Run AntiMalware Scan
+ inputs:
+ FileDirPath: $(System.DefaultWorkingDirectory)
+ EnableServices: true
+ continueOnError: true
+ condition: succeededOrFailed()
+ - task: BinSkim@3
+ displayName: Run BinSkim Analysis
+ inputs:
+ InputType: Basic
+ AnalyzeTarget: '$(Build.ArtifactStagingDirectory)\Symbols\*.dll'
+ AnalyzeVerbose: true
+ continueOnError: true
+ condition: succeededOrFailed()
+ - template: security\credscan\v2.yml@templates # from xamarin/yaml-templates repository
+ parameters:
+ suppressionsFile: $(System.DefaultWorkingDirectory)\build\CredScanSuppressions.json
+ - template: security\policheck\v1.yml@templates # from xamarin/yaml-templates repository
+ parameters:
+ exclusionFile: $(System.DefaultWorkingDirectory)\build\PoliCheckExclusions.xml
+ - task: CodeInspector@2
+ displayName: Run Code Inspector Analysis
+ inputs:
+ ProductId: '$(System.TeamProjectId)'
+ continueOnError: true
+ condition: succeededOrFailed()
+ - task: SdtReport@1
+ displayName: Create Security Analysis Report
+ inputs:
+ AntiMalware: true
+ BinSkim: true
+ CredScan: true
+ RoslynAnalyzers: true
+ PoliCheck: true
+ CodeInspector: true
+ continueOnError: true
+ condition: succeededOrFailed()
+ - task: PublishSecurityAnalysisLogs@2
+ displayName: Publish Security Analysis Logs
+ inputs:
+ ArtifactName: ComplianceLogs
+ continueOnError: true
+ condition: succeededOrFailed()
+ - task: PostAnalysis@1
+ displayName: Run Security Post Analysis
+ inputs:
+ AntiMalware: true
+ BinSkim: true
+ CredScan: true
+ RoslynAnalyzers: true
+ PoliCheck: true
+ CodeInspector: true
+ continueOnError: true
+ condition: succeededOrFailed()
+ - task: TSAUpload@1
+ inputs:
+ tsaVersion: 'TsaV2'
+ codebase: 'NewOrUpdate'
+ tsaEnvironment: 'PROD'
+ codeBaseName: 'mqtt_main'
+ notificationAlias: 'xvs@microsoft.com,maagno@microsoft.com'
+ notifyAlwaysV2: false
+ codeBaseAdmins: 'REDMOND\maagno;REDMOND\vsengxamarin'
+ instanceUrlForTsaV2: 'DEVDIV'
+ projectNameDEVDIV: 'DevDiv'
+ areaPath: 'DevDiv\Xamarin Tools\XamarinVS\XMA'
+ iterationPath: 'DevDiv\OneVS'
+ uploadAPIScan: true
+ uploadBinSkim: true
+ uploadCredScan: true
+ uploadFortifySCA: true
+ uploadFxCop: true
+ uploadModernCop: true
+ uploadPoliCheck: true
+ uploadPREfast: true
+ uploadRoslyn: true
+ uploadTSLint: true
+ uploadAsync: true
+ condition: succeededOrFailed()
diff --git a/build/stages/push.yml b/build/stages/push.yml
new file mode 100644
index 0000000..5f27313
--- /dev/null
+++ b/build/stages/push.yml
@@ -0,0 +1,37 @@
+# Upload Stage
+
+stages:
+- stage : Package
+ dependsOn:
+ - Test
+ - Compliance
+ condition: and(succeeded(), eq(variables['Build.SourceBranch'], variables['MainBranch']))
+ jobs:
+ - job: Push
+ displayName: Pack & Push
+ timeoutInMinutes: 10
+ pool:
+ name: $(WindowsPoolName)
+ steps:
+ - checkout: self
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Packages
+ inputs:
+ artifactName: packages
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+
+ - task: NuGetCommand@2
+ displayName: 'NuGet Update'
+ inputs:
+ command: custom
+ arguments: 'update -self'
+
+ - task: NuGetCommand@2
+ displayName: Push Packages
+ continueOnError: true
+ inputs:
+ command: push
+ packagesToPush: '$(Build.ArtifactStagingDirectory)/packages/*.nupkg'
+ nuGetFeedType: external
+ publishFeedCredentials: '$(PackagesFeedCredentials)'
diff --git a/build/stages/test.yml b/build/stages/test.yml
new file mode 100644
index 0000000..69fe0a7
--- /dev/null
+++ b/build/stages/test.yml
@@ -0,0 +1,57 @@
+# Test Stage
+
+stages:
+- stage: Test
+ dependsOn: Build
+ jobs:
+ - job: Unit
+ timeoutInMinutes: 10
+ pool:
+ name: $(WindowsPoolName)
+
+ steps:
+ - checkout: none
+
+ - task: DownloadBuildArtifacts@0
+ inputs:
+ artifactName: unit-tests
+
+ - task: VSTest@2
+ displayName: 'Unit Tests'
+ timeoutInMinutes: 10
+ inputs:
+ testSelector: 'testAssemblies'
+ testAssemblyVer2: |
+ **\Tests.dll
+ searchFolder: '$(Build.ArtifactStagingDirectory)\unit-tests'
+ testFiltercriteria: 'Flaky!=true'
+ codeCoverageEnabled: true
+ runInParallel: true
+ rerunFailedTests: true
+ rerunMaxAttempts: 5
+
+ - job: Integration
+ timeoutInMinutes: 10
+ pool:
+ name: $(WindowsPoolName)
+
+ steps:
+ - checkout: none
+
+ - task: DownloadBuildArtifacts@0
+ inputs:
+ artifactName: integration-tests
+
+ - task: VSTest@2
+ displayName: 'Integration Tests'
+ timeoutInMinutes: 10
+ inputs:
+ testSelector: 'testAssemblies'
+ testAssemblyVer2: |
+ **\IntegrationTests.dll
+ searchFolder: '$(Build.ArtifactStagingDirectory)\integration-tests'
+ codeCoverageEnabled: false
+ diagnosticsEnabled: false
+ runInParallel: false
+ rerunFailedTests: true
+ rerunMaxAttempts: 5
\ No newline at end of file
diff --git a/build/variables.yml b/build/variables.yml
new file mode 100644
index 0000000..0c8cdd0
--- /dev/null
+++ b/build/variables.yml
@@ -0,0 +1,21 @@
+# Common Variables
+
+variables:
+- group: Xamarin Release
+- group: Xamarin Signing
+- group: Xamarin Notarization
+- group: Xamarin-Secrets
+- group: xamops-azdev-secrets
+- group: akaxvs-secrets
+- name: MSBUILDDISABLENODEREUSE
+ value: 1
+- name: VSS_NUGET_EXTERNAL_FEED_ENDPOINTS
+ value: $(ExternalFeedEndpoints)
+- name: DotNetCoreVersion
+ value: '3.1.102'
+- name: WindowsPoolName
+ value: $(PoolName)
+- name: Configuration
+ value: Release
+- name: MainBranch
+ value: refs/heads/main
diff --git a/pipeline.yml b/pipeline.yml
new file mode 100644
index 0000000..059153d
--- /dev/null
+++ b/pipeline.yml
@@ -0,0 +1,24 @@
+resources:
+ repositories:
+ - repository: templates
+ type: github
+ name: xamarin/yaml-templates
+ ref: refs/heads/main
+ endpoint: xamarin
+
+trigger:
+ batch: false
+ branches:
+ include:
+ - main
+pr:
+ - main
+
+variables:
+- template: build/variables.yml
+
+stages:
+- template: build/stages/build.yml
+- template: build/stages/compliance.yml
+- template: build/stages/test.yml
+- template: build/stages/push.yml
diff --git a/src/Client/Client.csproj b/src/Client/Client.csproj
index b1bc6ab..de0151b 100644
--- a/src/Client/Client.csproj
+++ b/src/Client/Client.csproj
@@ -1,14 +1,13 @@
-
-
+
net46;netstandard2.0
- true
-
System.Net.Mqtt
System.Net.Mqtt
- $(AssemblyName)
$(IntermediateOutputPath)\$(TargetFramework)\$(AssemblyName).xml
+
+
+ $(AssemblyName)
A lightweight and simple MQTT client implementation written entirely in C#.
@@ -26,5 +25,4 @@
Resources.Designer.cs
-
\ No newline at end of file
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 77ead03..c3f691c 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -5,7 +5,7 @@
System.Net.Mqtt
-
+
Microsoft
true
https://raw.githubusercontent.com/xamarin/mqtt/main/LICENSE
@@ -14,13 +14,16 @@
© Microsoft Corporation. All rights reserved.
m2m iot sockets mqtt
+ true
+ $(MSBuildThisFileDirectory)..\pack
+
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+ false
+ true
-
true
$(MSBuildThisFileDirectory)Hermes.snk
-
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index 371faa9..7892e04 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -7,6 +7,7 @@
+
diff --git a/src/Server/Server.csproj b/src/Server/Server.csproj
index ee7c6b6..c6483cc 100644
--- a/src/Server/Server.csproj
+++ b/src/Server/Server.csproj
@@ -1,14 +1,13 @@
-
net46;netstandard2.0
- true
-
System.Net.Mqtt.Server
System.Net.Mqtt.Server
- $(AssemblyName)
$(IntermediateOutputPath)\$(TargetFramework)\$(AssemblyName).xml
+
+
+ $(AssemblyName)
A lightweight and simple MQTT Server implementation written entirely in C#.
@@ -22,5 +21,4 @@
Resources.Designer.cs
-
\ No newline at end of file