Merge pull request #17 from actions/v-malob/python-parser

Rework version grabber and add Python support
This commit is contained in:
Maxim Lobanov
2020-12-09 22:25:52 +03:00
committed by GitHub
11 changed files with 189 additions and 197 deletions

View File

@@ -32,6 +32,7 @@ stages:
- stage: Trigger_Builds
dependsOn: Get_New_Versions
condition: and(succeeded(), ne(stageDependencies.Get_New_Versions.Get_Tool_Versions.outputs['Get_versions.TOOL_VERSIONS'], ''), ne(variables['WORKFLOW_FILE_NAME'], ''))
jobs:
- deployment: Run_Builds
pool:

View File

@@ -6,32 +6,25 @@ steps:
targetType: filePath
filePath: './get-new-tool-versions/get-new-tool-versions.ps1'
arguments: |
-DistURL "$(DIST_URL)" `
-ManifestLink "$(MANIFEST_URL)" `
-VersionFilterToInclude $(INCLUDE_FILTER) `
-VersionFilterToExclude $(EXCLUDE_FILTER)
-ToolName "$(TOOL_NAME)"
- task: PowerShell@2
displayName: 'Cancel build'
condition: and(succeeded(), eq(variables['Get_versions.TOOL_VERSIONS'], ''))
inputs:
TargetType: inline
script: |
Import-Module "./azure-devops/azure-devops-api.ps1"
$azureDevOpsApi = Get-AzureDevOpsApi -TeamFoundationCollectionUri $(System.TeamFoundationCollectionUri) `
-ProjectName $(System.TeamProject) `
-AccessToken $(System.AccessToken)
$AzureDevOpsApi.UpdateBuildStatus($(Build.BuildId), 'Cancelling') | Out-Null
- task: PowerShell@2
displayName: 'Set env variable'
condition: and(succeeded(), ne(variables['Get_versions.TOOL_VERSIONS'], ''))
displayName: 'Set PIPELINE_URL variable'
condition: and(succeeded(), ne(variables['TOOL_NAME'], 'Python'))
inputs:
TargetType: inline
script: |
$PipelineUrl = "$(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)"
Write-Output "##vso[task.setvariable variable=PIPELINE_URL]$PipelineUrl"
Write-Host "##vso[task.setvariable variable=PIPELINE_URL]$PipelineUrl"
- task: PowerShell@2
displayName: 'Change build name'
condition: and(succeeded(), ne(variables['Get_versions.TOOL_VERSIONS'], ''))
inputs:
TargetType: inline
script: |
$newBuildName = "[FOUND] $(Build.BuildNumber)"
Write-Host "##vso[build.updatebuildnumber]$newBuildName"
- task: PowerShell@2
displayName: 'Send Slack notification'
@@ -43,5 +36,5 @@ steps:
-Url "$(SLACK_CHANNEL_URL)" `
-ToolName "$(TOOL_NAME)" `
-ToolVersion "$(Get_versions.TOOL_VERSIONS)" `
-PipelineUrl "$(PIPELINE_URL)" `
-PipelineUrl "${{ variables.PIPELINE_URL }}" `
-ImageUrl "$(IMAGE_URL)"

View File

@@ -1,93 +0,0 @@
#Requires -Modules Pester
Import-Module (Join-Path $PSScriptRoot "helpers.psm1") -Force
Describe "Validate-FiltersFormat" {
It "Filter with word" {
{ Validate-FiltersFormat -Filters @("1two.2") } | Should -Throw "Invalid filter format"
}
It "Filter with non-word character" {
{ Validate-FiltersFormat -Filters @("1,.2") } | Should -Throw "Invalid filter format"
}
It "Valid filters" {
{ Validate-FiltersFormat -Filters @("*", "1", "1.*", "1.2", "1.2.*") } | Should -Not -Throw "Invalid filter format"
}
}
Describe "Format-Versions" {
It "Clean versions" {
$actualOutput = Format-Versions -Versions @("14.2.0", "1.14.0")
$expectedOutput = @("14.2.0", "1.14.0")
$actualOutput | Should -Be $expectedOutput
}
It "Versions with prefixes" {
$actualOutput = Format-Versions -Versions @("v14.2.0", "go1.14.0")
$expectedOutput = @("14.2.0", "1.14.0")
$actualOutput | Should -Be $expectedOutput
}
It "Skip beta and rc versions" {
$actualOutput = Format-Versions -Versions @("14.2.0-beta", "v1.14.0-rc-1")
$expectedOutput = @()
$actualOutput | Should -Be $expectedOutput
}
It "Short version" {
$actualOutput = Format-Versions -Versions @("14.2", "v2.0")
$expectedOutput = @("14.2.0", "2.0.0")
$actualOutput | Should -Be $expectedOutput
}
It "Skip versions with 1 digit" {
$actualOutput = Format-Versions -Versions @("14", "v2")
$expectedOutput = @()
$actualOutput | Should -Be $expectedOutput
}
}
Describe "Select-VersionsByFilter" {
$inputVersions = @("8.2.1", "9.3.3", "10.0.2", "10.0.3", "10.5.6", "12.4.3", "12.5.1", "14.2.0")
It "Include filter only" {
$includeFilters = @("8.*", "14.*")
$excludeFilters = @()
$actualOutput = Select-VersionsByFilter -Versions $inputVersions -IncludeFilters $includeFilters -ExcludeFilters $excludeFilters
$expectedOutput = @("8.2.1", "14.2.0")
$actualOutput | Should -Be $expectedOutput
}
It "Include and exclude filters" {
$includeFilters = @("10.*", "12.*")
$excludeFilters = @("10.0.*", "12.4.3")
$actualOutput = Select-VersionsByFilter -Versions $inputVersions -IncludeFilters $includeFilters -ExcludeFilters $excludeFilters
$expectedOutput = @("10.5.6", "12.5.1")
$actualOutput | Should -Be $expectedOutput
}
It "Exclude filter only" {
$includeFilters = @()
$excludeFilters = @("10.*", "12.*")
$actualOutput = Select-VersionsByFilter -Versions $inputVersions -IncludeFilters $includeFilters -ExcludeFilters $excludeFilters
$expectedOutput = @("8.2.1", "9.3.3", "14.2.0")
$actualOutput | Should -Be $expectedOutput
}
It "Include and exclude filters are empty" {
$actualOutput = Select-VersionsByFilter -Versions $inputVersions
$expectedOutput = @("8.2.1", "9.3.3", "10.0.2", "10.0.3", "10.5.6", "12.4.3", "12.5.1", "14.2.0")
$actualOutput | Should -Be $expectedOutput
}
}
Describe "Skip-ExistingVersions" {
It "Substract versions correctly" {
$distInput = @("14.2.0", "14.3.0", "14.4.0", "14.4.1")
$manifestInput = @("12.0.0", "14.2.0", "14.4.0")
$actualOutput = Skip-ExistingVersions -VersionsFromDist $distInput -VersionsFromManifest $manifestInput
$expectedOutput = @("14.3.0", "14.4.1")
$actualOutput | Should -Be $expectedOutput
}
}

View File

@@ -2,79 +2,26 @@
.SYNOPSIS
Check and return list of new available tool versions
.PARAMETER DistURL
Required parameter. Link to the json file included all available tool versions
.PARAMETER ManifestLink
Required parameter. Link to the the version-manifest.json file
.PARAMETER VersionFilterToInclude
Optional parameter. List of filters to include particular versions
.PARAMETER VersionFilterToExclude
Optional parameter. List of filters to exclude particular versions
.PARAMETER RetryIntervalSec
Optional parameter. Retry interval in seconds
.PARAMETER RetryCount
Optional parameter. Retry count
.PARAMETER ToolName
Required parameter. The name of tool for which parser is available (Node, Go, Python)
#>
param (
[Parameter(Mandatory)] [string] $DistURL,
[Parameter(Mandatory)] [string] $ManifestLink,
[string[]] $VersionFilterToInclude,
[string[]] $VersionFilterToExclude,
[UInt32] $RetryIntervalSec = 60,
[UInt32] $RetryCount = 3
[Parameter(Mandatory)] [string] $ToolName
)
Import-Module (Join-Path $PSScriptRoot "helpers.psm1")
Import-Module "$PSScriptRoot/parsers/parsers-factory.psm1"
function Get-VersionsByUrl {
param (
[Parameter(Mandatory)] [string] $ToolPackagesUrl,
[Parameter(Mandatory)] [UInt32] $RetryIntervalSec,
[Parameter(Mandatory)] [UInt32] $RetryCount
)
$ToolVersionParser = Get-ToolVersionsParser -ToolName $ToolName
$VersionsFromDist = $ToolVersionParser.GetAvailableVersions()
$VersionsFromManifest = $ToolVersionParser.GetUploadedVersions()
$packages = Invoke-RestMethod $ToolPackagesUrl -MaximumRetryCount $RetryCount -RetryIntervalSec $RetryIntervalSec
return $packages.version
}
$VersionsToBuild = $VersionsFromDist | Where-Object { $VersionsFromManifest -notcontains $_ }
if ($VersionFilterToInclude) {
Validate-FiltersFormat -Filters $VersionFilterToInclude
}
if ($VersionFilterToExclude) {
Validate-FiltersFormat -Filters $VersionFilterToExclude
}
Write-Host "Get the packages list from $DistURL"
$versionsFromDist = Get-VersionsByUrl -ToolPackagesUrl $DistURL `
-RetryIntervalSec $RetryIntervalSec `
-RetryCount $RetryCount
Write-Host "Get the packages list from $ManifestLink"
[Version[]] $versionsFromManifest = Get-VersionsByUrl -ToolPackagesUrl $ManifestLink `
-RetryIntervalSec $RetryIntervalSec `
-RetryCount $RetryCount
[Version[]] $formattedVersions = Format-Versions -Versions $versionsFromDist
$formattedVersions = Select-VersionsByFilter -Versions $formattedVersions `
-IncludeFilters $VersionFilterToInclude `
-ExcludeFilters $VersionFilterToExclude
if (-not $formattedVersions) {
Write-Host "Couldn't find available versions with current filters"
exit 1
}
$versionsToBuild = Skip-ExistingVersions -VersionsFromManifest $versionsFromManifest `
-VersionsFromDist $formattedVersions
if ($versionsToBuild) {
$availableVersions = $versionsToBuild -join ","
$toolVersions = $availableVersions.Replace(",",", ")
Write-Host "The following versions are available to build:`n$toolVersions"
Write-Output "##vso[task.setvariable variable=TOOL_VERSIONS;isOutput=true]$toolVersions"
if ($VersionsToBuild) {
$availableVersions = $VersionsToBuild -join ", "
Write-Host "The following versions are available to build:`n${availableVersions}"
Write-Host "##vso[task.setvariable variable=TOOL_VERSIONS;isOutput=true]${availableVersions}"
} else {
Write-Host "There aren't versions to build"
}

View File

@@ -1,17 +1,3 @@
function Validate-FiltersFormat {
param (
[Parameter(Mandatory)] [string[]] $Filters
)
foreach($filter in $Filters) {
$filter.Split('.') | ForEach-Object {
if (($_ -notmatch '^\d+$') -and ($_ -ne '*')) {
throw "Invalid filter format - $filter"
}
}
}
}
function Format-Versions {
param (
[Parameter(Mandatory)] [string[]] $Versions

View File

@@ -0,0 +1,31 @@
class BaseVersionsParser {
[Int32]$ApiRetryCount = 3
[Int32]$ApiRetryIntervalSeconds = 60
[SemVer[]] GetAvailableVersions() {
$allVersionsRaw = $this.ParseAllAvailableVersions()
$allVersions = $allVersionsRaw | ForEach-Object { $this.FormatVersion($_) }
$filteredVersions = $allVersions | Where-Object { $this.ShouldIncludeVersion($_) }
return $filteredVersions
}
[SemVer[]] GetUploadedVersions() {
throw "Method is not implemented in base class"
}
hidden [SemVer[]] ParseAllAvailableVersions() {
throw "Method is not implemented in base class"
}
hidden [SemVer] FormatVersion([string]$VersionSpec) {
throw "Method is not implemented in base class"
}
hidden [bool] ShouldIncludeVersion([SemVer]$Version) {
throw "Method is not implemented in base class"
}
hidden [string] BuildGitHubFileUrl($OrganizationName, $RepositoryName, $BranchName, $FilePath) {
return "https://raw.githubusercontent.com/${OrganizationName}/${RepositoryName}/${BranchName}/${FilePath}"
}
}

View File

@@ -0,0 +1,25 @@
using module "./base-parser.psm1"
class GoVersionsParser: BaseVersionsParser {
[SemVer[]] GetUploadedVersions() {
$url = $this.BuildGitHubFileUrl("actions", "go-versions", "main", "versions-manifest.json")
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [string[]] ParseAllAvailableVersions() {
$url = "https://golang.org/dl/?mode=json&include=all"
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [SemVer] FormatVersion([string]$VersionSpec) {
$cleanVersion = $VersionSpec -replace "^go", ""
return [SemVer]$cleanVersion
}
hidden [bool] ShouldIncludeVersion([SemVer]$Version) {
# For Go, we include all versions greater than 1.12
return $Version -gt [SemVer]"1.12.0"
}
}

View File

@@ -0,0 +1,30 @@
using module "./base-parser.psm1"
class NodeVersionsParser: BaseVersionsParser {
[SemVer[]] GetUploadedVersions() {
$url = $this.BuildGitHubFileUrl("actions", "node-versions", "main", "versions-manifest.json")
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [string[]] ParseAllAvailableVersions() {
$url = "https://nodejs.org/dist/index.json"
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [SemVer] FormatVersion([string]$VersionSpec) {
$cleanVersion = $VersionSpec -replace "^v", ""
return [SemVer]$cleanVersion
}
hidden [bool] ShouldIncludeVersion([SemVer]$Version) {
if ($Version.Major -lt 8) {
return $false
}
# For Node.JS, we should include all LTS versions (all even-numbered releases)
# https://nodejs.org/en/about/releases/
return $Version.Major % 2 -eq 0
}
}

View File

@@ -0,0 +1,19 @@
using module "./node-parser.psm1"
using module "./go-parser.psm1"
using module "./python-parser.psm1"
function Get-ToolVersionsParser {
param(
[Parameter(Mandatory)]
[string]$ToolName
)
switch ($ToolName) {
"Node" { return [NodeVersionsParser]::New() }
"Go" { return [GoVersionsParser]::New() }
"Python" { return [PythonVersionsParser]::New() }
Default {
throw "Unknown tool name"
}
}
}

View File

@@ -0,0 +1,53 @@
using module "./base-parser.psm1"
class PythonVersionsParser: BaseVersionsParser {
[SemVer[]] GetUploadedVersions() {
$url = $this.BuildGitHubFileUrl("actions", "python-versions", "main", "versions-manifest.json")
$releases = Invoke-RestMethod $url -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $releases.version
}
hidden [string[]] ParseAllAvailableVersions() {
$stableVersionsUrl = "https://www.python.org/ftp/python"
$stableVersionsHtmlRaw = Invoke-WebRequest $stableVersionsUrl -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
$stableVersionsList = $stableVersionsHtmlRaw.Links.href | Where-Object {
$parsed = $null
return $_.EndsWith("/") -and [SemVer]::TryParse($_.Replace("/", ""), [ref]$parsed)
}
return $stableVersionsList | ForEach-Object {
$subVersionsUrl = "${stableVersionsUrl}/${_}"
$subVersionsHtmlRaw = Invoke-WebRequest $subVersionsUrl -MaximumRetryCount $this.ApiRetryCount -RetryIntervalSec $this.ApiRetryIntervalSeconds
return $subVersionsHtmlRaw.Links.href | ForEach-Object {
if ($_ -match "^Python-(\d+\.\d+\.\d+[a-z]{0,2}\d*)\.tgz$") {
return $Matches[1]
}
}
}
}
hidden [SemVer] FormatVersion([string]$VersionSpec) {
$VersionSpec -match "^(\d+)\.(\d+)\.(\d+)([a-z]{1,2})?(\d+)?$"
if ($Matches.Count -gt 4) {
$VersionLabel = "{0}.{1}" -f $this.ConvertPythonLabel($Matches[4]), $Matches[5]
return [SemVer]::new($Matches[1], $Matches[2], $Matches[3], $VersionLabel)
}
return [SemVer]::new($Matches[1], $Matches[2], $Matches[3])
}
hidden [string] ConvertPythonLabel([string]$Label) {
switch ($Label) {
"a" { return "alpha" }
"b" { return "beta" }
}
return $Label
}
[bool] ShouldIncludeVersion([SemVer]$Version) {
# For Python, we include all versions greater than 3.9.0
return $Version -gt [SemVer]"3.9.0"
}
}

View File

@@ -27,10 +27,7 @@ param(
[ValidateNotNullOrEmpty()]
[System.String]$ToolVersion,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[System.String]$PipelineUrl,
[System.String]$ImageUrl = 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png'
)
@@ -38,7 +35,10 @@ param(
Import-Module $PSScriptRoot/helpers.psm1 -DisableNameChecking
# Create JSON body
$text = "The following versions of '$toolName' are available to upload: $toolVersion\nLink to the pipeline: $pipelineUrl"
$text = "The following versions of '$toolName' are available to upload: $toolVersion"
if ($PipelineUrl) {
$text += "\nLink to the pipeline: $pipelineUrl"
}
$jsonBodyMessage = @"
{
"blocks": [