diff --git a/eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml b/eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml index 2d1168cc1ea4..3e702056f79e 100644 --- a/eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +++ b/eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml @@ -42,12 +42,12 @@ stages: - template: ../steps/create-go-workspace.yml - template: ../steps/set-scope.yml - parameters: + parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GoWorkspace: $(GO_WORKSPACE_PATH) - - template: ../steps/build.yml - parameters: + - template: ../steps/build-test.yml + parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GoWorkspace: $(GO_WORKSPACE_PATH) Scope: $(SCOPE) @@ -70,18 +70,18 @@ stages: - template: ../steps/create-go-workspace.yml - template: ../steps/set-scope.yml - parameters: + parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GoWorkspace: $(GO_WORKSPACE_PATH) - template: ../steps/analyze.yml - parameters: + parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GoWorkspace: $(GO_WORKSPACE_PATH) Scope: $(SCOPE) LintVersion: $(GoLintCLIVersion) -# Below stage won't work until the release stage is added/necessary. +# Below stage won't work until the release stage is added/necessary. # "Releasing" is just the package in the repository on github, but there may be some other metadata related # tasks that become necessary later on. diff --git a/eng/pipelines/templates/jobs/archetype-sdk-client.yml b/eng/pipelines/templates/jobs/archetype-sdk-client.yml index cc980b20f6fd..609be1d1463d 100644 --- a/eng/pipelines/templates/jobs/archetype-sdk-client.yml +++ b/eng/pipelines/templates/jobs/archetype-sdk-client.yml @@ -1,5 +1,6 @@ parameters: ServiceDirectory: '' + RunTests: false stages: - stage: Build @@ -42,17 +43,18 @@ stages: - template: ../steps/create-go-workspace.yml - template: ../steps/set-scope.yml - parameters: + parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GoWorkspace: $(GO_WORKSPACE_PATH) - template: ../steps/build-test.yml - parameters: + parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GoWorkspace: $(GO_WORKSPACE_PATH) Scope: $(SCOPE) Image: $(vm.image) GoVersion: $(go.version) + RunTests: ${{ parameters.RunTests }} - job: Analyze displayName: Analyze @@ -70,18 +72,18 @@ stages: - template: ../steps/create-go-workspace.yml - template: ../steps/set-scope.yml - parameters: + parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GoWorkspace: $(GO_WORKSPACE_PATH) - template: ../steps/analyze.yml - parameters: + parameters: ServiceDirectory: ${{ parameters.ServiceDirectory }} GoWorkspace: $(GO_WORKSPACE_PATH) Scope: $(SCOPE) LintVersion: $(GoLintCLIVersion) -# Below stage won't work until the release stage is added/necessary. +# Below stage won't work until the release stage is added/necessary. # "Releasing" is just the package in the repository on github, but there may be some other metadata related # tasks that become necessary later on. diff --git a/eng/pipelines/templates/steps/analyze.yml b/eng/pipelines/templates/steps/analyze.yml index e4f87d56d82f..0ba99d33c9c9 100644 --- a/eng/pipelines/templates/steps/analyze.yml +++ b/eng/pipelines/templates/steps/analyze.yml @@ -37,9 +37,9 @@ steps: failOnStderr: true workingDirectory: 'sdk/${{parameters.ServiceDirectory}}' - - script: | - echo check source file formatting in $(pwd) - gofmt -s -l -d $(find . -name '*.go' -print) >&2 + - pwsh: | + Write-Host "##[command]Check source file formatting in $(pwd)" + gofmt -s -l -d . displayName: 'Format Check' condition: succeededOrFailed() failOnStderr: true diff --git a/eng/pipelines/templates/steps/build-test.yml b/eng/pipelines/templates/steps/build-test.yml index 9d2b6112c9c3..3182b3ca10b0 100644 --- a/eng/pipelines/templates/steps/build-test.yml +++ b/eng/pipelines/templates/steps/build-test.yml @@ -4,86 +4,76 @@ parameters: Scope: 'sdk/...' Image: '' GoVersion: '' + RunTests: false steps: - - pwsh: | - go get github.com/jstemmer/go-junit-report - go get github.com/axw/gocov/gocov - go get github.com/AlekSi/gocov-xml - go get github.com/matm/gocov-html - go get -u github.com/wadey/gocovmerge - displayName: "Install Coverage and Junit Dependencies" - workingDirectory: '${{parameters.GoWorkspace}}' - - - pwsh: | - $modDirs = (./eng/scripts/get_module_dirs.ps1 -serviceDir $(SCOPE)) - foreach ($md in $modDirs) { - pushd $md - Write-Host "##[command]Executing go build -v ./... in $md" - go build -v ./... - } + - pwsh: ./eng/scripts/build.ps1 displayName: 'Build' workingDirectory: '${{parameters.GoWorkspace}}' env: GO111MODULE: 'on' - - pwsh: | - $modDirs = (./eng/scripts/get_module_dirs.ps1 -serviceDir $(SCOPE)) - foreach ($md in $modDirs) { - pushd $md - Write-Host "##[command]Executing go vet ./... in $md" - go vet ./... - } + - pwsh: ./eng/scripts/build.ps1 -vet -skipBuild displayName: 'Vet' workingDirectory: '${{parameters.GoWorkspace}}' env: GO111MODULE: 'on' - - pwsh: | - $testDirs = (./eng/scripts/get_test_dirs.ps1 -serviceDir $(SCOPE)) - foreach ($td in $testDirs) { - pushd $td - Write-Host "##[command]Executing go test -run "^Test" -race -v -coverprofile coverage.txt -covermode atomic $td | go-junit-report -set-exit-code > report.xml" - go test -run "^Test" -race -v -coverprofile coverage.txt -covermode atomic . | go-junit-report -set-exit-code > report.xml - # if no tests were actually run (e.g. examples) delete the coverage file so it's omitted from the coverage report - if (Select-String -path ./report.xml -pattern '' -simplematch -quiet) { - Write-Host "##[command]Deleting empty coverage file" - rm coverage.txt + - ${{ if eq(parameters.RunTests, 'true') }}: + - pwsh: | + go get github.com/jstemmer/go-junit-report + go get github.com/axw/gocov/gocov + go get github.com/AlekSi/gocov-xml + go get github.com/matm/gocov-html + go get -u github.com/wadey/gocovmerge + displayName: "Install Coverage and Junit Dependencies" + workingDirectory: '${{parameters.GoWorkspace}}' + + - pwsh: | + $testDirs = (./eng/scripts/get_test_dirs.ps1 -serviceDir $(SCOPE)) + foreach ($td in $testDirs) { + pushd $td + Write-Host "##[command]Executing go test -run "^Test" -race -v -coverprofile coverage.txt -covermode atomic $td | go-junit-report -set-exit-code > report.xml" + go test -run "^Test" -race -v -coverprofile coverage.txt -covermode atomic . | go-junit-report -set-exit-code > report.xml + # if no tests were actually run (e.g. examples) delete the coverage file so it's omitted from the coverage report + if (Select-String -path ./report.xml -pattern '' -simplematch -quiet) { + Write-Host "##[command]Deleting empty coverage file" + rm coverage.txt + } } - } - displayName: 'Run Tests' - workingDirectory: '${{parameters.GoWorkspace}}' - env: - GO111MODULE: 'on' + displayName: 'Run Tests' + workingDirectory: '${{parameters.GoWorkspace}}' + env: + GO111MODULE: 'on' - - pwsh: | - $coverageFiles = [Collections.Generic.List[String]]@() - Get-Childitem -recurse -path $(SCOPE) -filter coverage.txt | foreach-object { - $covFile = $_.FullName - Write-Host "Adding $covFile to the list of code coverage files" - $coverageFiles.Add($covFile) - } - gocovmerge $coverageFiles > mergedCoverage.txt - gocov convert ./mergedCoverage.txt > ./coverage.json - # gocov converts rely on standard input - Get-Content ./coverage.json | gocov-xml > ./coverage.xml - Get-Content ./coverage.json | gocov-html > ./coverage.html - displayName: 'Generate Coverage XML' - workingDirectory: '${{parameters.GoWorkspace}}sdk' + - pwsh: | + $coverageFiles = [Collections.Generic.List[String]]@() + Get-Childitem -recurse -path $(SCOPE) -filter coverage.txt | foreach-object { + $covFile = $_.FullName + Write-Host "Adding $covFile to the list of code coverage files" + $coverageFiles.Add($covFile) + } + gocovmerge $coverageFiles > mergedCoverage.txt + gocov convert ./mergedCoverage.txt > ./coverage.json + # gocov converts rely on standard input + Get-Content ./coverage.json | gocov-xml > ./coverage.xml + Get-Content ./coverage.json | gocov-html > ./coverage.html + displayName: 'Generate Coverage XML' + workingDirectory: '${{parameters.GoWorkspace}}sdk' - - task: PublishTestResults@2 - condition: succeededOrFailed() - inputs: - testRunner: JUnit - testResultsFiles: '${{parameters.GoWorkspace}}sdk/**/report.xml' - testRunTitle: 'Go ${{ parameters.GoVersion }} on ${{ parameters.Image }}' - failTaskOnFailedTests: true + - task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + testRunner: JUnit + testResultsFiles: '${{parameters.GoWorkspace}}sdk/**/report.xml' + testRunTitle: 'Go ${{ parameters.GoVersion }} on ${{ parameters.Image }}' + failTaskOnFailedTests: true - - task: PublishCodeCoverageResults@1 - condition: succeededOrFailed() - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '${{parameters.GoWorkspace}}sdk/coverage.xml' - additionalCodeCoverageFiles: '${{parameters.GoWorkspace}}sdk/coverage.html' - failIfCoverageEmpty: true + - task: PublishCodeCoverageResults@1 + condition: succeededOrFailed() + inputs: + codeCoverageTool: Cobertura + summaryFileLocation: '${{parameters.GoWorkspace}}sdk/coverage.xml' + additionalCodeCoverageFiles: '${{parameters.GoWorkspace}}sdk/coverage.html' + failIfCoverageEmpty: true diff --git a/eng/pipelines/templates/steps/build.yml b/eng/pipelines/templates/steps/build.yml deleted file mode 100644 index 1d1fcf40e00c..000000000000 --- a/eng/pipelines/templates/steps/build.yml +++ /dev/null @@ -1,22 +0,0 @@ -# This builds only track 2 SDKs. See \azure-pipelines.yml for track 1. - -parameters: - ServiceDirectory: '' - GoWorkspace: '' - Scope: 'sdk/...' - Image: '' - GoVersion: '' - -steps: - - - pwsh: ./eng/scripts/build.ps1 - displayName: 'Build' - workingDirectory: '${{parameters.GoWorkspace}}' - env: - GO111MODULE: 'on' - - - pwsh: ./eng/scripts/build.ps1 -vet -skipBuild - displayName: 'Vet' - workingDirectory: '${{parameters.GoWorkspace}}' - env: - GO111MODULE: 'on' diff --git a/eng/scripts/build.ps1 b/eng/scripts/build.ps1 index 6b909c593505..163460f412a4 100644 --- a/eng/scripts/build.ps1 +++ b/eng/scripts/build.ps1 @@ -19,9 +19,9 @@ foreach ($sdk in (./eng/scripts/get_module_dirs.ps1 -serviceDir 'sdk/...')) { } $keys = $sdks.Keys | Sort-Object; -if (![string]::IsNullOrWhiteSpace($filter)) { +if (![string]::IsNullOrWhiteSpace($filter)) { Write-Host "Using filter: $filter" - $keys = $keys.Where( { $_ -match $filter }) + $keys = $keys.Where( { $_ -match $filter }) } $keys | ForEach-Object { $sdks[$_] } | ForEach-Object { diff --git a/eng/scripts/get_test_dirs.ps1 b/eng/scripts/get_test_dirs.ps1 index 07a46f047c8b..0ad6b8136616 100644 --- a/eng/scripts/get_test_dirs.ps1 +++ b/eng/scripts/get_test_dirs.ps1 @@ -7,9 +7,13 @@ $testDirs = [Collections.Generic.List[String]]@() # find each directory under $serviceDir that contains Go test files Get-Childitem -recurse -path $serviceDir -filter *_test.go | foreach-object { $cdir = $_.Directory - if (!$testDirs.Contains($cdir)) { - Write-Host "Adding $cdir to list of test directories" - $testDirs.Add($cdir) + $tests = Select-String -Path $_ 'Test' -AllMatches + + if ($tests.Count -gt 0) { + if (!$testDirs.Contains($cdir)) { + Write-Host "Adding $cdir to list of test directories" + $testDirs.Add($cdir) + } } } diff --git a/sdk/agfood/armagfood/ci.yml b/sdk/agfood/armagfood/ci.yml index 760bd529e50d..691a946e6c07 100644 --- a/sdk/agfood/armagfood/ci.yml +++ b/sdk/agfood/armagfood/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/agfood/armagfood/ stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'agfood/armagfood' diff --git a/sdk/agrifood/armagrifood/ci.yml b/sdk/agrifood/armagrifood/ci.yml index 3b1fda8a9cbd..77aa09520ef0 100644 --- a/sdk/agrifood/armagrifood/ci.yml +++ b/sdk/agrifood/armagrifood/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/agrifood/armagrifood stages: -- template: /eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'agrifood/armagrifood' diff --git a/sdk/authorization/armauthorization/ci.yml b/sdk/authorization/armauthorization/ci.yml index 605f490ff563..6aadcffe031c 100644 --- a/sdk/authorization/armauthorization/ci.yml +++ b/sdk/authorization/armauthorization/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/authorization/armauthorization stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'authorization/armauthorization' diff --git a/sdk/azcore/ci.yml b/sdk/azcore/ci.yml index d282266b3a1e..9ed5180726cb 100644 --- a/sdk/azcore/ci.yml +++ b/sdk/azcore/ci.yml @@ -8,9 +8,10 @@ pr: paths: include: - sdk/azcore/ - - + + stages: - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'azcore' + RunTests: true diff --git a/sdk/azidentity/ci.yml b/sdk/azidentity/ci.yml index e4496e8d0f38..5e5adcfd1511 100644 --- a/sdk/azidentity/ci.yml +++ b/sdk/azidentity/ci.yml @@ -13,3 +13,4 @@ stages: - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'azidentity' + RunTests: true diff --git a/sdk/compute/armcompute/ci.yml b/sdk/compute/armcompute/ci.yml index 04f7f82782a9..0d41291c2072 100644 --- a/sdk/compute/armcompute/ci.yml +++ b/sdk/compute/armcompute/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/compute/armcompute/ stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'compute/armcompute' diff --git a/sdk/containerregistry/armcontainerregistry/ci.yml b/sdk/containerregistry/armcontainerregistry/ci.yml index 8be8ad81a3fc..f4670ebf4109 100644 --- a/sdk/containerregistry/armcontainerregistry/ci.yml +++ b/sdk/containerregistry/armcontainerregistry/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/containerregistry/armcontainerregistry/ stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'containerregistry/armcontainerregistry' \ No newline at end of file diff --git a/sdk/containerservice/armcontainerservice/ci.yml b/sdk/containerservice/armcontainerservice/ci.yml index 0429d0e26b44..3fdd60cf0177 100644 --- a/sdk/containerservice/armcontainerservice/ci.yml +++ b/sdk/containerservice/armcontainerservice/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/containerservice/armcontainerservice stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'containerservice/armcontainerservice' diff --git a/sdk/keyvault/armkeyvault/ci.yml b/sdk/keyvault/armkeyvault/ci.yml index 845bc171bcf2..1a7ab4335350 100644 --- a/sdk/keyvault/armkeyvault/ci.yml +++ b/sdk/keyvault/armkeyvault/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/keyvault/armkeyvault stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'keyvault/armkeyvault' diff --git a/sdk/monitor/armmonitor/ci.yml b/sdk/monitor/armmonitor/ci.yml index 951eceb9ee5d..f6a51997e22c 100644 --- a/sdk/monitor/armmonitor/ci.yml +++ b/sdk/monitor/armmonitor/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/monitor/armmonitor stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'monitor/armmonitor' diff --git a/sdk/network/armnetwork/ci.yml b/sdk/network/armnetwork/ci.yml index 72ec4784aee3..31fb47aa984c 100644 --- a/sdk/network/armnetwork/ci.yml +++ b/sdk/network/armnetwork/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/network/armnetwork/ stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'network/armnetwork' diff --git a/sdk/privatedns/armprivatedns/ci.yml b/sdk/privatedns/armprivatedns/ci.yml index 578a671d1861..06d97401a0c1 100644 --- a/sdk/privatedns/armprivatedns/ci.yml +++ b/sdk/privatedns/armprivatedns/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/privatedns/armprivatedns stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'privatedns/armprivatedns' diff --git a/sdk/profiles/ci.yml b/sdk/profiles/ci.yml index 6921a0c413ea..c4ad86adf473 100644 --- a/sdk/profiles/ci.yml +++ b/sdk/profiles/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/profiles/ stages: -- template: ../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: - ServiceDirectory: 'sdk/profiles' + ServiceDirectory: 'profiles' diff --git a/sdk/resources/armresources/ci.yml b/sdk/resources/armresources/ci.yml index 1b893badf2ec..c6996fdf6249 100644 --- a/sdk/resources/armresources/ci.yml +++ b/sdk/resources/armresources/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/resources/armresources/ stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'resources/armresources' diff --git a/sdk/samples/azidentity/SDKV1Adapter/example_SDKV1_test.go b/sdk/samples/azidentity/SDKV1Adapter/example_SDKV1_test.go index fd1f0d40eea2..6c1e2e86d2db 100644 --- a/sdk/samples/azidentity/SDKV1Adapter/example_SDKV1_test.go +++ b/sdk/samples/azidentity/SDKV1Adapter/example_SDKV1_test.go @@ -33,10 +33,7 @@ var ( tenantID = os.Getenv("AZURE_TENANT_ID") ) -var ( - location = os.Getenv("AZURE_LOCATION") - userAgent = "azidentitysample" -) +var location = os.Getenv("AZURE_LOCATION") // ExampleNewDefaultAzureCredential for using the DefaultAzureCredential through the NewDefaultAzureCredentialAdapter and assigning the credential to the // SDK V1 authorizer. @@ -101,7 +98,10 @@ func ExampleNewClientSecretCredential() { } for list.NotDone() { fmt.Println(*list.Value().Name) - list.Next() + err = list.Next() + if err != nil { + panic(err.Error()) + } } // Output: // samplegroup diff --git a/sdk/samples/ci.yml b/sdk/samples/ci.yml index 4648930383eb..621e488d836d 100644 --- a/sdk/samples/ci.yml +++ b/sdk/samples/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/samples/ stages: -- template: ../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'samples' diff --git a/sdk/storage/armstorage/ci.yml b/sdk/storage/armstorage/ci.yml index 307eea0ed166..2be3a91b4f46 100644 --- a/sdk/storage/armstorage/ci.yml +++ b/sdk/storage/armstorage/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/storage/armstorage/ stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'storage/armstorage' diff --git a/sdk/synapse/azartifacts/ci.yml b/sdk/synapse/azartifacts/ci.yml index b1310415977a..467be0a35a07 100644 --- a/sdk/synapse/azartifacts/ci.yml +++ b/sdk/synapse/azartifacts/ci.yml @@ -8,9 +8,9 @@ pr: paths: include: - sdk/synapse/azartifacts/ - + stages: -- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: ../../../eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'synapse/azartifacts' diff --git a/sdk/web/armweb/ci.yml b/sdk/web/armweb/ci.yml index 8525bd2bfc28..debef9f72c33 100644 --- a/sdk/web/armweb/ci.yml +++ b/sdk/web/armweb/ci.yml @@ -10,6 +10,6 @@ pr: - sdk/web/armweb/ stages: -- template: /eng/pipelines/templates/jobs/archetype-sdk-client-samples.yml +- template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml parameters: ServiceDirectory: 'web/armweb'