diff --git a/azure-pipelines/templates/run-ci-builds-steps.yml b/azure-pipelines/templates/run-ci-builds-steps.yml index f5a6634..e802b99 100644 --- a/azure-pipelines/templates/run-ci-builds-steps.yml +++ b/azure-pipelines/templates/run-ci-builds-steps.yml @@ -1,29 +1,15 @@ steps: - checkout: self -- task: PowerShell@2 - displayName: 'Get source version' - inputs: - TargetType: inline - script: | - $url = "https://api.github.com/repos/$(REPOSITORY)/commits/$(BRANCH)" - $commit = Invoke-RestMethod -Uri $url -Method "GET" - Write-Output "##vso[task.setvariable variable=COMMIT_SHA]$($commit.sha)" - - task: PowerShell@2 displayName: 'Run builds' inputs: targetType: filePath - filePath: './azure-devops/run-ci-builds.ps1' + filePath: './github/run-ci-builds.ps1' arguments: | - -TeamFoundationCollectionUri $(System.TeamFoundationCollectionUri) ` - -AzureDevOpsProjectName $(System.TeamProject) ` - -AzureDevOpsAccessToken $(System.AccessToken) ` - -SourceBranch $(BRANCH) ` - -DefinitionId $(DEFINITION_ID) ` - -SourceVersion $(COMMIT_SHA) ` - -ManifestLink $(MANIFEST_URL) ` - -WaitForBuilds $(WAIT_FOR_BUILDS) ` + -RepositoryFullName $(REPOSITORY_FULL_NAME) ` + -AccessToken $(GITHUB_TOKEN) ` + -WorkflowFileName $(WORKFLOW_FILE_NAME) ` + -WorkflowDispatchRef $(DISPATCH_REF) ` -ToolVersions "$(ToolVersions)" ` - -RetryIntervalSec $(INTERVAL_SEC) ` - -RetryCount $(RETRY_COUNT) + -PublishReleases $(PUPLISH_RELEASES) \ No newline at end of file diff --git a/clean-toolcache.ps1 b/clean-toolcache.ps1 index 67796de..1f61df0 100644 --- a/clean-toolcache.ps1 +++ b/clean-toolcache.ps1 @@ -3,6 +3,11 @@ param ( ) $targetPath = $env:AGENT_TOOLSDIRECTORY +if ([string]::IsNullOrEmpty($targetPath)) { + # GitHub Windows images don't have `AGENT_TOOLSDIRECTORY` variable + $targetPath = $env:RUNNER_TOOL_CACHE +} + if ($ToolName) { $targetPath = Join-Path $targetPath $ToolName } diff --git a/github/create-pull-request.ps1 b/github/create-pull-request.ps1 index 9c01042..a30d4fb 100644 --- a/github/create-pull-request.ps1 +++ b/github/create-pull-request.ps1 @@ -2,10 +2,8 @@ .SYNOPSIS Create commit with all unstaged changes in repository and create pull-request -.PARAMETER RepositoryOwner -Required parameter. The organization which tool repository belongs -.PARAMETER RepositoryName -Optional parameter. The name of tool repository +.PARAMETER RepositoryFullName +Required parameter. The owner and repository name. For example, 'actions/versions-package-tools' .PARAMETER AccessToken Required parameter. PAT Token to authorize .PARAMETER BranchName @@ -18,8 +16,7 @@ Required parameter. The title of pull-request Required parameter. The description of pull-request #> param ( - [Parameter(Mandatory)] [string] $RepositoryOwner, - [Parameter(Mandatory)] [string] $RepositoryName, + [Parameter(Mandatory)] [string] $RepositoryFullName, [Parameter(Mandatory)] [string] $AccessToken, [Parameter(Mandatory)] [string] $BranchName, [Parameter(Mandatory)] [string] $CommitMessage, @@ -46,11 +43,11 @@ function Update-PullRequest { $updatedPullRequest = $GitHubApi.UpdatePullRequest($Title, $Body, $BranchName, $PullRequest.number) - if (($updatedPullRequest -eq $null) -or ($updatedPullRequest.html_url -eq $null)) { - Write-Host "##vso[task.logissue type=error;] Unexpected error occurs while updating pull request." + if (($null -eq $updatedPullRequest) -or ($null -eq $updatedPullRequest.html_url)) { + Write-Host "Unexpected error occurs while updating pull request." exit 1 } - Write-host "##[section] Pull request updated: $($updatedPullRequest.html_url)" + Write-host "Pull request updated: $($updatedPullRequest.html_url)" } function Create-PullRequest { @@ -67,12 +64,12 @@ function Create-PullRequest { $createdPullRequest = $GitHubApi.CreateNewPullRequest($Title, $Body, $BranchName) - if (($createdPullRequest -eq $null) -or ($createdPullRequest.html_url -eq $null)) { - Write-Host "##vso[task.logissue type=error;] Unexpected error occurs while creating pull request." + if (($null -eq $createdPullRequest) -or ($null -eq $createdPullRequest.html_url)) { + Write-Host "Unexpected error occurs while creating pull request." exit 1 } - Write-host "##[section] Pull request created: $($createdPullRequest.html_url)" + Write-host "Pull request created: $($createdPullRequest.html_url)" } Write-Host "Configure local git preferences" @@ -87,8 +84,9 @@ Git-CommitAllChanges -Message $CommitMessage Write-Host "Push branch: $BranchName" Git-PushBranch -Name $BranchName -Force $true -$gitHubApi = Get-GitHubApi -AccountName $RepositoryOwner -ProjectName $RepositoryName -AccessToken $AccessToken -$pullRequest = $gitHubApi.GetPullRequest($BranchName, $RepositoryOwner) +$gitHubApi = Get-GitHubApi -RepositoryFullName $RepositoryFullName -AccessToken $AccessToken +$repositoryOwner = $RepositoryFullName.Split('/')[0] +$pullRequest = $gitHubApi.GetPullRequest($BranchName, $repositoryOwner) if ($pullRequest.Count -gt 0) { Write-Host "Update pull request" diff --git a/github/github-api.psm1 b/github/github-api.psm1 index 4cb0929..aacffb1 100644 --- a/github/github-api.psm1 +++ b/github/github-api.psm1 @@ -5,15 +5,13 @@ The module that contains a bunch of methods to interact with GitHub API V3 class GitHubApi { [string] $BaseUrl - [string] $RepoOwner [object] $AuthHeader GitHubApi( - [string] $AccountName, - [string] $ProjectName, + [string] $RepositoryFullName, [string] $AccessToken ) { - $this.BaseUrl = $this.BuildBaseUrl($AccountName, $ProjectName) + $this.BaseUrl = $this.BuildBaseUrl($RepositoryFullName) $this.AuthHeader = $this.BuildAuth($AccessToken) } @@ -27,8 +25,8 @@ class GitHubApi } } - [string] hidden BuildBaseUrl([string]$RepositoryOwner, [string]$RepositoryName) { - return "https://api.github.com/repos/$RepositoryOwner/$RepositoryName" + [string] hidden BuildBaseUrl([string]$RepositoryFullName) { + return "https://api.github.com/repos/$RepositoryFullName" } [object] CreateNewPullRequest([string]$Title, [string]$Body, [string]$BranchName){ @@ -82,6 +80,35 @@ class GitHubApi return $releases } + [void] DispatchWorkflow([string]$EventType) { + $url = "dispatches" + $body = @{ + event_type = $EventType + } | ConvertTo-Json + + $this.InvokeRestMethod($url, 'POST', $null, $body) + } + + [object] GetWorkflowRuns([string]$WorkflowFileName) { + $url = "actions/workflows/$WorkflowFileName/runs" + return $this.InvokeRestMethod($url, 'GET', $null, $null) + } + + [object] GetWorkflowRunJobs([string]$WorkflowRunId) { + $url = "actions/runs/$WorkflowRunId/jobs" + return $this.InvokeRestMethod($url, 'GET', $null, $null) + } + + [void] CreateWorkflowDispatch([string]$WorkflowFileName, [string]$Ref, [object]$Inputs) { + $url = "actions/workflows/${WorkflowFileName}/dispatches" + $body = @{ + ref = $Ref + inputs = $Inputs + } | ConvertTo-Json + + $this.InvokeRestMethod($url, 'POST', $null, $body) + } + [string] hidden BuildUrl([string]$Url, [string]$RequestParams) { if ([string]::IsNullOrEmpty($RequestParams)) { return "$($this.BaseUrl)/$($Url)" @@ -117,10 +144,9 @@ class GitHubApi function Get-GitHubApi { param ( - [string] $AccountName, - [string] $ProjectName, + [string] $RepositoryFullName, [string] $AccessToken ) - return [GitHubApi]::New($AccountName, $ProjectName, $AccessToken) + return [GitHubApi]::New($RepositoryFullName, $AccessToken) } \ No newline at end of file diff --git a/github/run-ci-builds.ps1 b/github/run-ci-builds.ps1 new file mode 100644 index 0000000..e4b8a03 --- /dev/null +++ b/github/run-ci-builds.ps1 @@ -0,0 +1,91 @@ +<# +.SYNOPSIS +Trigger runs on the workflow_dispatch event to build and upload tool packages + +.PARAMETER RepositoryFullName +Required parameter. The owner and repository name. For example, 'actions/versions-package-tools' +.PARAMETER AccessToken +Required parameter. PAT Token to authorize +.PARAMETER WorkflowFileName +Required parameter. The name of workflow file that will be triggered +.PARAMETER WorkflowDispatchRef +Required parameter. The reference of the workflow run. The reference can be a branch, tag, or a commit SHA. +.PARAMETER ToolVersions +Required parameter. List of tool versions to build and upload +.PARAMETER PublishReleases +Required parameter. Whether to publish releases, true or false +#> + +param ( + [Parameter(Mandatory)] [string] $RepositoryFullName, + [Parameter(Mandatory)] [string] $AccessToken, + [Parameter(Mandatory)] [string] $WorkflowFileName, + [Parameter(Mandatory)] [string] $WorkflowDispatchRef, + [Parameter(Mandatory)] [string] $ToolVersions, + [Parameter(Mandatory)] [string] $PublishReleases +) + +Import-Module (Join-Path $PSScriptRoot "github-api.psm1") + +function Get-WorkflowRunLink { + param( + [Parameter(Mandatory)] [object] $GitHubApi, + [Parameter(Mandatory)] [string] $WorkflowFileName, + [Parameter(Mandatory)] [string] $ToolVersion + ) + + $listWorkflowRuns = $GitHubApi.GetWorkflowRuns($WorkflowFileName).workflow_runs | Sort-Object -Property 'run_number' -Descending + + foreach ($workflowRun in $listWorkflowRuns) { + $workflowRunJob = $gitHubApi.GetWorkflowRunJobs($workflowRun.id).jobs | Select-Object -First 1 + + if ($workflowRunJob.name -match $ToolVersion) { + return $workflowRun.html_url + } + } + + return $null +} + +function Queue-Builds { + param ( + [Parameter(Mandatory)] [object] $GitHubApi, + [Parameter(Mandatory)] [string] $ToolVersions, + [Parameter(Mandatory)] [string] $WorkflowFileName, + [Parameter(Mandatory)] [string] $WorkflowDispatchRef, + [Parameter(Mandatory)] [string] $PublishReleases + ) + + $inputs = @{ + PUBLISH_RELEASES = $PublishReleases + } + + $ToolVersions.Split(',') | ForEach-Object { + $version = $_.Trim() + $inputs.VERSION = $version + + Write-Host "Queue build for $version..." + $GitHubApi.CreateWorkflowDispatch($WorkflowFileName, $WorkflowDispatchRef, $inputs) + + Start-Sleep -s 10 + $workflowRunLink = Get-WorkflowRunLink -GitHubApi $GitHubApi ` + -WorkflowFileName $WorkflowFileName ` + -ToolVersion $version + + if (-not $workflowRunLink) { + Write-Host "Could not find build for $version..." + exit 1 + } + + Write-Host "Link to the build: $workflowRunLink" + } +} + +$gitHubApi = Get-GitHubApi -RepositoryFullName $RepositoryFullName -AccessToken $AccessToken + +Write-Host "Versions to build: $ToolVersions" +Queue-Builds -GitHubApi $gitHubApi ` + -ToolVersions $ToolVersions ` + -WorkflowFileName $WorkflowFileName ` + -WorkflowDispatchRef $WorkflowDispatchRef ` + -PublishReleases $PublishReleases diff --git a/packages-generation/manifest-generator.ps1 b/packages-generation/manifest-generator.ps1 index a1d8397..75acd89 100644 --- a/packages-generation/manifest-generator.ps1 +++ b/packages-generation/manifest-generator.ps1 @@ -1,13 +1,10 @@ <# .SYNOPSIS Generate versions manifest based on repository releases - .DESCRIPTION Versions manifest is needed to find the latest assets for particular version of tool -.PARAMETER GitHubRepositoryOwner -Required parameter. The organization which tool repository belongs -.PARAMETER GitHubRepositoryName -Required parameter. The name of tool repository +.PARAMETER RepositoryFullName +Required parameter. The owner and repository name. For example, 'actions/versions-package-tools' .PARAMETER GitHubAccessToken Required parameter. PAT Token to overcome GitHub API Rate limit .PARAMETER OutputFile @@ -17,8 +14,7 @@ Path to the json file with parsing configuration #> param ( - [Parameter(Mandatory)] [string] $GitHubRepositoryOwner, - [Parameter(Mandatory)] [string] $GitHubRepositoryName, + [Parameter(Mandatory)] [string] $RepositoryFullName, [Parameter(Mandatory)] [string] $GitHubAccessToken, [Parameter(Mandatory)] [string] $OutputFile, [Parameter(Mandatory)] [string] $ConfigurationFile @@ -29,7 +25,7 @@ Import-Module (Join-Path $PSScriptRoot "manifest-utils.psm1") -Force $configuration = Read-ConfigurationFile -Filepath $ConfigurationFile -$gitHubApi = Get-GitHubApi -AccountName $GitHubRepositoryOwner -ProjectName $GitHubRepositoryName -AccessToken $GitHubAccessToken +$gitHubApi = Get-GitHubApi -RepositoryFullName $RepositoryFullName -AccessToken $GitHubAccessToken $releases = $gitHubApi.GetReleases() $versionIndex = Build-VersionsManifest -Releases $releases -Configuration $configuration $versionIndex | ConvertTo-Json -Depth 5 | Out-File $OutputFile -Encoding UTF8NoBOM -Force