mirror of https://github.com/abpframework/abp
				
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							347 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
	
	
							347 lines
						
					
					
						
							12 KiB
						
					
					
				#Requires -Version 3.0
 | 
						|
 | 
						|
function New-GitHubRelease
 | 
						|
{
 | 
						|
<#
 | 
						|
	.SYNOPSIS
 | 
						|
	Creates a new Release for the given GitHub repository.
 | 
						|
 | 
						|
	.DESCRIPTION
 | 
						|
	Uses the GitHub API to create a new Release for a given repository.
 | 
						|
	Allows you to specify all of the Release properties, such as the Tag, Name, Assets, and if it's a Draft or Prerelease or not.
 | 
						|
 | 
						|
	.PARAMETER GitHubUsername
 | 
						|
	The username that the GitHub repository exists under.
 | 
						|
	e.g. For the repository https://github.com/deadlydog/New-GitHubRelease, the username is 'deadlydog'.
 | 
						|
 | 
						|
	.PARAMETER GitHubRepositoryName
 | 
						|
	The name of the repository to create the Release for.
 | 
						|
	e.g. For the repository https://github.com/deadlydog/New-GitHubRelease, the repository name is 'New-GitHubRelease'.
 | 
						|
 | 
						|
	.PARAMETER GitHubAccessToken
 | 
						|
	The Access Token to use as credentials for GitHub.
 | 
						|
	Access tokens can be generated at https://github.com/settings/tokens.
 | 
						|
	The access token will need to have the repo/public_repo permission on it for it to be allowed to create a new Release.
 | 
						|
 | 
						|
	.PARAMETER TagName
 | 
						|
	The name of the tag to create at the Commitish.
 | 
						|
 | 
						|
	.PARAMETER ReleaseName
 | 
						|
	The name to use for the new release.
 | 
						|
	If blank, the TagName will be used.
 | 
						|
 | 
						|
	.PARAMETER ReleaseNotes
 | 
						|
	The text describing the contents of the release.
 | 
						|
 | 
						|
	.PARAMETER AssetFilePaths
 | 
						|
	The full paths of the files to include in the release.
 | 
						|
 | 
						|
	.PARAMETER Commitish
 | 
						|
	Specifies the commitish value that determines where the Git tag is created from.
 | 
						|
	Can be any branch or commit SHA. Unused if the Git tag already exists.
 | 
						|
	Default: the repository's default branch (usually master).
 | 
						|
 | 
						|
	.PARAMETER IsDraft
 | 
						|
	True to create a draft (unpublished) release, false to create a published one.
 | 
						|
	Default: false
 | 
						|
 | 
						|
	.PARAMETER IsPreRelease
 | 
						|
	True to identify the release as a prerelease. false to identify the release as a full release.
 | 
						|
	Default: false
 | 
						|
 | 
						|
	.OUTPUTS
 | 
						|
	A hash table with the following properties is returned:
 | 
						|
 | 
						|
	Succeeded = $true if the Release was created successfully and all assets were uploaded to it, $false if some part of the process failed.
 | 
						|
	ReleaseCreationSucceeded = $true if the Release was created successfully (does not include asset uploads), $false if the Release was not created.
 | 
						|
	AllAssetUploadsSucceeded = $true if all assets were uploaded to the Release successfully, $false if one of them failed, $null if there were no assets to upload.
 | 
						|
	ReleaseUrl = The URL of the new Release that was created.
 | 
						|
	ErrorMessage = A message describing what went wrong in the case that Succeeded is $false.
 | 
						|
 | 
						|
	.EXAMPLE
 | 
						|
	# Import the module dynamically from the PowerShell Gallery. Use CurrentUser scope to avoid having to run as admin.
 | 
						|
	Import-Module -Name New-GitHubRelease -Scope CurrentUser
 | 
						|
 | 
						|
	# Specify the parameters required to create the release. Do it as a hash table for easier readability.
 | 
						|
	$newGitHubReleaseParameters =
 | 
						|
	@{
 | 
						|
		GitHubUsername = 'deadlydog'
 | 
						|
		GitHubRepositoryName = 'New-GitHubRelease'
 | 
						|
		GitHubAccessToken = 'SomeLongHexidecimalString'
 | 
						|
		ReleaseName = "New-GitHubRelease v1.0.0"
 | 
						|
		TagName = "v1.0.0"
 | 
						|
		ReleaseNotes = "This release contains the following changes: ..."
 | 
						|
		AssetFilePaths = @('C:\MyProject\Installer.exe','C:\MyProject\Documentation.md')
 | 
						|
		IsPreRelease = $false
 | 
						|
		IsDraft = $true	# Set to true when testing so we don't publish a real release (visible to everyone) by accident.
 | 
						|
	}
 | 
						|
 | 
						|
	# Try to create the Release on GitHub and save the results.
 | 
						|
	$result = New-GitHubRelease @newGitHubReleaseParameters
 | 
						|
 | 
						|
	# Provide some feedback to the user based on the results.
 | 
						|
	if ($result.Succeeded -eq $true)
 | 
						|
	{
 | 
						|
		Write-Output "Release published successfully! View it at $($result.ReleaseUrl)"
 | 
						|
	}
 | 
						|
	elseif ($result.ReleaseCreationSucceeded -eq $false)
 | 
						|
	{
 | 
						|
		Write-Error "The release was not created. Error message is: $($result.ErrorMessage)"
 | 
						|
	}
 | 
						|
	elseif ($result.AllAssetUploadsSucceeded -eq $false)
 | 
						|
	{
 | 
						|
		Write-Error "The release was created, but not all of the assets were uploaded to it. View it at $($result.ReleaseUrl). Error message is: $($result.ErrorMessage)"
 | 
						|
	}
 | 
						|
 | 
						|
	Attempt to create a new Release on GitHub, and provide feedback to the user indicating if it succeeded or not.
 | 
						|
 | 
						|
	.LINK
 | 
						|
	Project home: https://github.com/deadlydog/New-GitHubRelease
 | 
						|
 | 
						|
	.NOTES
 | 
						|
	Name:   New-GitHubRelease
 | 
						|
	Author: Daniel Schroeder (originally based on the script at https://github.com/majkinetor/au/blob/master/scripts/Github-CreateRelease.ps1)
 | 
						|
	GitHub Release API Documentation: https://developer.github.com/v3/repos/releases/#create-a-release
 | 
						|
	Version: 1.0.2
 | 
						|
#>
 | 
						|
	[CmdletBinding()]
 | 
						|
	param
 | 
						|
	(
 | 
						|
		[Parameter(Mandatory=$true,HelpMessage="The username the repository is under (e.g. deadlydog).")]
 | 
						|
		[string] $GitHubUsername,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$true,HelpMessage="The repository name to create the release in (e.g. Invoke-MsBuild).")]
 | 
						|
		[string] $GitHubRepositoryName,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$true,HelpMessage="The Acess Token to use as credentials for GitHub.")]
 | 
						|
		[string] $GitHubAccessToken,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$true,HelpMessage="The name of the tag to create at the the Commitish.")]
 | 
						|
		[string] $TagName,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$false,HelpMessage="The name of the release. If blank, the TagName will be used.")]
 | 
						|
		[string] $ReleaseName,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$false,HelpMessage="Text describing the contents of the tag.")]
 | 
						|
		[string] $ReleaseNotes,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$false,HelpMessage="The full paths of the files to include in the release.")]
 | 
						|
		[string[]] $AssetFilePaths,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$false, HelpMessage="Specifies the commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Unused if the Git tag already exists. Default: the repository's default branch (usually master).")]
 | 
						|
		[string] $Commitish,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$false,HelpMessage="True to create a draft (unpublished) release, false to create a published one. Default: false")]
 | 
						|
		[bool] $IsDraft = $false,
 | 
						|
 | 
						|
		[Parameter(Mandatory=$false,HelpMessage="True to identify the release as a prerelease. false to identify the release as a full release. Default: false")]
 | 
						|
		[bool] $IsPreRelease = $false
 | 
						|
	)
 | 
						|
 | 
						|
	BEGIN
 | 
						|
	{
 | 
						|
		# Turn on Strict Mode to help catch syntax-related errors.
 | 
						|
		# 	This must come after a script's/function's param section.
 | 
						|
		# 	Forces a function to be the first non-comment code to appear in a PowerShell Script/Module.
 | 
						|
		Set-StrictMode -Version Latest
 | 
						|
 | 
						|
		Set-SecurityProtocolForThread
 | 
						|
 | 
						|
		[string] $NewLine = [Environment]::NewLine
 | 
						|
 | 
						|
		if ([string]::IsNullOrEmpty($ReleaseName))
 | 
						|
		{
 | 
						|
			$ReleaseName = $TagName
 | 
						|
		}
 | 
						|
 | 
						|
		# Ensure that all of the given asset file paths to upload are valid.
 | 
						|
		Test-AllFilePathsAndThrowErrorIfOneIsNotValid $AssetFilePaths
 | 
						|
	}
 | 
						|
 | 
						|
	END { }
 | 
						|
 | 
						|
	PROCESS
 | 
						|
	{
 | 
						|
		# Create the hash table to return, with default values.
 | 
						|
		$result = @{}
 | 
						|
		$result.Succeeded = $false
 | 
						|
		$result.ReleaseCreationSucceeded = $false
 | 
						|
		$result.AllAssetUploadsSucceeded = $false
 | 
						|
		$result.ReleaseUrl = $null
 | 
						|
		$result.ErrorMessage = $null
 | 
						|
 | 
						|
		[bool] $thereAreNoAssetsToIncludeInTheRelease = ($AssetFilePaths -eq $null) -or ($AssetFilePaths.Count -le 0)
 | 
						|
		if ($thereAreNoAssetsToIncludeInTheRelease)
 | 
						|
		{
 | 
						|
			$result.AllAssetUploadsSucceeded = $null
 | 
						|
		}
 | 
						|
 | 
						|
		$authHeader =
 | 
						|
		@{
 | 
						|
			Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($GitHubAccessToken + ":x-oauth-basic"))
 | 
						|
		}
 | 
						|
 | 
						|
		$releaseData =
 | 
						|
		@{
 | 
						|
			tag_name         = $TagName
 | 
						|
			target_commitish = $Commitish
 | 
						|
			name             = $ReleaseName
 | 
						|
			body             = $ReleaseNotes
 | 
						|
			draft            = $IsDraft
 | 
						|
			prerelease       = $IsPreRelease
 | 
						|
		}
 | 
						|
 | 
						|
		$createReleaseWebRequestParameters =
 | 
						|
		@{
 | 
						|
			Uri         = "https://api.github.com/repos/$GitHubUsername/$GitHubRepositoryName/releases"
 | 
						|
			Method      = 'POST'
 | 
						|
			Headers     = $authHeader
 | 
						|
			ContentType = 'application/json'
 | 
						|
			Body        = (ConvertTo-Json $releaseData -Compress)
 | 
						|
		}
 | 
						|
 | 
						|
		try
 | 
						|
		{
 | 
						|
			Write-Verbose "Sending web request to create the new Release..."
 | 
						|
			$createReleaseWebRequestResults = Invoke-RestMethodAndThrowDescriptiveErrorOnFailure $createReleaseWebRequestParameters
 | 
						|
		}
 | 
						|
		catch
 | 
						|
		{
 | 
						|
			$result.ReleaseCreationSucceeded = $false
 | 
						|
			$result.ErrorMessage = $_.Exception.Message
 | 
						|
			return $result
 | 
						|
		}
 | 
						|
 | 
						|
		$result.ReleaseCreationSucceeded = $true
 | 
						|
		$result.ReleaseUrl = $createReleaseWebRequestResults.html_url
 | 
						|
 | 
						|
		if ($thereAreNoAssetsToIncludeInTheRelease)
 | 
						|
		{
 | 
						|
			$result.Succeeded = $true
 | 
						|
			return $result
 | 
						|
		}
 | 
						|
 | 
						|
		# Upload Url has template parameters on the end (e.g. ".../assets{?name,label}"), so remove them.
 | 
						|
		[string] $urlToUploadFilesTo = $createReleaseWebRequestResults.upload_url -replace '{.+}'
 | 
						|
 | 
						|
		try
 | 
						|
		{
 | 
						|
			Write-Verbose "Uploading asset files to the new release..."
 | 
						|
			Send-FilesToGitHubRelease -filePathsToUpload $AssetFilePaths -urlToUploadFilesTo $urlToUploadFilesTo -authHeader $authHeader
 | 
						|
		}
 | 
						|
		catch
 | 
						|
		{
 | 
						|
			$result.AllAssetUploadsSucceeded = $false
 | 
						|
			$result.ErrorMessage = $_.Exception.Message
 | 
						|
			return $result
 | 
						|
		}
 | 
						|
 | 
						|
		$result.AllAssetUploadsSucceeded = $true
 | 
						|
		$result.Succeeded = $true
 | 
						|
		return $result
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function Send-FilesToGitHubRelease([string[]] $filePathsToUpload, [string] $urlToUploadFilesTo, $authHeader)
 | 
						|
{
 | 
						|
	[int] $numberOfFilesToUpload = $filePathsToUpload.Count
 | 
						|
	[int] $numberOfFilesUploaded = 0
 | 
						|
	$filePathsToUpload | ForEach-Object `
 | 
						|
	{
 | 
						|
		$filePath = $_
 | 
						|
		$fileName = Get-Item $filePath | Select-Object -ExpandProperty Name
 | 
						|
 | 
						|
		$uploadAssetWebRequestParameters =
 | 
						|
		@{
 | 
						|
			# Append the name of the file to the upload url.
 | 
						|
			Uri         = $urlToUploadFilesTo + "?name=$fileName"
 | 
						|
			Method      = 'POST'
 | 
						|
			Headers     = $authHeader
 | 
						|
			ContentType = 'application/zip'
 | 
						|
			InFile      = $filePath
 | 
						|
		}
 | 
						|
 | 
						|
		$numberOfFilesUploaded = $numberOfFilesUploaded + 1
 | 
						|
		Write-Verbose "Uploading asset $numberOfFilesUploaded of $numberOfFilesToUpload, '$filePath'."
 | 
						|
		Invoke-RestMethodAndThrowDescriptiveErrorOnFailure $uploadAssetWebRequestParameters > $null
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function Test-AllFilePathsAndThrowErrorIfOneIsNotValid([string[]] $filePaths)
 | 
						|
{
 | 
						|
	foreach ($filePath in $filePaths)
 | 
						|
	{
 | 
						|
		[bool] $fileWasNotFoundAtPath = [string]::IsNullOrEmpty($filePath) -or !(Test-Path -Path $filePath -PathType Leaf)
 | 
						|
		if ($fileWasNotFoundAtPath)
 | 
						|
		{
 | 
						|
			throw "There is no file at the specified path, '$filePath'."
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function Invoke-RestMethodAndThrowDescriptiveErrorOnFailure($requestParametersHashTable)
 | 
						|
{
 | 
						|
	$requestDetailsAsNicelyFormattedString = Convert-HashTableToNicelyFormattedString $requestParametersHashTable
 | 
						|
	Write-Verbose "Making web request with the following parameters:$NewLine$requestDetailsAsNicelyFormattedString"
 | 
						|
 | 
						|
	try
 | 
						|
	{
 | 
						|
		$webRequestResult = Invoke-RestMethod @requestParametersHashTable
 | 
						|
	}
 | 
						|
	catch
 | 
						|
	{
 | 
						|
		[Exception] $exception = $_.Exception
 | 
						|
 | 
						|
		[string] $errorMessage = Get-RestMethodExceptionDetailsOrNull -restMethodException $exception
 | 
						|
		if ([string]::IsNullOrWhiteSpace($errorMessage))
 | 
						|
		{
 | 
						|
			$errorMessage = $exception.ToString()
 | 
						|
		}
 | 
						|
 | 
						|
		throw "An unexpected error occurred while making web request:$NewLine$errorMessage"
 | 
						|
	}
 | 
						|
 | 
						|
	Write-Verbose "Web request returned the following result:$NewLine$webRequestResult"
 | 
						|
	return $webRequestResult
 | 
						|
}
 | 
						|
 | 
						|
function Get-RestMethodExceptionDetailsOrNull([Exception] $restMethodException)
 | 
						|
{
 | 
						|
	try
 | 
						|
	{
 | 
						|
		$responseDetails = @{
 | 
						|
			ResponseUri = $exception.Response.ResponseUri
 | 
						|
			StatusCode = $exception.Response.StatusCode
 | 
						|
			StatusDescription = $exception.Response.StatusDescription
 | 
						|
			ErrorMessage = $exception.Message
 | 
						|
		}
 | 
						|
		[string] $responseDetailsAsNicelyFormattedString = Convert-HashTableToNicelyFormattedString $responseDetails
 | 
						|
 | 
						|
		[string] $errorInfo = "Request Details:" + $NewLine + $requestDetailsAsNicelyFormattedString
 | 
						|
		$errorInfo += $NewLine
 | 
						|
		$errorInfo += "Response Details:" + $NewLine + $responseDetailsAsNicelyFormattedString
 | 
						|
		return $errorInfo
 | 
						|
	}
 | 
						|
	catch
 | 
						|
	{
 | 
						|
		return $null
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function Convert-HashTableToNicelyFormattedString($hashTable)
 | 
						|
{
 | 
						|
	[string] $nicelyFormattedString = $hashTable.Keys | ForEach-Object `
 | 
						|
	{
 | 
						|
		$key = $_
 | 
						|
		$value = $hashTable.$key
 | 
						|
		"  $key = $value$NewLine"
 | 
						|
	}
 | 
						|
	return $nicelyFormattedString
 | 
						|
}
 | 
						|
 | 
						|
function Set-SecurityProtocolForThread
 | 
						|
{
 | 
						|
	[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls
 | 
						|
}
 | 
						|
 | 
						|
Export-ModuleMember -Function New-GitHubRelease |