1 . (Join-Path $EngCommonScriptsDir SemVer.ps1)
2 
3 $SDIST_PACKAGE_REGEX = "^(?<package>.*)\-(?<versionstring>$([AzureEngSemanticVersion]::SEMVER_REGEX))"
4 
5 # Posts a github release for each item of the pkgList variable. SilentlyContinue
CreateReleases($pkgList, $releaseApiUrl, $releaseSha)6 function CreateReleases($pkgList, $releaseApiUrl, $releaseSha) {
7   foreach ($pkgInfo in $pkgList) {
8     Write-Host "Creating release $($pkgInfo.Tag)"
9 
10     $releaseNotes = ""
11     if ($pkgInfo.ReleaseNotes -ne $null) {
12       $releaseNotes = $pkgInfo.ReleaseNotes
13     }
14 
15     $isPrerelease = $False
16 
17     $parsedSemver = [AzureEngSemanticVersion]::ParseVersionString($pkgInfo.PackageVersion)
18 
19     if ($parsedSemver) {
20       $isPrerelease = $parsedSemver.IsPrerelease
21     }
22 
23     $url = $releaseApiUrl
24     $body = ConvertTo-Json @{
25       tag_name         = $pkgInfo.Tag
26       target_commitish = $releaseSha
27       name             = $pkgInfo.Tag
28       draft            = $False
29       prerelease       = $isPrerelease
30       body             = $releaseNotes
31     }
32 
33     $headers = @{
34       "Content-Type"  = "application/json"
35       "Authorization" = "token $($env:GH_TOKEN)"
36     }
37 
38     Invoke-RestMethod -Uri $url -Body $body -Headers $headers -Method "Post" -MaximumRetryCount 3 -RetryIntervalSec 10
39   }
40 }
41 
42 # Retrieves the list of all tags that exist on the target repository
GetExistingTags($apiUrl)43 function GetExistingTags($apiUrl) {
44   try {
45     return (Invoke-RestMethod -Method "GET" -Uri "$apiUrl/git/refs/tags" -MaximumRetryCount 3 -RetryIntervalSec 10) | % { $_.ref.Replace("refs/tags/", "") }
46   }
47   catch {
48     Write-Host $_
49     $statusCode = $_.Exception.Response.StatusCode.value__
50     $statusDescription = $_.Exception.Response.StatusDescription
51 
52     Write-Host "Failed to retrieve tags from repository."
53     Write-Host "StatusCode:" $statusCode
54     Write-Host "StatusDescription:" $statusDescription
55 
56     # Return an empty list if there are no tags in the repo
57     if ($statusCode -eq 404) {
58       return ,@()
59     }
60 
61     exit(1)
62   }
63 }
64 
65 # Retrieve release tag for artiface package. If multiple packages, then output the first one.
RetrieveReleaseTag($artifactLocation, $continueOnError = $true)66 function RetrieveReleaseTag($artifactLocation, $continueOnError = $true) {
67   if (!$artifactLocation) {
68     return ""
69   }
70   try {
71     $pkgs, $parsePkgInfoFn = RetrievePackages -artifactLocation $artifactLocation
72     if (!$pkgs -or !$pkgs[0]) {
73       Write-Host "No packages retrieved from artifact location."
74       return ""
75     }
76     if ($pkgs.Count -gt 1) {
77       Write-Host "There are more than 1 packages retieved from artifact location."
78       foreach ($pkg in $pkgs) {
79         Write-Host "The package name is $($pkg.BaseName)"
80       }
81       return ""
82     }
83     $parsedPackage = &$parsePkgInfoFn -pkg $pkgs[0] -workingDirectory $artifactLocation
84     return $parsedPackage.ReleaseTag
85   }
86   catch {
87     if ($continueOnError) {
88       return ""
89     }
90     Write-Error "No release tag retrieved from $artifactLocation"
91   }
92 }
93 
RetrievePackages($artifactLocation)94 function RetrievePackages($artifactLocation) {
95   $pkgs = Get-ChildItem -Path $artifactLocation -Include $packagePattern -Recurse -File
96   if ($GetPackageInfoFromPackageFileFn -and (Test-Path "Function:$GetPackageInfoFromPackageFileFn"))
97   {
98     return $pkgs, $GetPackageInfoFromPackageFileFn
99   }
100   else
101   {
102     LogError "The function for '$GetPackageInfoFromPackageFileFn' was not found.`
103     Make sure it is present in eng/scripts/Language-Settings.ps1 and referenced in eng/common/scripts/common.ps1.`
104     See https://github.com/Azure/azure-sdk-tools/blob/main/doc/common/common_engsys.md#code-structure"
105   }
106 }
107 
108 # Walk across all build artifacts, check them against the appropriate repository, return a list of tags/releases
VerifyPackages($artifactLocation, $workingDirectory, $apiUrl, $releaseSha,  $continueOnError = $false)109 function VerifyPackages($artifactLocation, $workingDirectory, $apiUrl, $releaseSha,  $continueOnError = $false) {
110   $pkgList = [array]@()
111   $pkgs, $parsePkgInfoFn = RetrievePackages -artifactLocation $artifactLocation
112 
113   foreach ($pkg in $pkgs) {
114     try {
115       $parsedPackage = &$parsePkgInfoFn -pkg $pkg -workingDirectory $workingDirectory
116 
117       if ($parsedPackage -eq $null) {
118         continue
119       }
120 
121       if ($parsedPackage.Deployable -ne $True -and !$continueOnError) {
122         Write-Host "Package $($parsedPackage.PackageId) is marked with version $($parsedPackage.PackageVersion), the version $($parsedPackage.PackageVersion) has already been deployed to the target repository."
123         Write-Host "Maybe a pkg version wasn't updated properly?"
124         exit(1)
125       }
126       $docsReadMeName = $parsedPackage.PackageId
127       if ($parsedPackage.DocsReadMeName) {
128         $docsReadMeName = $parsedPackage.DocsReadMeName
129       }
130       $pkgList += New-Object PSObject -Property @{
131         PackageId      = $parsedPackage.PackageId
132         PackageVersion = $parsedPackage.PackageVersion
133         GroupId        = $parsedPackage.GroupId
134         Tag            = $parsedPackage.ReleaseTag
135         ReleaseNotes   = $parsedPackage.ReleaseNotes
136         ReadmeContent  = $parsedPackage.ReadmeContent
137         DocsReadMeName = $docsReadMeName
138         IsPrerelease   = [AzureEngSemanticVersion]::ParseVersionString($parsedPackage.PackageVersion).IsPrerelease
139       }
140     }
141     catch {
142       Write-Host $_.Exception.Message
143       exit(1)
144     }
145   }
146 
147   $results = @([array]$pkgList | Sort-Object -Property Tag -uniq)
148 
149   $existingTags = GetExistingTags($apiUrl)
150 
151   $intersect = $results | % { $_.Tag } | ? { $existingTags -contains $_ }
152 
153   if ($intersect.Length -gt 0 -and !$continueOnError) {
154     CheckArtifactShaAgainstTagsList -priorExistingTagList $intersect -releaseSha $releaseSha -apiUrl $apiUrl -continueOnError $continueOnError
155 
156     # all the tags are clean. remove them from the list of releases we will publish.
157     $results = $results | ? { -not ($intersect -contains $_.Tag ) }
158   }
159 
160   return $results
161 }
162 
163 # given a set of tags that we want to release, we need to ensure that if they already DO exist.
164 # if they DO exist, quietly exit if the commit sha of the artifact matches that of the tag
165 # if the commit sha does not match, exit with error and report both problem shas
CheckArtifactShaAgainstTagsList($priorExistingTagList, $releaseSha, $apiUrl, $continueOnError)166 function CheckArtifactShaAgainstTagsList($priorExistingTagList, $releaseSha, $apiUrl, $continueOnError) {
167   $headers = @{
168     "Content-Type"  = "application/json"
169     "Authorization" = "token $($env:GH_TOKEN)"
170   }
171 
172   $unmatchedTags = @()
173 
174   foreach ($tag in $priorExistingTagList) {
175     $tagSha = (Invoke-RestMethod -Method "Get" -Uri "$apiUrl/git/refs/tags/$tag" -Headers $headers -MaximumRetryCount 3 -RetryIntervalSec 10)."object".sha
176 
177     if ($tagSha -eq $releaseSha) {
178       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."
179     }
180     else {
181       Write-Host "The artifact SHA $releaseSha does not match that of the currently existing tag."
182       Write-Host "Tag with issues is $tag with commit SHA $tagSha"
183 
184       $unmatchedTags += $tag
185     }
186   }
187 
188   if ($unmatchedTags.Length -gt 0 -and !$continueOnError) {
189     Write-Host "Tags already existing with different SHA versions. Exiting."
190     exit(1)
191   }
192 }
193