Add source code archival pipeline

This commit is contained in:
Andrew Arnott 2022-09-16 20:37:29 -06:00
Родитель 990e1fddf7
Коммит 6f6af479ce
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: F33A420C60ED9C6F
6 изменённых файлов: 274 добавлений и 2 удалений

Просмотреть файл

@ -39,6 +39,7 @@ Further customize your repo by:
1. Verify the license is suitable for your goal as it appears in the LICENSE and stylecop.json files and the Directory.Build.props file's `PackageLicenseExpression` property.
1. Reset or replace the badges at the top of this file.
1. Check and maybe change any variable groups referenced in the .yml files. Search for `- group:` to find them.
### Maintaining your repo based on this template

Просмотреть файл

@ -0,0 +1,220 @@
#Requires -PSEdition Core -Version 7
<#
.SYNOPSIS
Submits a source archival request for this repo.
.PARAMETER Requester
The alias for the user requesting this backup.
.PARAMETER ManagerAlias
The alias of the manager that owns the repo.
.PARAMETER TeamAlias
The alias of the team that owns the repo.
.PARAMETER BusinessGroupName
A human-readable title for your team or business group.
.PARAMETER ProductionType
.PARAMETER ReleaseType
The type of release being backed up.
.PARAMETER ReleaseDate
The date of the release of your software. Defaults to today.
.PARAMETER OwnerAlias
The alias of the owner.
.PARAMETER OS
.PARAMETER ProductLanguage
One or more languages.
.PARAMETER Notes
Any notes to record with the backup.
.PARAMETER FileCollection
One or more collections to archive.
.PARAMETER ProductName
The name of the product. This will default to the repository name.
.PARAMETER RepoUrl
The URL to the repository. This will default to the repository containing this script.
.PARAMETER BackupType
The kind of backup to be performed.
.PARAMETER ServerPath
The UNC path to the server to be backed up (if applicable).
.PARAMETER SourceCodeArchivalUri
The URI to POST the source code archival request to.
This value will typically come automatically by a variable group associated with your pipeline.
You can also look it up at https://dpsrequestforms.azurewebsites.net/#/help -> SCA Request Help -> SCA API Help -> Description
#>
[CmdletBinding(SupportsShouldProcess = $true, PositionalBinding = $false)]
param (
[Parameter()]
[string]$Requester,
[Parameter(Mandatory = $true)]
[string]$ManagerAlias,
[Parameter(Mandatory = $true)]
[string]$TeamAlias,
[Parameter(Mandatory = $true)]
[string]$BusinessGroupName,
[Parameter()]
[string]$ProductionType = 'Visual Studio',
[Parameter()]
[string]$ReleaseType = 'RTW',
[Parameter()]
[DateTime]$ReleaseDate = [DateTime]::Today,
[Parameter()]
[string]$OwnerAlias,
[Parameter()]
[ValidateSet('64-Bit Win', '32-Bit Win', 'Linux', 'Mac', '64-Bit ARM', '32-Bit ARM')]
[string[]]$OS = @('64-Bit Win'),
[Parameter(Mandatory = $true)]
[ValidateSet('English', 'Chinese Simplified', 'Chinese Traditional', 'Czech', 'French', 'German', 'Italian', 'Japanese', 'Korean', 'Polish', 'Portuguese', 'Russian', 'Spanish', 'Turkish')]
[string[]]$ProductLanguage,
[Parameter()]
[string]$Notes = '',
[Parameter()]
[ValidateSet('Binaries', 'Localization', 'Source Code')]
[string[]]$FileCollection = @('Source Code'),
[Parameter()]
[string]$ProductName,
[Parameter()]
[Uri]$RepoUrl,
[Parameter()]
[ValidateSet('Server Path', 'Code Repo(Git URL/AzureDevOps)', 'Git', 'Azure Storage Account')]
[string]$BackupType = 'Code Repo(Git URL/AzureDevOps)',
[Parameter()]
[string]$ServerPath = '',
[Parameter()]
[Uri]$SourceCodeArchivalUri = $env:SOURCECODEARCHIVALURI
)
function Invoke-Git() {
# Make sure we invoke git from within the repo.
Push-Location $PSScriptRoot
try {
return (git $args)
}
finally {
Pop-Location
}
}
if (!$ProductName) {
if ($env:BUILD_REPOSITORY_NAME) {
Write-Verbose 'Using $env:BUILD_REPOSITORY_NAME for ProductName.' # single quotes are intentional so user sees the name of env var.
$ProductName = $env:BUILD_REPOSITORY_NAME
}
else {
$originUrl = [Uri](Invoke-Git remote get-url origin)
if ($originUrl) {
$lastPathSegment = $originUrl.Segments[$originUrl.Segments.Length - 1]
if ($lastPathSegment.EndsWith('.git')) {
$lastPathSegment = $lastPathSegment.Substring(0, $lastPathSegment.Length - '.git'.Length)
}
Write-Verbose 'Using origin remote URL to derive ProductName.'
$ProductName = $lastPathSegment
}
}
if (!$ProductName) {
Write-Error "Unable to determine default value for -ProductName."
}
}
if (!$OwnerAlias) {
if ($env:BUILD_REQUESTEDFOREMAIL) {
Write-Verbose 'Using $env:BUILD_REQUESTEDFOREMAIL and slicing to just the alias for OwnerAlias.'
$OwnerAlias = ($env:BUILD_REQUESTEDFOREMAIL -split '@')[0]
}
else {
Write-Verbose 'Using $env:USERNAME for OwnerAlias.'
$OwnerAlias = $env:USERNAME
}
if (!$OwnerAlias) {
Write-Error "Unable to determine default value for -OwnerAlias."
}
}
if (!$Requester) {
if ($env:BUILD_REQUESTEDFOREMAIL) {
Write-Verbose 'Using $env:BUILD_REQUESTEDFOREMAIL and slicing to just the alias for Requester.'
$Requester = ($env:BUILD_REQUESTEDFOREMAIL -split '@')[0]
}
else {
Write-Verbose 'Using $env:USERNAME for Requester.'
$Requester = $env:USERNAME
}
if (!$Requester) {
Write-Error "Unable to determine default value for -Requester."
}
}
if (!$RepoUrl) {
$RepoUrl = $env:BUILD_REPOSITORY_URI
if (!$RepoUrl) {
$originUrl = [Uri](Invoke-Git remote get-url origin)
if ($originUrl) {
Write-Verbose 'Using git origin remote url for GitURL.'
$RepoUrl = $originUrl
}
if (!$RepoUrl) {
Write-Error "Unable to determine default value for -RepoUrl."
}
}
}
Push-Location $PSScriptRoot
$versionsObj = & (& "$PSScriptRoot/Get-nbgv.ps1") get-version -f json | ConvertFrom-Json
Pop-Location
$ReleaseDateString = $ReleaseDate.ToShortDateString()
$Version = $versionsObj.Version
$BackupSize = Get-ChildItem $PSScriptRoot\..\.git -Recurse -File | Measure-Object -Property Length -Sum
$DataSizeMB = [int]($BackupSize.Sum / 1mb)
$FileCount = $BackupSize.Count
$Request = @{
"Requester" = $Requester
"Manager" = $ManagerAlias
"TeamAlias" = $TeamAlias
"AdditionalContacts" = $AdditionalContacts
"BusinessGroupName" = $BusinessGroupName
"ProductName" = $ProductName
"Version" = $Version
"ProductionType" = $ProductionType
"ReleaseType" = $ReleaseType
"ReleaseDateString" = $ReleaseDateString
"OS" = [string]::Join(',', $OS)
"ProductLanguage" = [string]::Join(',', $ProductLanguage)
"FileCollection" = [string]::Join(',', $FileCollection)
"OwnerAlias" = $OwnerAlias
"Notes" = $Notes
"CustomerProvidedDataSizeMB" = $DataSizeMB
"CustomerProvidedFileCount" = $FileCount
"BackupType" = $BackupType
"ServerPath" = $ServerPath
"AzureStorageAccount" = $AzureStorageAccount
"AzureStorageContainer" = $AzureStorageContainer
"GitURL" = $RepoUrl
}
$RequestJson = ConvertTo-Json $Request
Write-Host "SCA request:`n$RequestJson"
if ($PSCmdlet.ShouldProcess('source archival request', 'post')) {
if (!$SourceCodeArchivalUri) {
Write-Error "Unable to post request without -SourceCodeArchivalUri parameter."
exit 1
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$Response = Invoke-WebRequest -Uri $SourceCodeArchivalUri -Method POST -Body $RequestJson -ContentType "application/json" -UseBasicParsing -SkipHttpErrorCheck
Write-Host "Status Code : " -NoNewline
$responseContent = ConvertFrom-Json ($Response.Content)
if ($Response.StatusCode -eq 200) {
Write-Host $Response.StatusCode -ForegroundColor Green
Write-Host "Ticket ID : " -NoNewline
Write-Host $responseContent
}
else {
$responseContent = ConvertFrom-Json $Response.Content
Write-Host $Response.StatusCode -ForegroundColor Red
Write-Host "Message : $($responseContent.message)"
}
} elseif ($SourceCodeArchivalUri) {
Write-Host "Would have posted to $SourceCodeArchivalUri"
}

Просмотреть файл

@ -0,0 +1,50 @@
trigger: none # We only want to trigger manually or based on resources
pr: none
# Source archival requirements come from a compliance tenet. Review a sample task here: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1550985
# Source code should be archived within 30 days of the release date, and at least every quarter if your product is releasing more than once every 6 months.
# If your sources on GitHub are public open source project, then using GitHub Public Archive is sufficient.
schedules:
- cron: "13 13 13 */3 *" # Every three months
displayName: Periodic source archival
branches:
include:
- main
parameters:
- name: notes
displayName: Notes to include in the SCA request
type: string
- name: whatif
displayName: Only simulate the request
type: boolean
variables:
- group: VS Core team # Expected to provide ManagerAlias, SourceCodeArchivalUri
pool:
name: AzurePipelines-EO
vmImage: AzurePipelinesUbuntu20.04compliant
steps:
- checkout: self
clean: true
fetchDepth: 0
- powershell: tools/Install-DotNetSdk.ps1
displayName: Install .NET SDK
- powershell: azure-pipelines/variables/_pipelines.ps1
failOnStderr: true
displayName: ⚙ Set pipeline variables based on source
- powershell: >
$TeamAlias = '$(TeamEmail)'.Substring(0, '$(TeamEmail)'.IndexOf('@'))
azure-pipelines/Archive-SourceCode.ps1
-ManagerAlias '$(ManagerAlias)'
-TeamAlias $TeamAlias
-BusinessGroupName '$(BusinessGroupName)'
-ProductName '$(SymbolsFeatureName)'
-ProductLanguage English
-Notes '${{ parameters.notes }}'
-Verbose
-WhatIf:$${{ parameters.whatif }}
displayName: Submit archival request

Просмотреть файл

@ -21,7 +21,7 @@ jobs:
variables:
- ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
# https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/25351/APIScan-step-by-step-guide-to-setting-up-a-Pipeline
- group: VSCloudServices-APIScan
- group: VSCloudServices-APIScan # Expected to provide ApiScanClientId, ApiScanSecret, ApiScanTenant
steps:
- checkout: self
fetchDepth: 0 # avoid shallow clone so nbgv can do its work.

Просмотреть файл

@ -10,7 +10,7 @@ resources:
- auto-release
variables:
- group: VS SDK feeds
- group: VS SDK feeds # Expected to provide NuGetOrgApiKey
jobs:
- job: release

Просмотреть файл

@ -0,0 +1 @@
'Visual Studio - VS Core'