diff --git a/tools/devops/automation/scripts/Governance.psm1 b/tools/devops/automation/scripts/Governance.psm1 new file mode 100644 index 000000000000..a0217266555f --- /dev/null +++ b/tools/devops/automation/scripts/Governance.psm1 @@ -0,0 +1,44 @@ +class APIScanConfiguration { + [string[]] $enabledPlatforms + + APIScanConfiguration ( + [string[]] $enabledPlatforms) { + $this.enabledPlatforms = $enabledPlatforms + } + + [string] Create() { + $vars = [ordered]@{} + Write-Host "enabledPlatforms: $($this.enabledPlatforms)" + + foreach ($platform in $this.enabledPlatforms) { + # dictionary with the secrets needed by each matrix + $platformVars = [ordered]@{ + CLIENT_ID = $Env:API_SCAN_CLIENT_ID; + TENANT = $Env:API_SCAN_TENANT; + SECRET = "`$(API_SCAN_SECRET_$($platform.ToUpper()))"; + PLATFORM = $platform.ToUpper(); + } + $vars[$platform] = $platformVars + } + + return $vars | ConvertTo-Json + } + +} + +function Get-APIScanConfiguration { + param + ( + [Parameter(Mandatory)] + [string] + [AllowEmptyString()] + $EnabledPlatforms + ) + + $arrEnabledPlatforms = -split $EnabledPlatforms + $config = [APIScanConfiguration]::new($arrEnabledPlatforms) + return $config.Create() +} + +# export public functions, other functions are private and should not be used outside the module. +Export-ModuleMember -Function Get-APIScanConfiguration diff --git a/tools/devops/automation/scripts/MaciosCI.psd1 b/tools/devops/automation/scripts/MaciosCI.psd1 index 3230cbc9eb27..8add509de46b 100644 --- a/tools/devops/automation/scripts/MaciosCI.psd1 +++ b/tools/devops/automation/scripts/MaciosCI.psd1 @@ -71,6 +71,7 @@ ScriptsToProcess = @( NestedModules = @( 'Artifacts.psm1', 'GitHub.psm1', + 'Governance.psm1', 'MLaunch.psm1', 'RemoteMac.psm1', 'StaticPages.psm1', diff --git a/tools/devops/automation/templates/common/configure.yml b/tools/devops/automation/templates/common/configure.yml index 4e8e45692f48..f0a065e80bfe 100644 --- a/tools/devops/automation/templates/common/configure.yml +++ b/tools/devops/automation/templates/common/configure.yml @@ -80,11 +80,22 @@ steps: $testMatrix = $testMatrix | ConvertFrom-Json | ConvertTo-Json -Compress Write-Host "##vso[task.setvariable variable=TEST_MATRIX;isOutput=true]$testMatrix" name: test_matrix - displayName: 'Create strategy matrix' + displayName: 'Create tests strategy matrix' env: TEST_CONFIGURATIONS: ${{ convertToJson(parameters.testConfigurations) }} SUPPORTED_PLATFORMS: ${{ convertToJson(parameters.supportedPlatforms) }} +- pwsh: | + Import-Module $Env:SYSTEM_DEFAULTWORKINGDIRECTORY/xamarin-macios/tools/devops/automation/scripts/MaciosCI.psd1 + gci env: | sort | format-table -autosize -wrap + $apiScanMatrix = Get-APIScanConfiguration -EnabledPlatforms "$Env:CONFIGURE_PLATFORMS_DOTNET_PLATFORMS" + # compress the json to remove any newlines, because we can't set the variable below if the json has any newlines + Write-Host "$apiScanMatrix" + $apiScanMatrix = $apiScanMatrix | ConvertFrom-Json | ConvertTo-Json -Compress + Write-Host "##vso[task.setvariable variable=APISCAN_MATRIX;isOutput=true]$apiScanMatrix" + name: apiscan_matrix + displayName: 'Create APIScan matrix' + # upload config to be consumed later - ${{ if eq(parameters.uploadArtifacts, true) }}: - task: PublishPipelineArtifact@1 diff --git a/tools/devops/automation/templates/governance/apiscan.yml b/tools/devops/automation/templates/governance/apiscan.yml new file mode 100644 index 000000000000..4d63ae2a1f4d --- /dev/null +++ b/tools/devops/automation/templates/governance/apiscan.yml @@ -0,0 +1,28 @@ +parameters: + +- name: isPR + type: boolean + +- name: repositoryAlias + type: string + default: self + +- name: commit + type: string + default: HEAD + +- name: uploadPrefix + type: string + default: '$(MaciosUploadPrefix)' + +steps: + +- template: ../common/checkout.yml + parameters: + isPR: ${{ parameters.isPR }} + repositoryAlias: ${{ parameters.repositoryAlias }} + commit: ${{ parameters.commit }} + +- pwsh: | + Write-Output "Performing APISCan for $(PLATFORM) using tenant $(TENANT) client id $(CLIENT_ID) and secret $(SECRET)." + displayName: "APISCan" diff --git a/tools/devops/automation/templates/governance-checks.yml b/tools/devops/automation/templates/governance/general.yml similarity index 98% rename from tools/devops/automation/templates/governance-checks.yml rename to tools/devops/automation/templates/governance/general.yml index cf968d7861b3..0740e1a6e28a 100644 --- a/tools/devops/automation/templates/governance-checks.yml +++ b/tools/devops/automation/templates/governance/general.yml @@ -17,7 +17,7 @@ parameters: steps: -- template: ./common/checkout.yml +- template: ../common/checkout.yml parameters: isPR: ${{ parameters.isPR }} repositoryAlias: ${{ parameters.repositoryAlias }} @@ -31,7 +31,6 @@ steps: Dir $(System.DefaultWorkingDirectory) displayName: Show directories - - powershell: | Get-ChildItem -Recurse -Path $(Build.SourcesDirectory)/maccore displayName: Show maccore content diff --git a/tools/devops/automation/templates/governance/stage.yml b/tools/devops/automation/templates/governance/stage.yml new file mode 100644 index 000000000000..3c6f7173d90f --- /dev/null +++ b/tools/devops/automation/templates/governance/stage.yml @@ -0,0 +1,69 @@ +# contains the stage used to run all governance related jobs + +parameters: +- name: isPR + type: boolean + +- name: repositoryAlias + type: string + default: self + +- name: commit + type: string + default: HEAD + +- name: stageDisplayNamePrefix + type: string + default: '' + + +stages: +- stage: governance_checks + displayName: '${{ parameters.stageDisplayNamePrefix }}Governance Checks' + dependsOn: [ configure_build ] + + jobs: + - job: apiscan + displayName: 'APIScan:' + pool: + vmImage: windows-latest + + + strategy: + matrix: $[ stageDependencies.configure_build.configure.outputs['apiscan_matrix.APISCAN_MATRIX'] ] + + steps: + - template: ./apiscan.yml + parameters: + isPR: ${{ parameters.isPR }} + repositoryAlias: ${{ parameters.repositoryAlias }} + commit: ${{ parameters.commit }} + + - job: general_governance + displayName: 'Governance Checks' + pool: + vmImage: windows-latest + + steps: + - template: ./general.yml + parameters: + isPR: ${{ parameters.isPR }} + repositoryAlias: ${{ parameters.repositoryAlias }} + commit: ${{ parameters.commit }} + + - job: tsa_upload + displayName: 'TSA Upload' + dependsOn: [ general_governance, apiscan ] + pool: + vmImage: windows-latest + + variables: + ${{ each p in parameters.platforms }}: + INCLUDE_DOTNET_${{ upper(p.key) }}: $[ stageDependencies.configure_build.configure.outputs['configure_platforms.INCLUDE_DOTNET_${{ upper(p.key)}}'] ] + + steps: + - template: ./tsa-upload.yml + parameters: + isPR: ${{ parameters.isPR }} + repositoryAlias: ${{ parameters.repositoryAlias }} + commit: ${{ parameters.commit }} diff --git a/tools/devops/automation/templates/governance/tsa-upload.yml b/tools/devops/automation/templates/governance/tsa-upload.yml new file mode 100644 index 000000000000..8d54e5bb6968 --- /dev/null +++ b/tools/devops/automation/templates/governance/tsa-upload.yml @@ -0,0 +1,28 @@ +parameters: + +- name: isPR + type: boolean + +- name: repositoryAlias + type: string + default: self + +- name: commit + type: string + default: HEAD + +- name: uploadPrefix + type: string + default: '$(MaciosUploadPrefix)' + +steps: + +- template: ../common/checkout.yml + parameters: + isPR: ${{ parameters.isPR }} + repositoryAlias: ${{ parameters.repositoryAlias }} + commit: ${{ parameters.commit }} + +- pwsh: | + Write-Output "Upload to tsa." + displayName: "Debug" diff --git a/tools/devops/automation/templates/main-stage.yml b/tools/devops/automation/templates/main-stage.yml index 511cc410b035..ca345f47cd88 100644 --- a/tools/devops/automation/templates/main-stage.yml +++ b/tools/devops/automation/templates/main-stage.yml @@ -277,23 +277,12 @@ parameters: stages: - ${{ if eq(parameters.runGovernanceTests, true) }}: - - stage: governance_checks - displayName: '${{ parameters.stageDisplayNamePrefix }}Governance Checks' - dependsOn: build_packages - ${{ if and(ne(parameters.dependsOn, ''), ne(parameters.dependsOnResult, '')) }}: - condition: eq(dependencies.${{ parameters.dependsOn }}.result, '${{ parameters.dependsOnResult }}') - jobs: - - job: governance - displayName: 'Governance Checks' - pool: - vmImage: windows-latest - steps: - - template: governance-checks.yml - parameters: - isPR: ${{ parameters.isPR }} - repositoryAlias: ${{ parameters.repositoryAlias }} - commit: ${{ parameters.commit }} - + - template: ./governance/stage.yml + parameters: + isPR: ${{ parameters.isPR }} + repositoryAlias: ${{ parameters.repositoryAlias }} + commit: ${{ parameters.commit }} + stageDisplayNamePrefix: ${{ parameters.stageDisplayNamePrefix }} - ${{ if parameters.isPR }}: - stage: clean