Sync eng/common directory with azure-sdk-tools repository (#97)

This commit is contained in:
Azure SDK Bot 2020-05-13 10:05:03 -07:00 коммит произвёл GitHub
Родитель 60ac28b0af
Коммит be7fdcaf33
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 702 добавлений и 536 удалений

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

@ -16,8 +16,8 @@ parameters:
steps:
- pwsh: |
echo "git add ."
git add .
echo "git add -A"
git add -A
echo "git diff --name-status --cached --exit-code"
git diff --name-status --cached --exit-code

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

@ -0,0 +1,61 @@
# intended to be used as part of a release process
parameters:
ArtifactLocation: 'not-specified'
PackageRepository: 'not-specified'
ReleaseSha: 'not-specified'
RepoId: 'not-specified'
WorkingDirectory: ''
ScriptDirectory: eng/common/scripts
TargetDocRepoName: ''
TargetDocRepoOwner: ''
PRBranchName: 'smoke-test-rdme'
ArtifactName: ''
Language: ''
DocRepoDestinationPath: '' #usually docs-ref-services/
steps:
- pwsh: |
git clone https://github.com/${{ parameters.TargetDocRepoOwner }}/${{ parameters.TargetDocRepoName }} ${{ parameters.WorkingDirectory }}/repo
try {
Push-Location ${{ parameters.WorkingDirectory }}/repo
Write-Host "git checkout smoke-test"
git checkout smoke-test
} finally {
Pop-Location
}
displayName: Clone Documentation Repository
ignoreLASTEXITCODE: false
- task: PowerShell@2
displayName: 'Apply Documentation Updates From Artifact'
inputs:
targetType: filePath
filePath: ${{ parameters.ScriptDirectory }}/update-docs-metadata.ps1
arguments: >
-ArtifactLocation ${{parameters.ArtifactLocation}}
-Repository ${{parameters.PackageRepository}}
-ReleaseSHA ${{parameters.ReleaseSha}}
-RepoId ${{parameters.RepoId}}
-WorkDirectory '${{parameters.WorkingDirectory}}'
-DocRepoLocation "${{parameters.WorkingDirectory}}/repo"
-Language "${{parameters.Language}}"
-DocRepoContentLocation ${{ parameters.DocRepoDestinationPath }}
pwsh: true
env:
GH_TOKEN: $(azuresdk-github-pat)
- template: /eng/common/pipelines/templates/steps/create-pull-request.yml
parameters:
RepoName: ${{ parameters.TargetDocRepoName }}
RepoOwner: ${{ parameters.TargetDocRepoOwner }}
PRBranchName: ${{ parameters.PRBranchName }}
CommitMsg: "Update readme content for ${{ parameters.ArtifactName }}"
PRTitle: "Docs.MS Readme Update."
BaseBranchName: smoke-test
WorkingDirectory: ${{parameters.WorkingDirectory}}/repo
ScriptDirectory: ${{parameters.WorkingDirectory}}/${{parameters.ScriptDirectory}}

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

@ -0,0 +1,38 @@
# Template for all Python Scripts in this repository
parameters:
OSVmImage: $(OSVmImage)
steps:
- task: PythonScript@0
displayName: Verify Agent OS
inputs:
scriptSource: inline
script: |
# Script verifies the operating system for the platform on which it is being run
# Used in build pipelines to verify the build agent os
# Variable: The friendly name or image name of the os to verfy against
from __future__ import print_function
import sys
import platform
os_parameter = "${{ parameters.OSVmImage }}".lower()
if os_parameter.startswith('mac') or os_parameter.startswith('darwin'):
os_parameter = 'macOS'
elif os_parameter.startswith('ubuntu') or os_parameter.startswith('linux'):
os_parameter = 'Linux'
elif os_parameter.startswith('vs') or os_parameter.startswith('win'):
os_parameter = 'Windows'
else:
raise Exception('Variable OSVmImage is empty or has an unexpected value [${{ parameters.OSVmImage }}]')
print("Job requested to run on OS: %s" % (os_parameter))
agent_os = platform.system()
agent_os = 'macOS' if agent_os == 'Darwin' else agent_os
if (agent_os.lower() == os_parameter.lower()):
print('Job ran on OS: %s' % (agent_os))
print('##vso[task.setvariable variable=OSName]%s' % (agent_os))
else:
raise Exception('Job ran on the wrong OS: %s' % (agent_os))

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

@ -18,8 +18,9 @@ class AzureEngSemanticVersion {
[int] $PrereleaseNumber
[bool] $IsPrerelease
[string] $RawVersion
# Regex inspired but simplified from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
static [string] $SEMVER_REGEX = "(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-?(?<prelabel>[a-zA-Z-]*)(?:\.?(?<prenumber>0|[1-9]\d*)))?"
static [AzureEngSemanticVersion] ParseVersionString([string] $versionString)
{
try {
@ -31,10 +32,7 @@ class AzureEngSemanticVersion {
}
AzureEngSemanticVersion([string] $versionString){
# Regex inspired but simplifie from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
$SEMVER_REGEX = "^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-?(?<prelabel>[a-zA-Z-]*)(?:\.?(?<prenumber>0|[1-9]\d*)))?$"
if ($versionString -match $SEMVER_REGEX) {
if ($versionString -match "^$([AzureEngSemanticVersion]::SEMVER_REGEX)$") {
if ($null -eq $matches['prelabel']) {
# artifically provide these values for non-prereleases to enable easy sorting of them later than prereleases.
$prelabel = "zzz"

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

@ -0,0 +1,472 @@
. (Join-Path $PSScriptRoot SemVer.ps1)
$SDIST_PACKAGE_REGEX = "^(?<package>.*)\-(?<versionstring>$([AzureEngSemanticVersion]::SEMVER_REGEX))"
# Posts a github release for each item of the pkgList variable. SilentlyContinue
function CreateReleases($pkgList, $releaseApiUrl, $releaseSha) {
foreach ($pkgInfo in $pkgList) {
Write-Host "Creating release $($pkgInfo.Tag)"
$releaseNotes = ""
if ($pkgInfo.ReleaseNotes[$pkgInfo.PackageVersion].ReleaseContent -ne $null) {
$releaseNotes = $pkgInfo.ReleaseNotes[$pkgInfo.PackageVersion].ReleaseContent
}
$isPrerelease = $False
$parsedSemver = [AzureEngSemanticVersion]::ParseVersionString($pkgInfo.PackageVersion)
if ($parsedSemver) {
$isPrerelease = $parsedSemver.IsPrerelease
}
$url = $releaseApiUrl
$body = ConvertTo-Json @{
tag_name = $pkgInfo.Tag
target_commitish = $releaseSha
name = $pkgInfo.Tag
draft = $False
prerelease = $isPrerelease
body = $releaseNotes
}
$headers = @{
"Content-Type" = "application/json"
"Authorization" = "token $($env:GH_TOKEN)"
}
Invoke-WebRequest-WithHandling -url $url -body $body -headers $headers -method "Post"
}
}
function Invoke-WebRequest-WithHandling($url, $method, $body = $null, $headers = $null) {
$attempts = 1
while ($attempts -le 3) {
try {
return Invoke-RestMethod -Method $method -Uri $url -Body $body -Headers $headers
}
catch {
$response = $_.Exception.Response
$statusCode = $response.StatusCode.value__
$statusDescription = $response.StatusDescription
if ($statusCode) {
Write-Host "API request attempt number $attempts to $url failed with statuscode $statusCode"
Write-Host $statusDescription
Write-Host "Rate Limit Details:"
Write-Host "Total: $($response.Headers.GetValues("X-RateLimit-Limit"))"
Write-Host "Remaining: $($response.Headers.GetValues("X-RateLimit-Remaining"))"
Write-Host "Reset Epoch: $($response.Headers.GetValues("X-RateLimit-Reset"))"
}
else {
Write-Host "API request attempt number $attempts to $url failed with no statuscode present, exception follows:"
Write-Host $_.Exception.Response
Write-Host $_.Exception
}
if ($attempts -ge 3) {
Write-Host "Abandoning Request $url after 3 attempts."
exit(1)
}
Start-Sleep -s 10
}
$attempts += 1
}
}
# Parse out package publishing information given a maven POM file
function ParseMavenPackage($pkg, $workingDirectory) {
[xml]$contentXML = Get-Content $pkg
$pkgId = $contentXML.project.artifactId
$pkgVersion = $contentXML.project.version
$groupId = if ($contentXML.project.groupId -eq $null) { $contentXML.project.parent.groupId } else { $contentXML.project.groupId }
# if it's a snapshot. return $null (as we don't want to create tags for this, but we also don't want to fail)
if ($pkgVersion.Contains("SNAPSHOT")) {
return $null
}
$releaseNotes = &"${PSScriptRoot}/../Extract-ReleaseNotes.ps1" -ChangeLogLocation @(Get-ChildItem -Path $pkg.DirectoryName -Recurse -Include "$($pkg.Basename)-changelog.md")[0]
$readmeContentLoc = @(Get-ChildItem -Path $pkg.DirectoryName -Recurse -Include "$($pkg.Basename)-readme.md")[0]
if (Test-Path -Path $readmeContentLoc) {
$readmeContent = Get-Content -Raw $readmeContentLoc
}
return New-Object PSObject -Property @{
PackageId = $pkgId
PackageVersion = $pkgVersion
Deployable = $forceCreate -or !(IsMavenPackageVersionPublished -pkgId $pkgId -pkgVersion $pkgVersion -groupId $groupId.Replace(".", "/"))
ReleaseNotes = $releaseNotes
ReadmeContent = $readmeContent
}
}
# Returns the maven (really sonatype) publish status of a package id and version.
function IsMavenPackageVersionPublished($pkgId, $pkgVersion, $groupId) {
try {
$uri = "https://oss.sonatype.org/content/repositories/releases/$groupId/$pkgId/$pkgVersion/$pkgId-$pkgVersion.pom"
$pomContent = Invoke-RestMethod -MaximumRetryCount 3 -Method "GET" -uri $uri
if ($pomContent -ne $null -or $pomContent.Length -eq 0) {
return $true
}
else {
return $false
}
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
# if this is 404ing, then this pkg has never been published before
if ($statusCode -eq 404) {
return $false
}
Write-Host "VersionCheck to maven for packageId $pkgId failed with statuscode $statusCode"
Write-Host $statusDescription
exit(1)
}
}
# make certain to always take the package json closest to the top
function ResolvePkgJson($workFolder) {
$pathsWithComplexity = @()
foreach ($file in (Get-ChildItem -Path $workFolder -Recurse -Include "package.json")) {
$complexity = ($file.FullName -Split { $_ -eq "/" -or $_ -eq "\" }).Length
$pathsWithComplexity += New-Object PSObject -Property @{
Path = $file
Complexity = $complexity
}
}
return ($pathsWithComplexity | Sort-Object -Property Complexity)[0].Path
}
# Parse out package publishing information given a .tgz npm artifact
function ParseNPMPackage($pkg, $workingDirectory) {
$workFolder = "$workingDirectory$($pkg.Basename)"
$origFolder = Get-Location
New-Item -ItemType Directory -Force -Path $workFolder
cd $workFolder
tar -xzf $pkg
$packageJSON = ResolvePkgJson -workFolder $workFolder | Get-Content | ConvertFrom-Json
$releaseNotes = &"${PSScriptRoot}/../Extract-ReleaseNotes.ps1" -ChangeLogLocation @(Get-ChildItem -Path $workFolder -Recurse -Include "CHANGELOG.md")[0]
$readmeContentLoc = @(Get-ChildItem -Path $workFolder -Recurse -Include "README.md")[0]
if (Test-Path -Path $readmeContentLoc) {
$readmeContent = Get-Content -Raw $readmeContentLoc
}
cd $origFolder
Remove-Item $workFolder -Force -Recurse -ErrorAction SilentlyContinue
$pkgId = $packageJSON.name
$pkgVersion = $packageJSON.version
$resultObj = New-Object PSObject -Property @{
PackageId = $pkgId
PackageVersion = $pkgVersion
Deployable = $forceCreate -or !(IsNPMPackageVersionPublished -pkgId $pkgId -pkgVersion $pkgVersion)
ReleaseNotes = $releaseNotes
ReadmeContent = $readmeContent
}
return $resultObj
}
# Returns the npm publish status of a package id and version.
function IsNPMPackageVersionPublished($pkgId, $pkgVersion) {
$npmVersions = (npm show $pkgId versions)
if ($LastExitCode -ne 0) {
npm ping
if ($LastExitCode -eq 0) {
return $False
}
Write-Host "Could not find a deployed version of $pkgId, and NPM connectivity check failed."
exit(1)
}
$npmVersionList = $npmVersions.split(",") | % { return $_.replace("[", "").replace("]", "").Trim() }
return $npmVersionList.Contains($pkgVersion)
}
# Parse out package publishing information given a nupkg ZIP format.
function ParseNugetPackage($pkg, $workingDirectory) {
$workFolder = "$workingDirectory$($pkg.Basename)"
$origFolder = Get-Location
$zipFileLocation = "$workFolder/$($pkg.Basename).zip"
New-Item -ItemType Directory -Force -Path $workFolder
Copy-Item -Path $pkg -Destination $zipFileLocation
Expand-Archive -Path $zipFileLocation -DestinationPath $workFolder
[xml] $packageXML = Get-ChildItem -Path "$workFolder/*.nuspec" | Get-Content
$releaseNotes = &"${PSScriptRoot}/../Extract-ReleaseNotes.ps1" -ChangeLogLocation @(Get-ChildItem -Path $workFolder -Recurse -Include "CHANGELOG.md")[0]
$readmeContentLoc = @(Get-ChildItem -Path $workFolder -Recurse -Include "README.md")[0]
if (Test-Path -Path $readmeContentLoc) {
$readmeContent = Get-Content -Raw $readmeContentLoc
}
Remove-Item $workFolder -Force -Recurse -ErrorAction SilentlyContinue
$pkgId = $packageXML.package.metadata.id
$pkgVersion = $packageXML.package.metadata.version
return New-Object PSObject -Property @{
PackageId = $pkgId
PackageVersion = $pkgVersion
Deployable = $forceCreate -or !(IsNugetPackageVersionPublished -pkgId $pkgId -pkgVersion $pkgVersion)
ReleaseNotes = $releaseNotes
ReadmeContent = $readmeContent
}
}
# Returns the nuget publish status of a package id and version.
function IsNugetPackageVersionPublished($pkgId, $pkgVersion) {
$nugetUri = "https://api.nuget.org/v3-flatcontainer/$($pkgId.ToLowerInvariant())/index.json"
try {
$nugetVersions = Invoke-RestMethod -MaximumRetryCount 3 -uri $nugetUri -Method "GET"
return $nugetVersions.versions.Contains($pkgVersion)
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
# if this is 404ing, then this pkg has never been published before
if ($statusCode -eq 404) {
return $False
}
Write-Host "Nuget Invocation failed:"
Write-Host "StatusCode:" $statusCode
Write-Host "StatusDescription:" $statusDescription
exit(1)
}
}
# Parse out package publishing information given a python sdist of ZIP format.
function ParsePyPIPackage($pkg, $workingDirectory) {
$pkg.Basename -match $SDIST_PACKAGE_REGEX | Out-Null
$pkgId = $matches["package"]
$pkgVersion = $matches["versionstring"]
$workFolder = "$workingDirectory$($pkg.Basename)"
$origFolder = Get-Location
New-Item -ItemType Directory -Force -Path $workFolder
Expand-Archive -Path $pkg -DestinationPath $workFolder
$releaseNotes = &"${PSScriptRoot}/../Extract-ReleaseNotes.ps1" -ChangeLogLocation @(Get-ChildItem -Path $workFolder -Recurse -Include "CHANGELOG.md")[0]
$readmeContentLoc = @(Get-ChildItem -Path $workFolder -Recurse -Include "README.md")[0]
if (Test-Path -Path $readmeContentLoc) {
$readmeContent = Get-Content -Raw $readmeContentLoc
}
Remove-Item $workFolder -Force -Recurse -ErrorAction SilentlyContinue
return New-Object PSObject -Property @{
PackageId = $pkgId
PackageVersion = $pkgVersion
Deployable = $forceCreate -or !(IsPythonPackageVersionPublished -pkgId $pkgId -pkgVersion $pkgVersion)
ReleaseNotes = $releaseNotes
ReadmeContent = $readmeContent
}
}
function ParseCArtifact($pkg, $workingDirectory) {
$packageInfo = Get-Content -Raw -Path $pkg | ConvertFrom-JSON
$packageArtifactLocation = (Get-ItemProperty $pkg).Directory.FullName
$releaseNotes = ExtractReleaseNotes -changeLogLocation @(Get-ChildItem -Path $packageArtifactLocation -Recurse -Include "CHANGELOG.md")[0]
$readmeContentLoc = @(Get-ChildItem -Path $packageArtifactLocation -Recurse -Include "README.md")[0]
if (Test-Path -Path $readmeContentLoc) {
$readmeContent = Get-Content -Raw $readmeContentLoc
}
return New-Object PSObject -Property @{
PackageId = $packageInfo.name
PackageVersion = $packageInfo.version
# Artifact info is always considered deployable for C becasue it is not
# deployed anywhere. Dealing with duplicate tags happens downstream in
# CheckArtifactShaAgainstTagsList
Deployable = $true
ReleaseNotes = $releaseNotes
ReadmeContent = $readmeContent
}
}
# Returns the pypi publish status of a package id and version.
function IsPythonPackageVersionPublished($pkgId, $pkgVersion) {
try {
$existingVersion = (Invoke-RestMethod -MaximumRetryCount 3 -Method "Get" -uri "https://pypi.org/pypi/$pkgId/$pkgVersion/json").info.version
# if existingVersion exists, then it's already been published
return $True
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
# if this is 404ing, then this pkg has never been published before
if ($statusCode -eq 404) {
return $False
}
Write-Host "PyPI Invocation failed:"
Write-Host "StatusCode:" $statusCode
Write-Host "StatusDescription:" $statusDescription
exit(1)
}
}
# Retrieves the list of all tags that exist on the target repository
function GetExistingTags($apiUrl) {
try {
return (Invoke-WebRequest-WithHandling -Method "GET" -url "$apiUrl/git/refs/tags" ) | % { $_.ref.Replace("refs/tags/", "") }
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
Write-Host "Failed to retrieve tags from repository."
Write-Host "StatusCode:" $statusCode
Write-Host "StatusDescription:" $statusDescription
# Return an empty list if there are no tags in the repo
if ($statusCode -eq 404) {
return @()
}
exit(1)
}
}
# Walk across all build artifacts, check them against the appropriate repository, return a list of tags/releases
function VerifyPackages($pkgRepository, $artifactLocation, $workingDirectory, $apiUrl, $releaseSha, $exitOnError = $True) {
$pkgList = [array]@()
$ParsePkgInfoFn = ""
$packagePattern = ""
switch ($pkgRepository) {
"Maven" {
$ParsePkgInfoFn = "ParseMavenPackage"
$packagePattern = "*.pom"
break
}
"Nuget" {
$ParsePkgInfoFn = "ParseNugetPackage"
$packagePattern = "*.nupkg"
break
}
"NPM" {
$ParsePkgInfoFn = "ParseNPMPackage"
$packagePattern = "*.tgz"
break
}
"PyPI" {
$ParsePkgInfoFn = "ParsePyPIPackage"
$packagePattern = "*.zip"
break
}
"C" {
$ParsePkgInfoFn = "ParseCArtifact"
$packagePattern = "*.json"
}
default {
Write-Host "Unrecognized Language: $language"
exit(1)
}
}
$pkgs = (Get-ChildItem -Path $artifactLocation -Include $packagePattern -Recurse -File)
foreach ($pkg in $pkgs) {
try {
$parsedPackage = &$ParsePkgInfoFn -pkg $pkg -workingDirectory $workingDirectory
if ($parsedPackage -eq $null) {
continue
}
if ($parsedPackage.Deployable -ne $True -and $exitOnError) {
Write-Host "Package $($parsedPackage.PackageId) is marked with version $($parsedPackage.PackageVersion), the version $($parsedPackage.PackageVersion) has already been deployed to the target repository."
Write-Host "Maybe a pkg version wasn't updated properly?"
exit(1)
}
$pkgList += New-Object PSObject -Property @{
PackageId = $parsedPackage.PackageId
PackageVersion = $parsedPackage.PackageVersion
Tag = ($parsedPackage.PackageId + "_" + $parsedPackage.PackageVersion)
ReleaseNotes = $parsedPackage.ReleaseNotes
ReadmeContent = $parsedPackage.ReadmeContent
}
}
catch {
Write-Host $_.Exception.Message
exit(1)
}
}
$results = @([array]$pkgList | Sort-Object -Property Tag -uniq)
$existingTags = GetExistingTags($apiUrl)
$intersect = $results | % { $_.Tag } | ? { $existingTags -contains $_ }
if ($intersect.Length -gt 0 -and $exitOnError) {
CheckArtifactShaAgainstTagsList -priorExistingTagList $intersect -releaseSha $releaseSha -apiUrl $apiUrl -exitOnError $exitOnError
# all the tags are clean. remove them from the list of releases we will publish.
$results = $results | ? { -not ($intersect -contains $_.Tag ) }
}
return $results
}
# given a set of tags that we want to release, we need to ensure that if they already DO exist.
# if they DO exist, quietly exit if the commit sha of the artifact matches that of the tag
# if the commit sha does not match, exit with error and report both problem shas
function CheckArtifactShaAgainstTagsList($priorExistingTagList, $releaseSha, $apiUrl, $exitOnError) {
$headers = @{
"Content-Type" = "application/json"
"Authorization" = "token $($env:GH_TOKEN)"
}
$unmatchedTags = @()
foreach ($tag in $priorExistingTagList) {
$tagSha = (Invoke-WebRequest-WithHandling -Method "Get" -Url "$apiUrl/git/refs/tags/$tag" -Headers $headers)."object".sha
if ($tagSha -eq $releaseSha) {
Write-Host "This package has already been released. The existing tag commit SHA $releaseSha matches the artifact SHA being processed. Skipping release step for this tag."
}
else {
Write-Host "The artifact SHA $releaseSha does not match that of the currently existing tag."
Write-Host "Tag with issues is $tag with commit SHA $tagSha"
$unmatchedTags += $tag
}
}
if ($unmatchedTags.Length -gt 0 -and $exitOnError) {
Write-Host "Tags already existing with different SHA versions. Exiting."
exit(1)
}
}

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

@ -1,87 +0,0 @@
# Example Usage: ./copy-readmes-to-docs.ps1 -CodeRepo C:/repo/sdk-for-python -DocRepo C:/repo/azure-docs-sdk-python
# run the link updating script before this to get links fixed to the release
# Highly recommended that you use Powershell Core.
# git reset --hard origin/smoke-test on the doc repo prior to running this
param (
[String]$CodeRepo,
[String]$DocRepo,
[String]$TargetServices
)
Write-Host "> $PSCommandPath $args"
$PACKAGE_README_REGEX = ".*[\/\\]sdk[\\\/][^\/\\]+[\\\/][^\/\\]+[\/\\]README\.md"
Write-Host "repo is $CodeRepo"
$date = Get-Date -Format "MM/dd/yyyy"
if ($CodeRepo -Match "net")
{
$lang = ".NET"
$TARGET_FOLDER = Join-Path -Path $DocRepo -ChildPath "api/overview/azure"
$metadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/master/_data/releases/latest/dotnet-packages.csv"
}
if ($CodeRepo -Match "python"){
$lang = "Python"
$TARGET_FOLDER = Join-Path -Path $DocRepo -ChildPath "docs-ref-services"
$metadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/master/_data/releases/latest/python-packages.csv"
}
if ($CodeRepo -Match "java"){
$lang = "Java"
$TARGET_FOLDER = Join-Path -Path $DocRepo -ChildPath "docs-ref-services"
$metadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/master/_data/releases/latest/java-packages.csv"
}
if ($CodeRepo -Match "js"){
$lang = "JavaScript"
$TARGET_FOLDER = Join-Path -Path $DocRepo -ChildPath "docs-ref-services"
$metadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/master/_data/releases/latest/js-packages.csv"
}
$metadataResponse = Invoke-WebRequest -Uri $metadataUri | ConvertFrom-Csv
if ([string]::IsNullOrWhiteSpace($TargetServices))
{
$selectedServices = $metadataResponse | ForEach-Object -Process {$_.RepoPath} | Get-Unique
}
else {
$selectedServices = $TargetServices -Split "," | % { return $_.Trim() }
}
foreach($service in $selectedServices){
$readmePath = Join-Path -Path $CodeRepo -ChildPath "sdk/$service"
Write-Host "Examining: $readmePath"
$libraries = $metadataResponse | Where-Object { $_.RepoPath -eq $service }
foreach($library in $libraries){
$package = $library.Package
$version = If ([string]::IsNullOrWhiteSpace($library.VersionGA)) {$library.VersionPreview} Else {$library.VersionGA}
$file = Join-Path -Path $readmePath -ChildPath "/$package/README.md" | Get-Item
Write-Host "`tOutputting $($file.FullName)"
$fileContent = Get-Content $file
$fileContent = $fileContent -Join "`n"
$fileMatch = (Select-String -InputObject $fileContent -Pattern 'Azure .+? (client|plugin|shared) library for (JavaScript|Java|Python|\.NET)').Matches[0]
$header = "---`r`ntitle: $fileMatch`r`nkeywords: Azure, $lang, SDK, API, $service, $package`r`nauthor: maggiepint`r`nms.author: magpint`r`nms.date: $date`r`nms.topic: article`r`nms.prod: azure`r`nms.technology: azure`r`nms.devlang: $lang`r`nms.service: $service`r`n---`r`n"
$fileContent = $fileContent -replace $fileMatch, "$fileMatch - Version $version `r`n"
$fileContent = "$header $fileContent"
$readmeName = "$($file.Directory.Name.Replace('azure-','').Replace('Azure.', '').ToLower())-readme.md"
$readmeOutputLocation = Join-Path $TARGET_FOLDER -ChildPath $readmeName
Set-Content -Path $readmeOutputLocation -Value $fileContent
}
}

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

@ -20,447 +20,7 @@ param (
Write-Host "> $PSCommandPath $args"
$VERSION_REGEX = "(?<major>\d+)(\.(?<minor>\d+))?(\.(?<patch>\d+))?((?<pre>[^0-9][^\s]+))?"
$SDIST_PACKAGE_REGEX = "^(?<package>.*)\-(?<versionstring>$VERSION_REGEX$)"
# Posts a github release for each item of the pkgList variable. SilentlyContinue
function CreateReleases($pkgList, $releaseApiUrl, $releaseSha) {
foreach ($pkgInfo in $pkgList) {
Write-Host "Creating release $($pkgInfo.Tag)"
$releaseNotes = ""
if ($pkgInfo.ReleaseNotes[$pkgInfo.PackageVersion].ReleaseContent -ne $null) {
$releaseNotes = $pkgInfo.ReleaseNotes[$pkgInfo.PackageVersion].ReleaseContent
}
$isPrerelease = $False
if ($pkgInfo.PackageVersion -match $VERSION_REGEX) {
$preReleaseLabel = $matches["pre"]
$isPrerelease = ![string]::IsNullOrEmpty($preReleaseLabel)
}
$url = $releaseApiUrl
$body = ConvertTo-Json @{
tag_name = $pkgInfo.Tag
target_commitish = $releaseSha
name = $pkgInfo.Tag
draft = $False
prerelease = $isPrerelease
body = $releaseNotes
}
$headers = @{
"Content-Type" = "application/json"
"Authorization" = "token $($env:GH_TOKEN)"
}
FireAPIRequest -url $url -body $body -headers $headers -method "Post"
}
}
function FireAPIRequest($url, $method, $body = $null, $headers = $null) {
$attempts = 1
while ($attempts -le 3) {
try {
return Invoke-RestMethod -Method $method -Uri $url -Body $body -Headers $headers
}
catch {
$response = $_.Exception.Response
$statusCode = $response.StatusCode.value__
$statusDescription = $response.StatusDescription
if ($statusCode) {
Write-Host "API request attempt number $attempts to $url failed with statuscode $statusCode"
Write-Host $statusDescription
Write-Host "Rate Limit Details:"
Write-Host "Total: $($response.Headers.GetValues("X-RateLimit-Limit"))"
Write-Host "Remaining: $($response.Headers.GetValues("X-RateLimit-Remaining"))"
Write-Host "Reset Epoch: $($response.Headers.GetValues("X-RateLimit-Reset"))"
}
else {
Write-Host "API request attempt number $attempts to $url failed with no statuscode present, exception follows:"
Write-Host $_.Exception.Response
Write-Host $_.Exception
}
if ($attempts -ge 3) {
Write-Host "Abandoning Request $url after 3 attempts."
exit(1)
}
Start-Sleep -s 10
}
$attempts += 1
}
}
# Parse out package publishing information given a maven POM file
function ParseMavenPackage($pkg, $workingDirectory) {
[xml]$contentXML = Get-Content $pkg
$pkgId = $contentXML.project.artifactId
$pkgVersion = $contentXML.project.version
$groupId = if ($contentXML.project.groupId -eq $null) { $contentXML.project.parent.groupId } else { $contentXML.project.groupId }
# if it's a snapshot. return $null (as we don't want to create tags for this, but we also don't want to fail)
if ($pkgVersion.Contains("SNAPSHOT")) {
return $null
}
$releaseNotes = &"${PSScriptRoot}/../Extract-ReleaseNotes.ps1" -ChangeLogLocation @(Get-ChildItem -Path $pkg.DirectoryName -Recurse -Include "$($pkg.Basename)-changelog.md")[0]
return New-Object PSObject -Property @{
PackageId = $pkgId
PackageVersion = $pkgVersion
Deployable = $forceCreate -or !(IsMavenPackageVersionPublished -pkgId $pkgId -pkgVersion $pkgVersion -groupId $groupId.Replace(".", "/"))
ReleaseNotes = $releaseNotes
}
}
# Returns the maven (really sonatype) publish status of a package id and version.
function IsMavenPackageVersionPublished($pkgId, $pkgVersion, $groupId) {
try {
$uri = "https://oss.sonatype.org/content/repositories/releases/$groupId/$pkgId/$pkgVersion/$pkgId-$pkgVersion.pom"
$pomContent = Invoke-RestMethod -Method "GET" -Uri $uri
if ($pomContent -ne $null -or $pomContent.Length -eq 0) {
return $true
}
else {
return $false
}
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
# if this is 404ing, then this pkg has never been published before
if ($statusCode -eq 404) {
return $false
}
Write-Host "VersionCheck to maven for packageId $pkgId failed with statuscode $statusCode"
Write-Host $statusDescription
exit(1)
}
}
# make certain to always take the package json closest to the top
function ResolvePkgJson($workFolder) {
$pathsWithComplexity = @()
foreach ($file in (Get-ChildItem -Path $workFolder -Recurse -Include "package.json")) {
$complexity = ($file.FullName -Split { $_ -eq "/" -or $_ -eq "\" }).Length
$pathsWithComplexity += New-Object PSObject -Property @{
Path = $file
Complexity = $complexity
}
}
return ($pathsWithComplexity | Sort-Object -Property Complexity)[0].Path
}
# Parse out package publishing information given a .tgz npm artifact
function ParseNPMPackage($pkg, $workingDirectory) {
$workFolder = "$workingDirectory$($pkg.Basename)"
$origFolder = Get-Location
mkdir $workFolder
cd $workFolder
tar -xzf $pkg
$packageJSON = ResolvePkgJson -workFolder $workFolder | Get-Content | ConvertFrom-Json
$releaseNotes = &"${PSScriptRoot}/../Extract-ReleaseNotes.ps1" -ChangeLogLocation @(Get-ChildItem -Path $workFolder -Recurse -Include "CHANGELOG.md")[0]
cd $origFolder
Remove-Item $workFolder -Force -Recurse -ErrorAction SilentlyContinue
$pkgId = $packageJSON.name
$pkgVersion = $packageJSON.version
$resultObj = New-Object PSObject -Property @{
PackageId = $pkgId
PackageVersion = $pkgVersion
Deployable = $forceCreate -or !(IsNPMPackageVersionPublished -pkgId $pkgId -pkgVersion $pkgVersion)
ReleaseNotes = $releaseNotes
}
return $resultObj
}
# Returns the npm publish status of a package id and version.
function IsNPMPackageVersionPublished($pkgId, $pkgVersion) {
$npmVersions = (npm show $pkgId versions)
if ($LastExitCode -ne 0) {
npm ping
if ($LastExitCode -eq 0) {
return $False
}
Write-Host "Could not find a deployed version of $pkgId, and NPM connectivity check failed."
exit(1)
}
$npmVersionList = $npmVersions.split(",") | % { return $_.replace("[", "").replace("]", "").Trim() }
return $npmVersionList.Contains($pkgVersion)
}
# Parse out package publishing information given a nupkg ZIP format.
function ParseNugetPackage($pkg, $workingDirectory) {
$workFolder = "$workingDirectory$($pkg.Basename)"
$origFolder = Get-Location
$zipFileLocation = "$workFolder/$($pkg.Basename).zip"
mkdir $workFolder
Copy-Item -Path $pkg -Destination $zipFileLocation
Expand-Archive -Path $zipFileLocation -DestinationPath $workFolder
[xml] $packageXML = Get-ChildItem -Path "$workFolder/*.nuspec" | Get-Content
$releaseNotes = &"${PSScriptRoot}/../Extract-ReleaseNotes.ps1" -ChangeLogLocation @(Get-ChildItem -Path $workFolder -Recurse -Include "CHANGELOG.md")[0]
Remove-Item $workFolder -Force -Recurse -ErrorAction SilentlyContinue
$pkgId = $packageXML.package.metadata.id
$pkgVersion = $packageXML.package.metadata.version
return New-Object PSObject -Property @{
PackageId = $pkgId
PackageVersion = $pkgVersion
Deployable = $forceCreate -or !(IsNugetPackageVersionPublished -pkgId $pkgId -pkgVersion $pkgVersion)
ReleaseNotes = $releaseNotes
}
}
# Returns the nuget publish status of a package id and version.
function IsNugetPackageVersionPublished($pkgId, $pkgVersion) {
$nugetUri = "https://api.nuget.org/v3-flatcontainer/$($pkgId.ToLowerInvariant())/index.json"
try {
$nugetVersions = Invoke-RestMethod -Method "GET" -Uri $nugetUri
return $nugetVersions.versions.Contains($pkgVersion)
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
# if this is 404ing, then this pkg has never been published before
if ($statusCode -eq 404) {
return $False
}
Write-Host "Nuget Invocation failed:"
Write-Host "StatusCode:" $statusCode
Write-Host "StatusDescription:" $statusDescription
exit(1)
}
}
# Parse out package publishing information given a python sdist of ZIP format.
function ParsePyPIPackage($pkg, $workingDirectory) {
$pkg.Basename -match $SDIST_PACKAGE_REGEX | Out-Null
$pkgId = $matches["package"]
$pkgVersion = $matches["versionstring"]
$workFolder = "$workingDirectory$($pkg.Basename)"
$origFolder = Get-Location
mkdir $workFolder
Expand-Archive -Path $pkg -DestinationPath $workFolder
$releaseNotes = &"${PSScriptRoot}/../Extract-ReleaseNotes.ps1" -ChangeLogLocation @(Get-ChildItem -Path $workFolder -Recurse -Include "CHANGELOG.md")[0]
Remove-Item $workFolder -Force -Recurse -ErrorAction SilentlyContinue
return New-Object PSObject -Property @{
PackageId = $pkgId
PackageVersion = $pkgVersion
Deployable = $forceCreate -or !(IsPythonPackageVersionPublished -pkgId $pkgId -pkgVersion $pkgVersion)
ReleaseNotes = $releaseNotes
}
}
function ParseCArtifact($pkg, $workingDirectory) {
$packageInfo = Get-Content -Raw -Path $pkg | ConvertFrom-JSON
$packageArtifactLocation = (Get-ItemProperty $pkg).Directory.FullName
$releaseNotes = ExtractReleaseNotes -changeLogLocation @(Get-ChildItem -Path $packageArtifactLocation -Recurse -Include "CHANGELOG.md")[0]
return New-Object PSObject -Property @{
PackageId = $packageInfo.name
PackageVersion = $packageInfo.version
# Artifact info is always considered deployable for C becasue it is not
# deployed anywhere. Dealing with duplicate tags happens downstream in
# CheckArtifactShaAgainstTagsList
Deployable = $true
ReleaseNotes = $releaseNotes
}
}
# Returns the pypi publish status of a package id and version.
function IsPythonPackageVersionPublished($pkgId, $pkgVersion) {
try {
$existingVersion = (Invoke-RestMethod -Method "Get" -Uri "https://pypi.org/pypi/$pkgId/$pkgVersion/json").info.version
# if existingVersion exists, then it's already been published
return $True
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
# if this is 404ing, then this pkg has never been published before
if ($statusCode -eq 404) {
return $False
}
Write-Host "PyPI Invocation failed:"
Write-Host "StatusCode:" $statusCode
Write-Host "StatusDescription:" $statusDescription
exit(1)
}
}
# Retrieves the list of all tags that exist on the target repository
function GetExistingTags($apiUrl) {
try {
return (Invoke-RestMethod -Method "GET" -Uri "$apiUrl/git/refs/tags" ) | % { $_.ref.Replace("refs/tags/", "") }
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$statusDescription = $_.Exception.Response.StatusDescription
Write-Host "Failed to retrieve tags from repository."
Write-Host "StatusCode:" $statusCode
Write-Host "StatusDescription:" $statusDescription
# Return an empty list if there are no tags in the repo
if ($statusCode -eq 404) {
return @()
}
exit(1)
}
}
# Walk across all build artifacts, check them against the appropriate repository, return a list of tags/releases
function VerifyPackages($pkgRepository, $artifactLocation, $workingDirectory, $apiUrl, $releaseSha) {
$pkgList = [array]@()
$ParsePkgInfoFn = ""
$packagePattern = ""
switch ($pkgRepository) {
"Maven" {
$ParsePkgInfoFn = "ParseMavenPackage"
$packagePattern = "*.pom"
break
}
"Nuget" {
$ParsePkgInfoFn = "ParseNugetPackage"
$packagePattern = "*.nupkg"
break
}
"NPM" {
$ParsePkgInfoFn = "ParseNPMPackage"
$packagePattern = "*.tgz"
break
}
"PyPI" {
$ParsePkgInfoFn = "ParsePyPIPackage"
$packagePattern = "*.zip"
break
}
"C" {
$ParsePkgInfoFn = "ParseCArtifact"
$packagePattern = "*.json"
}
default {
Write-Host "Unrecognized Language: $language"
exit(1)
}
}
$pkgs = (Get-ChildItem -Path $artifactLocation -Include $packagePattern -Recurse -File)
Write-Host $pkgs
foreach ($pkg in $pkgs) {
try {
$parsedPackage = &$ParsePkgInfoFn -pkg $pkg -workingDirectory $workingDirectory
if ($parsedPackage -eq $null) {
continue
}
if ($parsedPackage.Deployable -ne $True) {
Write-Host "Package $($parsedPackage.PackageId) is marked with version $($parsedPackage.PackageVersion), the version $($parsedPackage.PackageVersion) has already been deployed to the target repository."
Write-Host "Maybe a pkg version wasn't updated properly?"
exit(1)
}
$pkgList += New-Object PSObject -Property @{
PackageId = $parsedPackage.PackageId
PackageVersion = $parsedPackage.PackageVersion
Tag = ($parsedPackage.PackageId + "_" + $parsedPackage.PackageVersion)
ReleaseNotes = $parsedPackage.ReleaseNotes
}
}
catch {
Write-Host $_.Exception.Message
exit(1)
}
}
$results = ([array]$pkgList | Sort-Object -Property Tag -uniq)
$existingTags = GetExistingTags($apiUrl)
$intersect = $results | % { $_.Tag } | ? { $existingTags -contains $_ }
if ($intersect.Length -gt 0) {
CheckArtifactShaAgainstTagsList -priorExistingTagList $intersect -releaseSha $releaseSha -apiUrl $apiUrl
# all the tags are clean. remove them from the list of releases we will publish.
$results = $results | ? { -not ($intersect -contains $_.Tag ) }
}
return $results
}
# given a set of tags that we want to release, we need to ensure that if they already DO exist.
# if they DO exist, quietly exit if the commit sha of the artifact matches that of the tag
# if the commit sha does not match, exit with error and report both problem shas
function CheckArtifactShaAgainstTagsList($priorExistingTagList, $releaseSha, $apiUrl) {
$headers = @{
"Content-Type" = "application/json"
"Authorization" = "token $($env:GH_TOKEN)"
}
$unmatchedTags = @()
foreach ($tag in $priorExistingTagList) {
$tagSha = (FireAPIRequest -Method "Get" -Url "$apiUrl/git/refs/tags/$tag" -Headers $headers)."object".sha
if ($tagSha -eq $releaseSha) {
Write-Host "This package has already been released. The existing tag commit SHA $releaseSha matches the artifact SHA being processed. Skipping release step for this tag."
}
else {
Write-Host "The artifact SHA $releaseSha does not match that of the currently existing tag."
Write-Host "Tag with issues is $tag with commit SHA $tagSha"
$unmatchedTags += $tag
}
}
if ($unmatchedTags.Length -gt 0) {
Write-Host "Tags already existing with different SHA versions. Exiting."
exit(1)
}
}
. (Join-Path $PSScriptRoot artifact-metadata-parsing.ps1)
$apiUrl = "https://api.github.com/repos/$repoId"
Write-Host "Using API URL $apiUrl"

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

@ -137,7 +137,6 @@ do
}
}
}
} while($needsRetry -and $tryNumber -le $numberOfRetries)
if ($LASTEXITCODE -ne 0)

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

@ -0,0 +1,125 @@
# Note, due to how `Expand-Archive` is leveraged in this script,
# powershell core is a requirement for successful execution.
param (
# arguments leveraged to parse and identify artifacts
$ArtifactLocation, # the root of the artifact folder. DevOps $(System.ArtifactsDirectory)
$WorkDirectory, # a clean folder that we can work in
$ReleaseSHA, # the SHA for the artifacts. DevOps: $(Release.Artifacts.<artifactAlias>.SourceVersion) or $(Build.SourceVersion)
$RepoId, # full repo id. EG azure/azure-sdk-for-net DevOps: $(Build.Repository.Id). Used as a part of VerifyPackages
$Repository, # EG: "Maven", "PyPI", "NPM"
# arguments necessary to power the docs release
$DocRepoLocation, # the location on disk where we have cloned the documentation repository
$Language, # EG: js, java, dotnet. Used in language for the embedded readme.
$DocRepoContentLocation = "docs-ref-services/" # within the doc repo, where does our readme go?
)
Write-Host "> $PSCommandPath $args"
# import artifact parsing and semver handling
. (Join-Path $PSScriptRoot artifact-metadata-parsing.ps1)
. (Join-Path $PSScriptRoot SemVer.ps1)
function GetMetaData($lang){
switch ($lang) {
"java" {
$metadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/master/_data/releases/latest/java-packages.csv"
break
}
".net" {
$metadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/master/_data/releases/latest/dotnet-packages.csv"
break
}
"python" {
$metadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/master/_data/releases/latest/python-packages.csv"
break
}
"javascript" {
$metadataUri = "https://raw.githubusercontent.com/Azure/azure-sdk/master/_data/releases/latest/js-packages.csv"
break
}
default {
Write-Host "Unrecognized Language: $language"
exit(1)
}
}
$metadataResponse = Invoke-WebRequest-WithHandling -url $metadataUri -method "GET" | ConvertFrom-Csv
}
function GetAdjustedReadmeContent($pkgInfo, $lang){
$date = Get-Date -Format "MM/dd/yyyy"
$service = ""
# the namespace is not expected to be present for js.
$pkgId = $pkgInfo.PackageId.Replace("@azure/", "")
try {
$metadata = GetMetaData -lang $lang
$service = $metadata | ? { $_.Package -eq $pkgId }
if ($service) {
$service = "$service,"
}
}
catch {
Write-Host $_
Write-Host "Unable to retrieve service metadata for packageId $($pkgInfo.PackageId)"
}
$headerContentMatch = (Select-String -InputObject $pkgInfo.ReadmeContent -Pattern 'Azure .+? (client|plugin|shared) library for (JavaScript|Java|Python|\.NET|C)').Matches[0]
if ($headerContentMatch){
$header = "---`r`ntitle: $headerContentMatch`r`nkeywords: Azure, $lang, SDK, API, $service $($pkgInfo.PackageId)`r`nauthor: maggiepint`r`nms.author: magpint`r`nms.date: $date`r`nms.topic: article`r`nms.prod: azure`r`nms.technology: azure`r`nms.devlang: $lang`r`nms.service: $service`r`n---`r`n"
$fileContent = $pkgInfo.ReadmeContent -replace $headerContentMatch, "$headerContentMatch - Version $($pkgInfo.PackageVersion) `r`n"
return "$header $fileContent"
}
else {
return ""
}
}
$apiUrl = "https://api.github.com/repos/$repoId"
$pkgs = VerifyPackages -pkgRepository $Repository `
-artifactLocation $ArtifactLocation `
-workingDirectory $WorkDirectory `
-apiUrl $apiUrl `
-releaseSha $ReleaseSHA `
-exitOnError $False
if ($pkgs) {
Write-Host "Given the visible artifacts, readmes will be copied for the following packages"
Write-Host ($pkgs | % { $_.PackageId })
foreach ($packageInfo in $pkgs) {
# sync the doc repo
$semVer = [AzureEngSemanticVersion]::ParseVersionString($packageInfo.PackageVersion)
$rdSuffix = ""
if ($semVer.IsPreRelease) {
$rdSuffix = "-pre"
}
$readmeName = "$($packageInfo.PackageId.Replace('azure-','').Replace('Azure.', '').Replace('@azure/', '').ToLower())-readme$rdSuffix.md"
$readmeLocation = Join-Path $DocRepoLocation $DocRepoContentLocation $readmeName
$adjustedContent = GetAdjustedReadmeContent -pkgInfo $packageInfo -lang $Language
if ($adjustedContent) {
try {
Push-Location $DocRepoLocation
Set-Content -Path $readmeLocation -Value $adjustedContent -Force
Write-Host "Updated readme for $readmeName."
} catch {
Write-Host $_
} finally {
Pop-Location
}
} else {
Write-Host "Unable to parse a header out of the readmecontent for PackageId $($packageInfo.PackageId)"
}
}
}
else {
Write-Host "No readmes discovered for doc release under folder $ArtifactLocation."
}