From 356af2f5b69fa8cd60bc77670d250cde796ac1d6 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Mon, 20 Jul 2020 08:48:48 -0700 Subject: [PATCH] Complete support for Releases API (#177) This completes the required work to support the set of Releases API's. It adds the following functions: * `New-GitHubRelease` * `Set-GitHubRelease` * `Remove-GitHubRelease` * `Get-GitHubReleaseAsset` * `New-GitHubReleaseAsset` * `Set-GitHubReleaseAsset` * `Remove-GitHubReleaseAsset` `Invoke-GHRestMethod` has been updated to be able to upload a file (via the new `InFile` parameter) and download a file (via the `Save` switch which will cause it to return back a `FileInfo` object of a temporary file which can then be renamed as seen fit by the caller). This also adds formatters for `GitHub.Release` and `GitHub.ReleaseAsset`. Positional Binding has been set as `false` for the three functions, and `Position` attributes added to the function's mandatory parameters. Reference: [GitHub Releases](https://developer.github.com/v3/repos/releases/) Fixes #47 Fixes #110 --- Formatters/GitHubReleases.Format.ps1xml | 135 +++ GitHubAssignees.ps1 | 4 + GitHubBranches.ps1 | 1 + GitHubContents.ps1 | 1 + GitHubCore.ps1 | 239 +++- GitHubEvents.ps1 | 1 + GitHubIssueComments.ps1 | 4 + GitHubIssues.ps1 | 6 + GitHubLabels.ps1 | 8 + GitHubMilestones.ps1 | 4 + GitHubMiscellaneous.ps1 | 2 + GitHubProjects.ps1 | 4 + GitHubPullRequests.ps1 | 2 + GitHubReleases.ps1 | 1337 ++++++++++++++++++++++- GitHubRepositories.ps1 | 12 + GitHubRepositoryForks.ps1 | 2 + GitHubRepositoryTraffic.ps1 | 4 + GitHubTeams.ps1 | 2 + Helpers.ps1 | 11 +- PowerShellForGitHub.psd1 | 17 +- Tests/GitHubReleases.tests.ps1 | 1091 ++++++++++++++++-- USAGE.md | 145 +++ 22 files changed, 2887 insertions(+), 145 deletions(-) create mode 100644 Formatters/GitHubReleases.Format.ps1xml diff --git a/Formatters/GitHubReleases.Format.ps1xml b/Formatters/GitHubReleases.Format.ps1xml new file mode 100644 index 00000000..e5e9bc78 --- /dev/null +++ b/Formatters/GitHubReleases.Format.ps1xml @@ -0,0 +1,135 @@ + + + + + + GitHub.Release + + GitHub.Release + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id + + + name + + + tag_name + + + target_commitish + + + draft + + + prerelease + + + created_at + + + published_at + + + + + + + + + GitHub.ReleaseAsset + + GitHub.ReleaseAsset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id + + + name + + + label + + + size + + + content_type + + + download_count + + + created_at + + + updated_at + + + + + + + + diff --git a/GitHubAssignees.ps1 b/GitHubAssignees.ps1 index 6bee8221..3f3fbb06 100644 --- a/GitHubAssignees.ps1 +++ b/GitHubAssignees.ps1 @@ -46,6 +46,7 @@ filter Get-GitHubAssignee GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository GitHub.User @@ -159,6 +160,7 @@ filter Test-GitHubAssignee GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository GitHub.User @@ -303,6 +305,7 @@ function Add-GitHubAssignee GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository GitHub.User @@ -481,6 +484,7 @@ function Remove-GitHubAssignee GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubBranches.ps1 b/GitHubBranches.ps1 index 41e5b100..502a785d 100644 --- a/GitHubBranches.ps1 +++ b/GitHubBranches.ps1 @@ -58,6 +58,7 @@ filter Get-GitHubRepositoryBranch GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubContents.ps1 b/GitHubContents.ps1 index 53397540..85b290f8 100644 --- a/GitHubContents.ps1 +++ b/GitHubContents.ps1 @@ -73,6 +73,7 @@ GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index 0bfd7f5d..02c887fd 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -29,17 +29,17 @@ function Invoke-GHRestMethod { <# .SYNOPSIS - A wrapper around Invoke-WebRequest that understands the Store API. + A wrapper around Invoke-WebRequest that understands the GitHub API. .DESCRIPTION - A very heavy wrapper around Invoke-WebRequest that understands the Store API and + A very heavy wrapper around Invoke-WebRequest that understands the GitHub API and how to perform its operation with and without console status updates. It also understands how to parse and handle errors from the REST calls. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub .PARAMETER UriFragment - The unique, tail-end, of the REST URI that indicates what Store REST action will + The unique, tail-end, of the REST URI that indicates what GitHub REST action will be performed. This should not start with a leading "/". .PARAMETER Method @@ -58,10 +58,22 @@ function Invoke-GHRestMethod Specify the media type in the Accept header. Different types of commands may require different media types. + .PARAMETER InFile + Gets the content of the web request from the specified file. Only valid for POST requests. + + .PARAMETER ContentType + Specifies the value for the MIME Content-Type header of the request. This will usually + be configured correctly automatically. You should only specify this under advanced + situations (like if the extension of InFile is of a type unknown to this module). + .PARAMETER ExtendedResult If specified, the result will be a PSObject that contains the normal result, along with the response code and other relevant header detail content. + .PARAMETER Save + If specified, this will save the result to a temporary file and return the FileInfo of that + temporary file. + .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api as opposed to requesting a new one. @@ -90,6 +102,7 @@ function Invoke-GHRestMethod .OUTPUTS [PSCustomObject] - The result of the REST operation, in whatever form it comes in. + [FileInfo] - The temporary file created for the downloaded file if -Save was specified. .EXAMPLE Invoke-GHRestMethod -UriFragment "users/octocat" -Method Get -Description "Get information on the octocat user" @@ -120,8 +133,15 @@ function Invoke-GHRestMethod [string] $AcceptHeader = $script:defaultAcceptHeader, + [ValidateNotNullOrEmpty()] + [string] $InFile, + + [string] $ContentType = $script:defaultJsonBodyContentType, + [switch] $ExtendedResult, + [switch] $Save, + [string] $AccessToken, [string] $TelemetryEventName = $null, @@ -135,6 +155,32 @@ function Invoke-GHRestMethod Invoke-UpdateCheck + # Minor error checking around $InFile + if ($PSBoundParameters.ContainsKey('InFile') -and ($Method -ne 'Post')) + { + $message = '-InFile may only be specified with Post requests.' + Write-Log -Message $message -Level Error + throw $message + } + + if ($PSBoundParameters.ContainsKey('InFile') -and (-not [String]::IsNullOrWhiteSpace($Body))) + { + $message = 'Cannot specify BOTH InFile and Body' + Write-Log -Message $message -Level Error + throw $message + } + + if ($PSBoundParameters.ContainsKey('InFile')) + { + $InFile = Resolve-UnverifiedPath -Path $InFile + if (-not (Test-Path -Path $InFile -PathType Leaf)) + { + $message = "Specified file [$InFile] does not exist or is inaccessible." + Write-Log -Message $message -Level Error + throw $message + } + } + # Normalize our Uri fragment. It might be coming from a method implemented here, or it might # be coming from the Location header in a previous response. Either way, we don't want there # to be a leading "/" or trailing '/' @@ -191,7 +237,23 @@ function Invoke-GHRestMethod if ($Method -in $ValidBodyContainingRequestMethods) { - $headers.Add("Content-Type", "application/json; charset=UTF-8") + if ($PSBoundParameters.ContainsKey('InFile') -and [String]::IsNullOrWhiteSpace($ContentType)) + { + $file = Get-Item -Path $InFile + $localTelemetryProperties['FileExtension'] = $file.Extension + + if ($script:extensionToContentType.ContainsKey($file.Extension)) + { + $ContentType = $script:extensionToContentType[$file.Extension] + } + else + { + $localTelemetryProperties['UnknownExtension'] = $file.Extension + $ContentType = $script:defaultInFileContentType + } + } + + $headers.Add("Content-Type", $ContentType) } if (-not $PSCmdlet.ShouldProcess($url, "Invoke-WebRequest")) @@ -201,6 +263,13 @@ function Invoke-GHRestMethod $originalSecurityProtocol = [Net.ServicePointManager]::SecurityProtocol + # When $Save is in use, we need to remember what file we're saving the result to. + $outFile = [String]::Empty + if ($Save) + { + $outFile = New-TemporaryFile + } + try { Write-Log -Message $Description -Level Verbose @@ -214,8 +283,10 @@ function Invoke-GHRestMethod $params.Add("UseDefaultCredentials", $true) $params.Add("UseBasicParsing", $true) $params.Add("TimeoutSec", (Get-GitHubConfiguration -Name WebRequestTimeoutSec)) + if ($PSBoundParameters.ContainsKey('InFile')) { $params.Add('InFile', $InFile) } + if (-not [String]::IsNullOrWhiteSpace($outFile)) { $params.Add('OutFile', $outFile) } - if ($Method -in $ValidBodyContainingRequestMethods -and (-not [String]::IsNullOrEmpty($Body))) + if (($Method -in $ValidBodyContainingRequestMethods) -and (-not [String]::IsNullOrEmpty($Body))) { $bodyAsBytes = [System.Text.Encoding]::UTF8.GetBytes($Body) $params.Add("Body", $bodyAsBytes) @@ -230,6 +301,7 @@ function Invoke-GHRestMethod $ProgressPreference = 'SilentlyContinue' [Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12 + $result = Invoke-WebRequest @params if ($Method -eq 'Delete') @@ -248,7 +320,14 @@ function Invoke-GHRestMethod $finalResult = $result.Content try { - $finalResult = $finalResult | ConvertFrom-Json + if ($Save) + { + $finalResult = Get-Item -Path $outFile + } + else + { + $finalResult = $finalResult | ConvertFrom-Json + } } catch [ArgumentException] { @@ -258,7 +337,7 @@ function Invoke-GHRestMethod $finalResult = $finalResult } - if (-not (Get-GitHubConfiguration -Name DisableSmarterObjects)) + if ((-not $Save) -and (-not (Get-GitHubConfiguration -Name DisableSmarterObjects))) { # In the case of getting raw content from the repo, we'll end up with a large object/byte # array which isn't convertible to a smarter object, but by _trying_ we'll end up wasting @@ -273,28 +352,31 @@ function Invoke-GHRestMethod } } - $links = $result.Headers['Link'] -split ',' - $nextLink = $null - $nextPageNumber = 1 - $numPages = 1 - $since = 0 - foreach ($link in $links) + if ($result.Headers.Count -gt 0) { - if ($link -match '<(.*page=(\d+)[^\d]*)>; rel="next"') - { - $nextLink = $Matches[1] - $nextPageNumber = [int]$Matches[2] - } - elseif ($link -match '<(.*since=(\d+)[^\d]*)>; rel="next"') + $links = $result.Headers['Link'] -split ',' + $nextLink = $null + $nextPageNumber = 1 + $numPages = 1 + $since = 0 + foreach ($link in $links) { - # Special case scenario for the users endpoint. - $nextLink = $Matches[1] - $since = [int]$Matches[2] - $numPages = 0 # Signifies an unknown number of pages. - } - elseif ($link -match '<.*page=(\d+)[^\d]+rel="last"') - { - $numPages = [int]$Matches[1] + if ($link -match '<(.*page=(\d+)[^\d]*)>; rel="next"') + { + $nextLink = $Matches[1] + $nextPageNumber = [int]$Matches[2] + } + elseif ($link -match '<(.*since=(\d+)[^\d]*)>; rel="next"') + { + # Special case scenario for the users endpoint. + $nextLink = $Matches[1] + $since = [int]$Matches[2] + $numPages = 0 # Signifies an unknown number of pages. + } + elseif ($link -match '<.*page=(\d+)[^\d]+rel="last"') + { + $numPages = [int]$Matches[1] + } } } @@ -480,7 +562,7 @@ function Invoke-GHRestMethodMultipleResult The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub .PARAMETER UriFragment - The unique, tail-end, of the REST URI that indicates what Store REST action will + The unique, tail-end, of the REST URI that indicates what GitHub REST action will be performed. This should *not* include the 'top' and 'max' parameters. These will be automatically added as needed. @@ -1045,3 +1127,104 @@ function Get-MediaAcceptHeader return $resultHeaders } + +@{ + defaultJsonBodyContentType = 'application/json; charset=UTF-8' + defaultInFileContentType = 'text/plain' + + # Compiled mostly from https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types + extensionToContentType = @{ + '.3gp' = 'video/3gpp' # 3GPP audio/video container + '.3g2' = 'video/3gpp2' # 3GPP2 audio/video container + '.7z' = 'application/x-7z-compressed' # 7-zip archive + '.aac' = 'audio/aac' # AAC audio + '.abw' = 'application/x-abiword' # AbiWord document + '.arc' = 'application/x-freearc' # Archive document (multiple files embedded) + '.avi' = 'video/x-msvideo' # AVI: Audio Video Interleave + '.azw' = 'application/vnd.amazon.ebook' # Amazon Kindle eBook format + '.bin' = 'application/octet-stream' # Any kind of binary data + '.bmp' = 'image/bmp' # Windows OS/2 Bitmap Graphics + '.bz' = 'application/x-bzip' # BZip archive + '.bz2' = 'application/x-bzip2' # BZip2 archive + '.csh' = 'application/x-csh' # C-Shell script + '.css' = 'text/css' # Cascading Style Sheets (CSS) + '.csv' = 'text/csv' # Comma-separated values (CSV) + '.deb' = 'application/octet-stream' # Standard Uix archive format + '.doc' = 'application/msword' # Microsoft Word + '.docx' = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' # Microsoft Word (OpenXML) + '.eot' = 'application/vnd.ms-fontobject' # MS Embedded OpenType fonts + '.epub' = 'application/epub+zip' # Electronic publication (EPUB) + '.exe' = 'application/vnd.microsoft.portable-executable' # Microsoft application executable + '.gz' = 'application/x-gzip' # GZip Compressed Archive + '.gif' = 'image/gif' # Graphics Interchange Format (GIF) + '.htm' = 'text/html' # HyperText Markup Language (HTML) + '.html' = 'text/html' # HyperText Markup Language (HTML) + '.ico' = 'image/vnd.microsoft.icon' # Icon format + '.ics' = 'text/calendar' # iCalendar format + '.ini' = 'text/plain' # Text-based configuration file + '.jar' = 'application/java-archive' # Java Archive (JAR) + '.jpeg' = 'image/jpeg' # JPEG images + '.jpg' = 'image/jpeg' # JPEG images + '.js' = 'text/javascript' # JavaScript + '.json' = 'application/json' # JSON format + '.jsonld' = 'application/ld+json' # JSON-LD format + '.mid' = 'audio/midi' # Musical Instrument Digital Interface (MIDI) + '.midi' = 'audio/midi' # Musical Instrument Digital Interface (MIDI) + '.mjs' = 'text/javascript' # JavaScript module + '.mp3' = 'audio/mpeg' # MP3 audio + '.mp4' = 'video/mp4' # MP3 video + '.mov' = 'video/quicktime' # Quicktime video + '.mpeg' = 'video/mpeg' # MPEG Video + '.mpg' = 'video/mpeg' # MPEG Video + '.mpkg' = 'application/vnd.apple.installer+xml' # Apple Installer Package + '.msi' = 'application/octet-stream' # Windows Installer package + '.msix' = 'application/octet-stream' # Windows Installer package + '.mkv' = 'video/x-matroska' # Matroska Multimedia Container + '.odp' = 'application/vnd.oasis.opendocument.presentation' # OpenDocument presentation document + '.ods' = 'application/vnd.oasis.opendocument.spreadsheet' # OpenDocument spreadsheet document + '.odt' = 'application/vnd.oasis.opendocument.text' # OpenDocument text document + '.oga' = 'audio/ogg' # OGG audio + '.ogg' = 'application/ogg' # OGG audio or video + '.ogv' = 'video/ogg' # OGG video + '.ogx' = 'application/ogg' # OGG + '.opus' = 'audio/opus' # Opus audio + '.otf' = 'font/otf' # OpenType font + '.png' = 'image/png' # Portable Network Graphics + '.pdf' = 'application/pdf' # Adobe Portable Document Format (PDF) + '.php' = 'application/x-httpd-php' # Hypertext Preprocessor (Personal Home Page) + '.pkg' = 'application/octet-stream' # mac OS X installer file + '.ps1' = 'text/plain' # PowerShell script file + '.psd1' = 'text/plain' # PowerShell module definition file + '.psm1' = 'text/plain' # PowerShell module file + '.ppt' = 'application/vnd.ms-powerpoint' # Microsoft PowerPoint + '.pptx' = 'application/vnd.openxmlformats-officedocument.presentationml.presentation' # Microsoft PowerPoint (OpenXML) + '.rar' = 'application/vnd.rar' # RAR archive + '.rtf' = 'application/rtf' # Rich Text Format (RTF) + '.rpm' = 'application/octet-stream' # Red Hat Linux package format + '.sh' = 'application/x-sh' # Bourne shell script + '.svg' = 'image/svg+xml' # Scalable Vector Graphics (SVG) + '.swf' = 'application/x-shockwave-flash' # Small web format (SWF) or Adobe Flash document + '.tar' = 'application/x-tar' # Tape Archive (TAR) + '.tif' = 'image/tiff' # Tagged Image File Format (TIFF) + '.tiff' = 'image/tiff' # Tagged Image File Format (TIFF) + '.ts' = 'video/mp2t' # MPEG transport stream + '.ttf' = 'font/ttf' # TrueType Font + '.txt' = 'text/plain' # Text (generally ASCII or ISO 8859-n) + '.vsd' = 'application/vnd.visio' # Microsoft Visio + '.vsix' = 'application/zip' # Visual Studio application package archive + '.wav' = 'audio/wav' # Waveform Audio Format + '.weba' = 'audio/webm' # WEBM audio + '.webm' = 'video/webm' # WEBM video + '.webp' = 'image/webp' # WEBP image + '.woff' = 'font/woff' # Web Open Font Format (WOFF) + '.woff2' = 'font/woff2' # Web Open Font Format (WOFF) + '.xhtml' = 'application/xhtml+xml' # XHTML + '.xls' = 'application/vnd.ms-excel' # Microsoft Excel + '.xlsx' = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' # Microsoft Excel (OpenXML) + '.xml' = 'application/xml' # XML + '.xul' = 'application/vnd.mozilla.xul+xml' # XUL + '.zip' = 'application/zip' # ZIP archive + } + }.GetEnumerator() | ForEach-Object { + Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value + } diff --git a/GitHubEvents.ps1 b/GitHubEvents.ps1 index 000574af..2dc597db 100644 --- a/GitHubEvents.ps1 +++ b/GitHubEvents.ps1 @@ -60,6 +60,7 @@ filter Get-GitHubEvent GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubIssueComments.ps1 b/GitHubIssueComments.ps1 index 0542581b..48ec9447 100644 --- a/GitHubIssueComments.ps1 +++ b/GitHubIssueComments.ps1 @@ -81,6 +81,7 @@ filter Get-GitHubIssueComment GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -346,6 +347,7 @@ filter New-GitHubIssueComment GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository GitHub.User @@ -490,6 +492,7 @@ filter Set-GitHubIssueComment GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository GitHub.User @@ -621,6 +624,7 @@ filter Remove-GitHubIssueComment GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE diff --git a/GitHubIssues.ps1 b/GitHubIssues.ps1 index 705a9da6..afd90bcf 100644 --- a/GitHubIssues.ps1 +++ b/GitHubIssues.ps1 @@ -130,6 +130,7 @@ filter Get-GitHubIssue GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository GitHub.User @@ -434,6 +435,7 @@ filter Get-GitHubIssueTimeline GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -573,6 +575,7 @@ filter New-GitHubIssue GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -742,6 +745,7 @@ filter Set-GitHubIssue GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -893,6 +897,7 @@ filter Lock-GitHubIssue GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE @@ -1024,6 +1029,7 @@ filter Unlock-GitHubIssue GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE diff --git a/GitHubLabels.ps1 b/GitHubLabels.ps1 index dd1391ac..22cf446f 100644 --- a/GitHubLabels.ps1 +++ b/GitHubLabels.ps1 @@ -65,6 +65,7 @@ filter Get-GitHubLabel GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -253,6 +254,7 @@ filter New-GitHubLabel GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -395,6 +397,7 @@ filter Remove-GitHubLabel GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE @@ -553,6 +556,7 @@ filter Set-GitHubLabel GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -700,6 +704,7 @@ filter Initialize-GitHubLabel GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE @@ -840,6 +845,7 @@ function Add-GitHubIssueLabel GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1001,6 +1007,7 @@ function Set-GitHubIssueLabel GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1193,6 +1200,7 @@ filter Remove-GitHubIssueLabel GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE diff --git a/GitHubMilestones.ps1 b/GitHubMilestones.ps1 index d2f2dc73..7326bf5e 100644 --- a/GitHubMilestones.ps1 +++ b/GitHubMilestones.ps1 @@ -69,6 +69,7 @@ filter Get-GitHubMilestone GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -272,6 +273,7 @@ filter New-GitHubMilestone GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -454,6 +456,7 @@ filter Set-GitHubMilestone GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -635,6 +638,7 @@ filter Remove-GitHubMilestone GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE diff --git a/GitHubMiscellaneous.ps1 b/GitHubMiscellaneous.ps1 index 20ecb3ee..a90a0a41 100644 --- a/GitHubMiscellaneous.ps1 +++ b/GitHubMiscellaneous.ps1 @@ -250,6 +250,7 @@ filter Get-GitHubLicense GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -488,6 +489,7 @@ filter Get-GitHubCodeOfConduct GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubProjects.ps1 b/GitHubProjects.ps1 index c96dc30f..87566375 100644 --- a/GitHubProjects.ps1 +++ b/GitHubProjects.ps1 @@ -64,6 +64,7 @@ filter Get-GitHubProject GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -277,6 +278,7 @@ filter New-GitHubProject GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -457,6 +459,7 @@ filter Set-GitHubProject GitHub.ProjectCard GitHub.ProjectColumn GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -585,6 +588,7 @@ filter Remove-GitHubProject GitHub.ProjectCard GitHub.ProjectColumn GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE diff --git a/GitHubPullRequests.ps1 b/GitHubPullRequests.ps1 index 0eeb5ee4..50b87fea 100644 --- a/GitHubPullRequests.ps1 +++ b/GitHubPullRequests.ps1 @@ -78,6 +78,7 @@ filter Get-GitHubPullRequest GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -274,6 +275,7 @@ filter New-GitHubPullRequest GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubReleases.ps1 b/GitHubReleases.ps1 index 7e5cf6c9..3ec46e28 100644 --- a/GitHubReleases.ps1 +++ b/GitHubReleases.ps1 @@ -3,6 +3,7 @@ @{ GitHubReleaseTypeName = 'GitHub.Release' + GitHubReleaseAssetTypeName = 'GitHub.ReleaseAsset' }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } @@ -67,6 +68,7 @@ filter Get-GitHubRelease GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -106,11 +108,8 @@ filter Get-GitHubRelease Information about published releases are available to everyone. Only users with push access will receive listings for draft releases. #> - [CmdletBinding( - SupportsShouldProcess, - DefaultParameterSetName='Elements')] + [CmdletBinding(DefaultParameterSetName='Elements')] [OutputType({$script:GitHubReleaseTypeName})] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] param( [Parameter(ParameterSetName='Elements')] [Parameter(ParameterSetName="Elements-ReleaseId")] @@ -156,18 +155,18 @@ filter Get-GitHubRelease [Parameter( Mandatory, - ParameterSetName="Elements-Latest")] + ParameterSetName='Elements-Latest')] [Parameter( Mandatory, - ParameterSetName="Uri-Latest")] + ParameterSetName='Uri-Latest')] [switch] $Latest, [Parameter( Mandatory, - ParameterSetName="Elements-Tag")] + ParameterSetName='Elements-Tag')] [Parameter( Mandatory, - ParameterSetName="Uri-Tag")] + ParameterSetName='Uri-Tag')] [string] $Tag, [string] $AccessToken, @@ -181,10 +180,10 @@ filter Get-GitHubRelease $OwnerName = $elements.ownerName $RepositoryName = $elements.repositoryName - $telemetryProperties = @{} - - $telemetryProperties['OwnerName'] = Get-PiiSafeString -PlainText $OwnerName - $telemetryProperties['RepositoryName'] = Get-PiiSafeString -PlainText $RepositoryName + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } $uriFragment = "repos/$OwnerName/$RepositoryName/releases" $description = "Getting releases for $OwnerName/$RepositoryName" @@ -197,7 +196,7 @@ filter Get-GitHubRelease $description = "Getting release information for $Release from $OwnerName/$RepositoryName" } - if($Latest) + if ($Latest) { $telemetryProperties['GetLatest'] = $true @@ -205,7 +204,7 @@ filter Get-GitHubRelease $description = "Getting latest release from $OwnerName/$RepositoryName" } - if(-not [String]::IsNullOrEmpty($Tag)) + if (-not [String]::IsNullOrEmpty($Tag)) { $telemetryProperties['ProvidedTag'] = $true @@ -225,57 +224,1309 @@ filter Get-GitHubRelease return (Invoke-GHRestMethodMultipleResult @params | Add-GitHubReleaseAdditionalProperties) } +filter New-GitHubRelease +{ +<# + .SYNOPSIS + Create a new release for a repository on GitHub. + + .DESCRIPTION + Create a new release for a repository on GitHub. -filter Add-GitHubReleaseAdditionalProperties + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Tag + The name of the tag. The tag will be created around the committish if it doesn't exist + in the remote, and will need to be synced back to the local repository afterwards. + + .PARAMETER Committish + The committish value that determines where the Git tag is created from. + Can be any branch or commit SHA. Unused if the Git tag already exists. + Will default to the repository's default branch (usually 'master'). + + .PARAMETER Name + The name of the release. + + .PARAMETER Body + Text describing the contents of the tag. + + .PARAMETER Draft + Specifies if this should be a draft (unpublished) release or a published one. + + .PARAMETER PreRelease + Indicates if this should be identified as a pre-release or as a full release. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .OUTPUTS + GitHub.Release + + .EXAMPLE + New-GitHubRelease -OwnerName microsoft -RepositoryName PowerShellForGitHub -Tag 0.12.0 + + .NOTES + Requires push access to the repository. + + This endpoind triggers notifications. Creating content too quickly using this endpoint + may result in abuse rate limiting. +#> + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false)] + [OutputType({$script:GitHubReleaseTypeName})] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri', + Position = 1)] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + Position = 2)] + [string] $Tag, + + [Alias('Sha')] + [Alias('BranchName')] + [Alias('Commitish')] # git documentation says "committish", but GitHub uses "commitish" + [string] $Committish, + + [string] $Name, + + [Alias('Description')] + [string] $Body, + + [switch] $Draft, + + [switch] $PreRelease, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + 'ProvidedCommittish' = ($PSBoundParameters.ContainsKey('Committish')) + 'ProvidedName' = ($PSBoundParameters.ContainsKey('Name')) + 'ProvidedBody' = ($PSBoundParameters.ContainsKey('Body')) + 'ProvidedDraft' = ($PSBoundParameters.ContainsKey('Draft')) + 'ProvidedPreRelease' = ($PSBoundParameters.ContainsKey('PreRelease')) + } + + $hashBody = @{ + 'tag_name' = $Tag + } + + if ($PSBoundParameters.ContainsKey('Committish')) { $hashBody['target_commitish'] = $Committish } + if ($PSBoundParameters.ContainsKey('Name')) { $hashBody['name'] = $Name } + if ($PSBoundParameters.ContainsKey('Body')) { $hashBody['body'] = $Body } + if ($PSBoundParameters.ContainsKey('Draft')) { $hashBody['draft'] = $Draft.ToBool() } + if ($PSBoundParameters.ContainsKey('PreRelease')) { $hashBody['prerelease'] = $PreRelease.ToBool() } + + $params = @{ + 'UriFragment' = "/repos/$OwnerName/$RepositoryName/releases" + 'Body' = (ConvertTo-Json -InputObject $hashBody) + 'Method' = 'Post' + 'Description' = "Creating release at $Tag" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + if (-not $PSCmdlet.ShouldProcess($Tag, "Create release for $RepositoryName at tag")) + { + return + } + + return (Invoke-GHRestMethod @params | Add-GitHubReleaseAdditionalProperties) +} + +filter Set-GitHubRelease { <# .SYNOPSIS - Adds type name and additional properties to ease pipelining to GitHub Release objects. + Edits a release for a repository on GitHub. - .PARAMETER InputObject - The GitHub object to add additional properties to. + .DESCRIPTION + Edits a release for a repository on GitHub. - .PARAMETER TypeName - The type that should be assigned to the object. + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Release + The ID of the release to edit. + + .PARAMETER Tag + The name of the tag. + + .PARAMETER Committish + The committish value that determines where the Git tag is created from. + Can be any branch or commit SHA. Unused if the Git tag already exists. + Will default to the repository's default branch (usually 'master'). + + .PARAMETER Name + The name of the release. + + .PARAMETER Body + Text describing the contents of the tag. + + .PARAMETER Draft + Specifies if this should be a draft (unpublished) release or a published one. + + .PARAMETER PreRelease + Indicates if this should be identified as a pre-release or as a full release. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. .INPUTS - [PSCustomObject] + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository .OUTPUTS GitHub.Release + + .EXAMPLE + Set-GitHubRelease -OwnerName microsoft -RepositoryName PowerShellForGitHub -Tag 0.12.0 -Body 'Adds core support for Projects' + + .NOTES + Requires push access to the repository. #> - [CmdletBinding()] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Internal helper that is definitely adding more than one property.")] + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false)] + [OutputType({$script:GitHubReleaseTypeName})] param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + [Parameter( Mandatory, - ValueFromPipeline)] - [AllowNull()] - [AllowEmptyCollection()] - [PSCustomObject[]] $InputObject, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri', + Position = 1)] + [Alias('RepositoryUrl')] + [string] $Uri, - [ValidateNotNullOrEmpty()] - [string] $TypeName = $script:GitHubReleaseTypeName + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + Position = 2)] + [Alias('ReleaseId')] + [int64] $Release, + + [string] $Tag, + + [Alias('Sha')] + [Alias('BranchName')] + [Alias('Commitish')] # git documentation says "committish", but GitHub uses "commitish" + [string] $Committish, + + [string] $Name, + + [Alias('Description')] + [string] $Body, + + [switch] $Draft, + + [switch] $PreRelease, + + [string] $AccessToken, + + [switch] $NoStatus ) - foreach ($item in $InputObject) + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + 'ProvidedTag' = ($PSBoundParameters.ContainsKey('Tag')) + 'ProvidedCommittish' = ($PSBoundParameters.ContainsKey('Committish')) + 'ProvidedName' = ($PSBoundParameters.ContainsKey('Name')) + 'ProvidedBody' = ($PSBoundParameters.ContainsKey('Body')) + 'ProvidedDraft' = ($PSBoundParameters.ContainsKey('Draft')) + 'ProvidedPreRelease' = ($PSBoundParameters.ContainsKey('PreRelease')) + } + + $hashBody = @{} + if ($PSBoundParameters.ContainsKey('Tag')) { $hashBody['tag_name'] = $Tag } + if ($PSBoundParameters.ContainsKey('Committish')) { $hashBody['target_commitish'] = $Committish } + if ($PSBoundParameters.ContainsKey('Name')) { $hashBody['name'] = $Name } + if ($PSBoundParameters.ContainsKey('Body')) { $hashBody['body'] = $Body } + if ($PSBoundParameters.ContainsKey('Draft')) { $hashBody['draft'] = $Draft.ToBool() } + if ($PSBoundParameters.ContainsKey('PreRelease')) { $hashBody['prerelease'] = $PreRelease.ToBool() } + + $params = @{ + 'UriFragment' = "/repos/$OwnerName/$RepositoryName/releases/$Release" + 'Body' = (ConvertTo-Json -InputObject $hashBody) + 'Method' = 'Patch' + 'Description' = "Creating release at $Tag" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + if (-not $PSCmdlet.ShouldProcess($Release, "Update GitHub Release")) { - $item.PSObject.TypeNames.Insert(0, $TypeName) + return + } - if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) - { - if (-not [String]::IsNullOrEmpty($item.html_url)) - { - $elements = Split-GitHubUri -Uri $item.html_url - $repositoryUrl = Join-GitHubUri @elements - Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force - } + return (Invoke-GHRestMethod @params | Add-GitHubReleaseAdditionalProperties) +} - Add-Member -InputObject $item -Name 'ReleaseId' -Value $item.id -MemberType NoteProperty -Force +filter Remove-GitHubRelease +{ +<# + .SYNOPSIS + Removes a release from a repository on GitHub. - if ($null -ne $item.author) - { - $null = Add-GitHubUserAdditionalProperties -InputObject $item.author + .DESCRIPTION + Removes a release from a repository on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Release + The ID of the release to remove. + + .PARAMETER Force + If this switch is specified, you will not be prompted for confirmation of command execution. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .EXAMPLE + Remove-GitHubRelease -OwnerName microsoft -RepositoryName PowerShellForGitHub -Release 1234567890 + + .EXAMPLE + Remove-GitHubRelease -OwnerName microsoft -RepositoryName PowerShellForGitHub -Release 1234567890 -Confirm:$false + + Will not prompt for confirmation, as -Confirm:$false was specified. + + .NOTES + Requires push access to the repository. +#> + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false, + ConfirmImpact='High')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.")] + [Alias('Delete-GitHubRelease')] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri', + Position = 1)] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + Position = 2)] + [Alias('ReleaseId')] + [int64] $Release, + + [switch] $Force, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $params = @{ + 'UriFragment' = "/repos/$OwnerName/$RepositoryName/releases/$Release" + 'Method' = 'Delete' + 'Description' = "Deleting release $Release" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + if (-not $PSCmdlet.ShouldProcess($Release, "Remove GitHub Release")) + { + return + } + + return Invoke-GHRestMethod @params +} + +filter Get-GitHubReleaseAsset +{ +<# + .SYNOPSIS + Gets a a list of assets for a release, or downloads a single release asset. + + .DESCRIPTION + Gets a a list of assets for a release, or downloads a single release asset. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Release + The ID of a specific release to see the assets for. + + .PARAMETER Asset + The ID of the specific asset to download. + + .PARAMETER Path + The path where the downloaded asset should be stored. + + .PARAMETER Force + If specified, will overwrite any file located at Path when downloading Asset. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .OUTPUTS + GitHub.ReleaseAsset + + .EXAMPLE + Get-GitHubReleaseAsset -OwnerName microsoft -RepositoryName PowerShellForGitHub -Release 1234567890 + + Gets a list of all the assets associated with this release + + .EXAMPLE + Get-GitHubReleaseAsset -OwnerName microsoft -RepositoryName PowerShellForGitHub -Asset 1234567890 -Path 'c:\users\PowerShellForGitHub\downloads\asset.zip' -Force + + Downloads the asset 1234567890 to 'c:\users\PowerShellForGitHub\downloads\asset.zip' and + overwrites the file that may already be there. +#> + [CmdletBinding(PositionalBinding = $false)] + [OutputType({$script:GitHubReleaseAssetTypeName})] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter(ParameterSetName='Elements-List')] + [Parameter(ParameterSetName='Elements-Info')] + [Parameter(ParameterSetName='Elements-Download')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements-List')] + [Parameter(ParameterSetName='Elements-Info')] + [Parameter(ParameterSetName='Elements-Download')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri-Info', + Position = 1)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri-Download', + Position = 1)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri-List', + Position = 1)] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Elements-List', + Position = 1)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri-List', + Position = 2)] + [Alias('ReleaseId')] + [int64] $Release, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Elements-Info', + Position = 1)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Elements-Download', + Position = 1)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri-Info', + Position = 2)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri-Download', + Position = 2)] + [Alias('AssetId')] + [int64] $Asset, + + [Parameter( + Mandatory, + ParameterSetName='Elements-Download', + Position = 2)] + [Parameter( + Mandatory, + ParameterSetName='Uri-Download', + Position = 3)] + [string] $Path, + + [Parameter(ParameterSetName='Elements-Download')] + [Parameter(ParameterSetName='Uri-Download')] + [switch] $Force, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $uriFragment = [String]::Empty + $description = [String]::Empty + $shouldSave = $false + $acceptHeader = $script:defaultAcceptHeader + if ($PSCmdlet.ParameterSetName -in ('Elements-List', 'Uri-List')) + { + $uriFragment = "/repos/$OwnerName/$RepositoryName/releases/$Release/assets" + $description = "Getting list of assets for release $Release" + } + elseif ($PSCmdlet.ParameterSetName -in ('Elements-Info', 'Uri-Info')) + { + $uriFragment = "/repos/$OwnerName/$RepositoryName/releases/assets/$Asset" + $description = "Getting information about release asset $Asset" + } + elseif ($PSCmdlet.ParameterSetName -in ('Elements-Download', 'Uri-Download')) + { + $uriFragment = "/repos/$OwnerName/$RepositoryName/releases/assets/$Asset" + $description = "Downloading release asset $Asset" + $shouldSave = $true + $acceptHeader = 'application/octet-stream' + + $Path = Resolve-UnverifiedPath -Path $Path + } + + $params = @{ + 'UriFragment' = $uriFragment + 'Method' = 'Get' + 'Description' = $description + 'AcceptHeader' = $acceptHeader + 'Save' = $shouldSave + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + $result = Invoke-GHRestMethod @params + + if ($PSCmdlet.ParameterSetName -in ('Elements-Download', 'Uri-Download')) + { + Write-Log -Message "Moving [$($result.FullName)] to [$Path]" -Level Verbose + return (Move-Item -Path $result -Destination $Path -Force:$Force -ErrorAction Stop -PassThru) + } + else + { + return ($result | Add-GitHubReleaseAssetAdditionalProperties) + } +} + +filter New-GitHubReleaseAsset +{ +<# + .SYNOPSIS + Uploads a new asset for a release on GitHub. + + .DESCRIPTION + Uploads a new asset for a release on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Release + The ID of the release that the asset is for. + + .PARAMETER UploadUrl + The value of 'upload_url' from getting the asset details. + + .PARAMETER Path + The path to the file to upload as a new asset. + + .PARAMETER Label + An alternate short description of the asset. Used in place of the filename. + + .PARAMETER ContentType + The MIME Media Type for the file being uploaded. By default, this will be inferred based + on the file's extension. If the extension is not known by this module, it will fallback to + using text/plain. You may specify a ContentType here to override the module's logic. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .OUTPUTS + GitHub.ReleaseAsset + + .EXAMPLE + New-GitHubReleaseAsset -OwnerName microsoft -RepositoryName PowerShellForGitHub -Release 123456 -Path 'c:\foo.zip' + + Uploads the file located at 'c:\foo.zip' to the 123456 release in microsoft/PowerShellForGitHub + + .EXAMPLE + $release = New-GitHubRelease -OwnerName microsoft -RepositoryName PowerShellForGitHub -Tag 'stable' + $release | New-GitHubReleaseAsset -Path 'c:\bar.txt' + + Creates a new release tagged as 'stable' and then uploads 'c:\bar.txt' as an asset for + that release. + + .NOTES + GitHub renames asset filenames that have special characters, non-alphanumeric characters, + and leading or trailing periods. Get-GitHubReleaseAsset lists the renamed filenames. + + If you upload an asset with the same filename as another uploaded asset, you'll receive + an error and must delete the old file before you can re-upload the new asset. +#> + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false)] + [OutputType({$script:GitHubReleaseAssetTypeName})] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri', + Position = 1)] + [Parameter( + ValueFromPipelineByPropertyName, + ParameterSetName='UploadUrl')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Elements', + Position = 1)] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri', + Position = 2)] + [Parameter( + ValueFromPipelineByPropertyName, + ParameterSetName='UploadUrl')] + [Alias('ReleaseId')] + [int64] $Release, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='UploadUrl', + Position = 1)] + [string] $UploadUrl, + + [Parameter( + Mandatory, + ValueFromPipeline)] + [ValidateScript( + {if (Test-Path -Path $_ -PathType Leaf) { $true } + else { throw "$_ does not exist or is inaccessible." }})] + [string] $Path, + + [string] $Label, + + [string] $ContentType, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $telemetryProperties = @{ + 'ProvidedUploadUrl' = ($PSBoundParameters.ContainsKey('UploadUrl')) + 'ProvidedLabel' = ($PSBoundParameters.ContainsKey('Label')) + 'ProvidedContentType' = ($PSBoundParameters.ContainsKey('ContentType')) + } + + # If UploadUrl wasn't provided, we'll need to query for it first. + if ([String]::IsNullOrEmpty($UploadUrl)) + { + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties['OwnerName'] = (Get-PiiSafeString -PlainText $OwnerName) + $telemetryProperties['RepositoryName'] = (Get-PiiSafeString -PlainText $RepositoryName) + + $params = @{ + 'OwnerName' = $OwnerName + 'RepositoryName' = $RepositoryName + 'Release' = $Release + 'AccessToken' = $AccessToken + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + $releaseInfo = Get-GitHubRelease @params + $UploadUrl = $releaseInfo.upload_url + } + + # Remove the '{name,label}' from the Url if it's there + if ($UploadUrl -match '(.*){') + { + $UploadUrl = $Matches[1] + } + + $Path = Resolve-UnverifiedPath -Path $Path + $file = Get-Item -Path $Path + $fileName = $file.Name + $fileNameEncoded = [Uri]::EscapeDataString($fileName) + $queryParams = @("name=$fileNameEncoded") + + if ($PSBoundParameters.ContainsKey('Label')) + { + $labelEncoded = [Uri]::EscapeDataString($Label) + $queryParams += "label=$labelEncoded" + } + + if (-not $PSCmdlet.ShouldProcess($Path, "Create new GitHub Release Asset")) + { + return + } + + $params = @{ + 'UriFragment' = $UploadUrl + '?' + ($queryParams -join '&') + 'Method' = 'Post' + 'Description' = "Uploading release asset: $fileName" + 'InFile' = $Path + 'ContentType' = $ContentType + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return (Invoke-GHRestMethod @params | Add-GitHubReleaseAssetAdditionalProperties) +} + +filter Set-GitHubReleaseAsset +{ +<# + .SYNOPSIS + Edits an existing asset for a release on GitHub. + + .DESCRIPTION + Edits an existing asset for a release on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Asset + The ID of the asset being updated. + + .PARAMETER Name + The new filename of the asset. + + .PARAMETER Label + An alternate short description of the asset. Used in place of the filename. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .OUTPUTS + GitHub.ReleaseAsset + + .EXAMPLE + Set-GitHubReleaseAsset -OwnerName microsoft -RepositoryName PowerShellForGitHub -Asset 123456 -Name bar.zip + + Renames the asset 123456 to be 'bar.zip'. + + .NOTES + Requires push access to the repository. +#> + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false)] + [OutputType({$script:GitHubReleaseAssetTypeName})] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri', + Position = 1)] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + Position = 2)] + [Alias('AssetId')] + [int64] $Asset, + + [string] $Name, + + [string] $Label, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + 'ProvidedName' = ($PSBoundParameters.ContainsKey('Name')) + 'ProvidedLabel' = ($PSBoundParameters.ContainsKey('Label')) + } + + $hashBody = @{} + if ($PSBoundParameters.ContainsKey('Name')) { $hashBody['name'] = $Name } + if ($PSBoundParameters.ContainsKey('Label')) { $hashBody['label'] = $Label } + + if (-not $PSCmdlet.ShouldProcess($Asset, "Update GitHub Release Asset")) + { + return + } + + $params = @{ + 'UriFragment' = "/repos/$OwnerName/$RepositoryName/releases/assets/$Asset" + 'Body' = (ConvertTo-Json -InputObject $hashBody) + 'Method' = 'Patch' + 'Description' = "Editing asset $Asset" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return (Invoke-GHRestMethod @params | Add-GitHubReleaseAssetAdditionalProperties) +} + +filter Remove-GitHubReleaseAsset +{ +<# + .SYNOPSIS + Removes an asset from a release on GitHub. + + .DESCRIPTION + Removes an asset from a release on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER Asset + The ID of the asset to remove. + + .PARAMETER Force + If this switch is specified, you will not be prompted for confirmation of command execution. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .EXAMPLE + Remove-GitHubReleaseAsset -OwnerName microsoft -RepositoryName PowerShellForGitHub -Asset 1234567890 + + .EXAMPLE + Remove-GitHubReleaseAsset -OwnerName microsoft -RepositoryName PowerShellForGitHub -Asset 1234567890 -Confirm:$false + + Will not prompt for confirmation, as -Confirm:$false was specified. +#> + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false, + ConfirmImpact='High')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="One or more parameters (like NoStatus) are only referenced by helper methods which get access to it from the stack via Get-Variable -Scope 1.")] + [Alias('Delete-GitHubReleaseAsset')] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri', + Position = 1)] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + Position = 2)] + [Alias('AssetId')] + [int64] $Asset, + + [switch] $Force, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $params = @{ + 'UriFragment' = "/repos/$OwnerName/$RepositoryName/releases/assets/$Asset" + 'Method' = 'Delete' + 'Description' = "Deleting asset $Asset" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + if (-not $PSCmdlet.ShouldProcess($Asset, "Delete GitHub Release Asset")) + { + return + } + + return Invoke-GHRestMethod @params +} + +filter Add-GitHubReleaseAdditionalProperties +{ +<# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Release objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + [PSCustomObject] + + .OUTPUTS + GitHub.Release +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Internal helper that is definitely adding more than one property.")] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubReleaseTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + if (-not [String]::IsNullOrEmpty($item.html_url)) + { + $elements = Split-GitHubUri -Uri $item.html_url + $repositoryUrl = Join-GitHubUri @elements + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + } + + Add-Member -InputObject $item -Name 'ReleaseId' -Value $item.id -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'UploadUrl' -Value $item.upload_url -MemberType NoteProperty -Force + + if ($null -ne $item.author) + { + $null = Add-GitHubUserAdditionalProperties -InputObject $item.author + } + } + + Write-Output $item + } +} + +filter Add-GitHubReleaseAssetAdditionalProperties +{ +<# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Release Asset objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + [PSCustomObject] + + .OUTPUTS + GitHub.ReleaseAsset +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Internal helper that is definitely adding more than one property.")] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubReleaseAssetTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + $elements = Split-GitHubUri -Uri $item.url + $repositoryUrl = Join-GitHubUri @elements + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + + Add-Member -InputObject $item -Name 'AssetId' -Value $item.id -MemberType NoteProperty -Force + + if ($null -ne $item.uploader) + { + $null = Add-GitHubUserAdditionalProperties -InputObject $item.uploader } } diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index 6a3fbc89..e198ef29 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -110,6 +110,7 @@ filter New-GitHubRepository GitHub.ProjectCard GitHub.ProjectColumn GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -450,6 +451,7 @@ filter Remove-GitHubRepository GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .EXAMPLE @@ -617,6 +619,7 @@ filter Get-GitHubRepository GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -942,6 +945,7 @@ filter Rename-GitHubRepository GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1124,6 +1128,7 @@ filter Set-GitHubRepository GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1309,6 +1314,7 @@ filter Get-GitHubRepositoryTopic GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1425,6 +1431,7 @@ function Set-GitHubRepositoryTopic GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1613,6 +1620,7 @@ filter Get-GitHubRepositoryContributor GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1766,6 +1774,7 @@ filter Get-GitHubRepositoryCollaborator GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1885,6 +1894,7 @@ filter Get-GitHubRepositoryLanguage GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -1994,6 +2004,7 @@ filter Get-GitHubRepositoryTag GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -2109,6 +2120,7 @@ filter Move-GitHubRepositoryOwnership GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubRepositoryForks.ps1 b/GitHubRepositoryForks.ps1 index 23cc63ae..18a3ca31 100644 --- a/GitHubRepositoryForks.ps1 +++ b/GitHubRepositoryForks.ps1 @@ -52,6 +52,7 @@ filter Get-GitHubRepositoryFork GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -170,6 +171,7 @@ filter New-GitHubRepositoryFork GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubRepositoryTraffic.ps1 b/GitHubRepositoryTraffic.ps1 index 0d32c21e..606b64d6 100644 --- a/GitHubRepositoryTraffic.ps1 +++ b/GitHubRepositoryTraffic.ps1 @@ -58,6 +58,7 @@ filter Get-GitHubReferrerTraffic GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -172,6 +173,7 @@ filter Get-GitHubPathTraffic GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -293,6 +295,7 @@ filter Get-GitHubViewTraffic GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS @@ -418,6 +421,7 @@ filter Get-GitHubCloneTraffic GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository .OUTPUTS diff --git a/GitHubTeams.ps1 b/GitHubTeams.ps1 index 44c94399..07d38454 100644 --- a/GitHubTeams.ps1 +++ b/GitHubTeams.ps1 @@ -62,6 +62,7 @@ filter Get-GitHubTeam GitHub.ProjectColumn GitHub.Reaction GitHub.Release + GitHub.ReleaseAsset GitHub.Repository GitHub.Team @@ -201,6 +202,7 @@ filter Get-GitHubTeamMember GitHub.ProjectCard GitHub.ProjectColumn GitHub.Release + GitHub.ReleaseAsset GitHub.Repository GitHub.Team diff --git a/Helpers.ps1 b/Helpers.ps1 index 482c5875..5d1b5ef7 100644 --- a/Helpers.ps1 +++ b/Helpers.ps1 @@ -428,13 +428,14 @@ function New-TemporaryDirectory [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] param() - $guid = [System.GUID]::NewGuid() - while (Test-Path -PathType Container (Join-Path -Path $env:TEMP -ChildPath $guid)) + $parentTempPath = [System.IO.Path]::GetTempPath() + $tempFolderPath = [String]::Empty + do { - $guid = [System.GUID]::NewGuid() + $guid = [System.Guid]::NewGuid() + $tempFolderPath = Join-Path -Path $parentTempPath -ChildPath $guid } - - $tempFolderPath = Join-Path -Path $env:TEMP -ChildPath $guid + while (Test-Path -Path $tempFolderPath -PathType Container) Write-Log -Message "Creating temporary directory: $tempFolderPath" -Level Verbose New-Item -ItemType Directory -Path $tempFolderPath diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 4be54289..3063585b 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -15,6 +15,7 @@ # Format files (.ps1xml) to be loaded when importing this module FormatsToProcess = @( + 'Formatters/GitHubReleases.Format.ps1xml' 'Formatters/GitHubRepositories.Format.ps1xml' ) @@ -89,6 +90,7 @@ 'Get-GitHubReaction', 'Get-GitHubReferrerTraffic', 'Get-GitHubRelease', + 'Get-GitHubReleaseAsset', 'Get-GitHubRepository', 'Get-GitHubRepositoryBranch', 'Get-GitHubRepositoryCollaborator', @@ -121,6 +123,8 @@ 'New-GitHubProjectCard', 'New-GitHubProjectColumn', 'New-GitHubPullRequest', + 'New-GitHubRelease', + 'New-GitHubReleaseAsset', 'New-GitHubRepository', 'New-GitHubRepositoryFromTemplate', 'New-GitHubRepositoryBranch', @@ -134,6 +138,8 @@ 'Remove-GitHubProjectCard', 'Remove-GitHubProjectColumn', 'Remove-GitHubReaction', + 'Remove-GitHubRelease', + 'Remove-GitHubReleaseAsset', 'Remove-GitHubRepository', 'Remove-GitHubRepositoryBranch' 'Rename-GitHubRepository', @@ -152,6 +158,8 @@ 'Set-GitHubProjectCard', 'Set-GitHubProjectColumn', 'Set-GitHubReaction', + 'Set-GitHubRelease', + 'Set-GitHubReleaseAsset', 'Set-GitHubRepository', 'Set-GitHubRepositoryTopic', 'Split-GitHubUri', @@ -163,6 +171,7 @@ ) AliasesToExport = @( + 'Delete-GitHubAsset', 'Delete-GitHubBranch', 'Delete-GitHubComment', 'Delete-GitHubIssueComment', @@ -170,17 +179,23 @@ 'Delete-GitHubMilestone', 'Delete-GitHubProject', 'Delete-GitHubProjectCard', - 'Delete-GitHubProjectColumn', + 'Delete-GitHubProjectColumn' 'Delete-GitHubReaction', + 'Delete-GitHubRelease', + 'Delete-GitHubReleaseAsset', 'Delete-GitHubRepository', 'Delete-GitHubRepositoryBranch', + 'Get-GitHubAsset', 'Get-GitHubBranch', 'Get-GitHubComment', + 'New-GitHubAsset', 'New-GitHubAssignee', 'New-GitHubBranch', 'New-GitHubComment', + 'Remove-GitHubAsset', 'Remove-GitHubBranch' 'Remove-GitHubComment', + 'Set-GitHubAsset', 'Set-GitHubComment', 'Transfer-GitHubRepositoryOwnership' 'Update-GitHubIssue', diff --git a/Tests/GitHubReleases.tests.ps1 b/Tests/GitHubReleases.tests.ps1 index 10c1b42a..abac19b8 100644 --- a/Tests/GitHubReleases.tests.ps1 +++ b/Tests/GitHubReleases.tests.ps1 @@ -18,122 +18,1077 @@ $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent try { Describe 'Getting releases from repository' { - $ownerName = "dotnet" - $repositoryName = "core" - $releases = @(Get-GitHubRelease -OwnerName $ownerName -RepositoryName $repositoryName) + Context 'Common test state' { + BeforeAll { + $dotNetOwnerName = "dotnet" + $repositoryName = "core" - Context 'When getting all releases' { - It 'Should return multiple releases' { - $releases.Count | Should -BeGreaterThan 1 + $releases = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName) + } + + Context 'When getting all releases' { + It 'Should return multiple releases' { + $releases.Count | Should -BeGreaterThan 1 + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $releases[0].html_url + $repositoryUrl = Join-GitHubUri @elements + + $releases[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $releases[0].RepositoryUrl | Should -Be $repositoryUrl + $releases[0].ReleaseId | Should -Be $releases[0].id + } + } + + Context 'When getting the latest releases' { + $latest = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName -Latest) + + It 'Should return one value' { + $latest.Count | Should -Be 1 + } + + It 'Should return the first release from the full releases list' { + $latest[0].url | Should -Be $releases[0].url + $latest[0].name | Should -Be $releases[0].name + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $latest[0].html_url + $repositoryUrl = Join-GitHubUri @elements + + $latest[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $latest[0].RepositoryUrl | Should -Be $repositoryUrl + $latest[0].ReleaseId | Should -Be $latest[0].id + } + } + + Context 'When getting the latest releases via the pipeline' { + $latest = @(Get-GitHubRepository -OwnerName $dotNetOwnerName -RepositoryName $repositoryName | + Get-GitHubRelease -Latest) + + It 'Should return one value' { + $latest.Count | Should -Be 1 + } + + It 'Should return the first release from the full releases list' { + $latest[0].url | Should -Be $releases[0].url + $latest[0].name | Should -Be $releases[0].name + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $latest[0].html_url + $repositoryUrl = Join-GitHubUri @elements + + $latest[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $latest[0].RepositoryUrl | Should -Be $repositoryUrl + $latest[0].ReleaseId | Should -Be $latest[0].id + } + + $latestAgain = @($latest | Get-GitHubRelease) + It 'Should be the same release' { + $latest[0].ReleaseId | Should -Be $latestAgain[0].ReleaseId + } + } + + Context 'When getting a specific release' { + $specificIndex = 5 + $specific = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName -ReleaseId $releases[$specificIndex].id) + + It 'Should return one value' { + $specific.Count | Should -Be 1 + } + + It 'Should return the correct release' { + $specific.name | Should -Be $releases[$specificIndex].name + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $specific[0].html_url + $repositoryUrl = Join-GitHubUri @elements + + $specific[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $specific[0].RepositoryUrl | Should -Be $repositoryUrl + $specific[0].id | Should -Be $specific[0].ReleaseId + } + } + + Context 'When getting a tagged release' { + $taggedIndex = 8 + $tagged = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName -Tag $releases[$taggedIndex].tag_name) + + It 'Should return one value' { + $tagged.Count | Should -Be 1 + } + + It 'Should return the correct release' { + $tagged.name | Should -Be $releases[$taggedIndex].name + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $tagged[0].html_url + $repositoryUrl = Join-GitHubUri @elements + + $tagged[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $tagged[0].RepositoryUrl | Should -Be $repositoryUrl + $tagged[0].ReleaseId | Should -Be $tagged[0].id + } + } + } + } + + Describe 'Getting releases from default owner/repository' { + Context 'Common test state' { + BeforeAll { + $originalOwnerName = Get-GitHubConfiguration -Name DefaultOwnerName + $originalRepositoryName = Get-GitHubConfiguration -Name DefaultRepositoryName + + Set-GitHubConfiguration -DefaultOwnerName "dotnet" + Set-GitHubConfiguration -DefaultRepositoryName "core" + } + + AfterAll { + Set-GitHubConfiguration -DefaultOwnerName $originalOwnerName + Set-GitHubConfiguration -DefaultRepositoryName $originalRepositoryName + } + + Context 'When getting all releases' { + $releases = @(Get-GitHubRelease) + + It 'Should return multiple releases' { + $releases.Count | Should -BeGreaterThan 1 + } + } + } + } + + Describe 'Creating, changing and deleting releases with defaults' { + Context 'Common test state' { + BeforeAll { + $defaultTagName = '0.2.0' + $defaultReleaseName = 'Release Name' + $defaultReleaseBody = 'Releasey Body' + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName + $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id + } + + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + + Context 'When creating a simple new release' { + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $release.html_url + $repositoryUrl = Join-GitHubUri @elements + + $release.PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $release.RepositoryUrl | Should -Be $repositoryUrl + $release.ReleaseId | Should -Be $release.id + } + + It 'Should be queryable' { + $queried.id | Should -Be $release.id + $queried.tag_name | Should -Be $defaultTagName + } + + It 'Should have the expected default property values' { + $queried.name | Should -BeNullOrEmpty + $queried.body | Should -BeNullOrEmpty + $queried.draft | Should -BeFalse + $queried.prerelease | Should -BeFalse + } + + It 'Should be modifiable' { + Set-GitHubRelease -Uri $repo.svn_url -Release $release.id -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease + $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeTrue + $queried.prerelease | Should -BeTrue + } + + It 'Should be removable' { + Remove-GitHubRelease -Uri $repo.svn_url -Release $release.id -Confirm:$false + { Get-GitHubRelease -Uri $repo.svn_url -Release $release.id } | Should -Throw + } + } + } + } + + Describe 'Creating, changing and deleting releases with defaults using the pipeline' { + Context 'Common test state' { + BeforeAll { + $defaultTagName = '0.2.0' + $defaultReleaseName = 'Release Name' + $defaultReleaseBody = 'Releasey Body' + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = $repo | New-GitHubRelease -Tag $defaultTagName + $queried = $release | Get-GitHubRelease + } + + AfterAll { + $repo | Remove-GitHubRepository -Force + } + + Context 'When creating a simple new release' { + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $release.html_url + $repositoryUrl = Join-GitHubUri @elements + + $release.PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $release.RepositoryUrl | Should -Be $repositoryUrl + $release.ReleaseId | Should -Be $release.id + } + + It 'Should be queryable' { + $queried.id | Should -Be $release.id + $queried.tag_name | Should -Be $defaultTagName + } + + It 'Should have the expected default property values' { + $queried.name | Should -BeNullOrEmpty + $queried.body | Should -BeNullOrEmpty + $queried.draft | Should -BeFalse + $queried.prerelease | Should -BeFalse + } + + It 'Should be modifiable with the release on the pipeline' { + $null = $release | Set-GitHubRelease -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease + $queried = $release | Get-GitHubRelease + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeTrue + $queried.prerelease | Should -BeTrue + } + + It 'Should be modifiable with the URI on the pipeline' { + $null = $repo | Set-GitHubRelease -Release $release.id -Draft:$false + $queried = $repo | Get-GitHubRelease -Release $release.id + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeFalse + $queried.prerelease | Should -BeTrue + } + + It 'Should be removable' { + $release | Remove-GitHubRelease -Force + { $release | Get-GitHubRelease } | Should -Throw + } + } + } + } + + Describe 'Creating and changing releases with non-defaults' { + Context 'Common test state' { + BeforeAll { + $defaultTagName = '0.2.0' + $defaultReleaseName = 'Release Name' + $defaultReleaseBody = 'Releasey Body' + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + } + + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + + Context 'When creating a simple new release' { + BeforeAll { + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease + $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id + } + + AfterAll { + $release | Remove-GitHubRelease -Force + } + + It 'Should be creatable with non-default property values' { + $queried.id | Should -Be $release.id + $queried.tag_name | Should -Be $defaultTagName + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeTrue + $queried.prerelease | Should -BeTrue + } + } + + Context 'When creating a simple new release with the repo on the pipeline' { + BeforeAll { + $release = $repo | New-GitHubRelease -Tag $defaultTagName -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease + $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id + } + + AfterAll { + $release | Remove-GitHubRelease -Force + } + + It 'Should be creatable with non-default property values' { + $queried.id | Should -Be $release.id + $queried.tag_name | Should -Be $defaultTagName + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeTrue + $queried.prerelease | Should -BeTrue + } + } + } + } + + Describe 'Get-GitHubReleaseAsset' { + BeforeAll { + $defaultTagName = '0.2.0' + + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + + $tempFile = New-TemporaryFile + $zipFile = "$($tempFile.FullName).zip" + Move-Item -Path $tempFile -Destination $zipFile + + $tempFile = New-TemporaryFile + $txtFile = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $txtFile + Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 + + # The file we'll save the downloaded contents to + $saveFile = New-TemporaryFile + + # Disable Progress Bar in function scope during Compress-Archive + $ProgressPreference = 'SilentlyContinue' + Compress-Archive -Path $txtFile -DestinationPath $zipFile -Force + + $labelBase = 'mylabel' + } + + AfterAll { + @($zipFile, $txtFile, $saveFile) | Remove-Item -ErrorAction SilentlyContinue | Out-Null + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + + Context 'Using parameters' { + BeforeAll { + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName + + # We want to make sure we start out without the file being there. + Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null + } + + AfterAll { + $release | Remove-GitHubRelease -Force + } + + $assets = @(Get-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id) + It 'Should have no assets so far' { + $assets.Count | Should -Be 0 + } + + @($zipFile, $txtFile) | ForEach-Object { + $fileName = (Get-Item -Path $_).Name + $finalLabel = "$labelBase-$fileName" + $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $_ -Label $finalLabel + It "Can add a release asset" { + $assetId = $asset.id + + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + $assets = @(Get-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id) + It 'Should have both assets now' { + $assets.Count | Should -Be 2 + } + + It 'Should have expected type and additional properties' { + foreach ($asset in $assets) + { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + $txtFileName = (Get-Item -Path $txtFile).Name + $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } + $asset = Get-GitHubReleaseAsset -Uri $repo.svn_url -Asset $txtFileAsset.id + It 'Should be able to query for a single asset' { + $asset.id | Should -Be $txtFileAsset.id + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + It 'Should not have the downloaded file yet' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse + } + + $downloadParams = @{ + OwnerName = $script:ownerName + RepositoryName = $repo.name + Asset = $txtFileAsset.id + Path = $saveFile + } + + $null = Get-GitHubReleaseAsset @downloadParams + It 'Should be able to download the asset file' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue + } + + It 'Should be able the same file' { + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + + It 'Should fail if the download location already exists' { + { Get-GitHubReleaseAsset @downloadParams } | Should -Throw + } + + It 'Should work if the download location already exists and -Force is used' { + $null = Get-GitHubReleaseAsset @downloadParams -Force + + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + } + + Context 'Using the repo on the pipeline' { + BeforeAll { + $release = $repo | New-GitHubRelease -Tag $defaultTagName + + # We want to make sure we start out without the file being there. + Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null + } + + AfterAll { + $release | Remove-GitHubRelease -Force + } + + $assets = @($repo | Get-GitHubReleaseAsset -Release $release.id) + It 'Should have no assets so far' { + $assets.Count | Should -Be 0 + } + + @($zipFile, $txtFile) | ForEach-Object { + $fileName = (Get-Item -Path $_).Name + $finalLabel = "$labelBase-$fileName" + $asset = $repo | New-GitHubReleaseAsset -Release $release.id -Path $_ -Label $finalLabel + It "Can add a release asset" { + $assetId = $asset.id + + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + $assets = @($repo | Get-GitHubReleaseAsset -Release $release.id) + It 'Should have both assets now' { + $assets.Count | Should -Be 2 } It 'Should have expected type and additional properties' { - $releases[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $releases[0].html_url.StartsWith($releases[0].RepositoryUrl) | Should -BeTrue - $releases[0].id | Should -Be $releases[0].ReleaseId + foreach ($asset in $assets) + { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + $txtFileName = (Get-Item -Path $txtFile).Name + $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } + $asset = $repo | Get-GitHubReleaseAsset -Asset $txtFileAsset.id + It 'Should be able to query for a single asset' { + $asset.id | Should -Be $txtFileAsset.id + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + It 'Should not have the downloaded file yet' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse + } + + $downloadParams = @{ + Asset = $txtFileAsset.id + Path = $saveFile + } + + $null = $repo | Get-GitHubReleaseAsset @downloadParams + It 'Should be able to download the asset file' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue + } + + It 'Should be able the same file' { + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + + It 'Should fail if the download location already exists' { + { $repo | Get-GitHubReleaseAsset @downloadParams } | Should -Throw + } + + It 'Should work if the download location already exists and -Force is used' { + $null = $repo | Get-GitHubReleaseAsset @downloadParams -Force + + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty } } - Context 'When getting the latest releases' { - $latest = @(Get-GitHubRelease -OwnerName $ownerName -RepositoryName $repositoryName -Latest) + Context 'Using the release on the pipeline' { + BeforeAll { + $release = $repo | New-GitHubRelease -Tag $defaultTagName + + # We want to make sure we start out without the file being there. + Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null + } + + AfterAll { + $release | Remove-GitHubRelease -Force + } - It 'Should return one value' { - $latest.Count | Should -Be 1 + $assets = @($release | Get-GitHubReleaseAsset) + It 'Should have no assets so far' { + $assets.Count | Should -Be 0 } - It 'Should return the first release from the full releases list' { - $latest[0].url | Should -Be $releases[0].url - $latest[0].name | Should -Be $releases[0].name + @($zipFile, $txtFile) | ForEach-Object { + $fileName = (Get-Item -Path $_).Name + $finalLabel = "$labelBase-$fileName" + $asset = $release | New-GitHubReleaseAsset -Path $_ -Label $finalLabel + It "Can add a release asset" { + $assetId = $asset.id + + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + $assets = @($release | Get-GitHubReleaseAsset) + It 'Should have both assets now' { + $assets.Count | Should -Be 2 + } + + It 'Should have expected type and additional properties' { + foreach ($asset in $assets) + { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + $txtFileName = (Get-Item -Path $txtFile).Name + $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } + $asset = $release | Get-GitHubReleaseAsset -Asset $txtFileAsset.id + It 'Should be able to query for a single asset' { + $asset.id | Should -Be $txtFileAsset.id } It 'Should have expected type and additional properties' { - $latest[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $latest[0].html_url.StartsWith($latest[0].RepositoryUrl) | Should -BeTrue - $latest[0].id | Should -Be $latest[0].ReleaseId + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + It 'Should not have the downloaded file yet' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse + } + + $downloadParams = @{ + Asset = $txtFileAsset.id + Path = $saveFile + } + + $null = $release | Get-GitHubReleaseAsset @downloadParams + It 'Should be able to download the asset file' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue + } + + It 'Should be able the same file' { + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + + It 'Should fail if the download location already exists' { + { $release | Get-GitHubReleaseAsset @downloadParams } | Should -Throw + } + + It 'Should work if the download location already exists and -Force is used' { + $null = $release | Get-GitHubReleaseAsset @downloadParams -Force + + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty } } - Context 'When getting the latest releases via the pipeline' { - $latest = @(Get-GitHubRepository -OwnerName $ownerName -RepositoryName $repositoryName | - Get-GitHubRelease -Latest) + Context 'Verifying a zip file' { + BeforeAll { + $release = $repo | New-GitHubRelease -Tag $defaultTagName + + # To get access to New-TemporaryDirectory + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Helpers.ps1') + $tempPath = New-TemporaryDirectory - It 'Should return one value' { - $latest.Count | Should -Be 1 + $tempFile = New-TemporaryFile + $downloadedZipFile = "$($tempFile.FullName).zip" + Move-Item -Path $tempFile -Destination $downloadedZipFile } - It 'Should return the first release from the full releases list' { - $latest[0].url | Should -Be $releases[0].url - $latest[0].name | Should -Be $releases[0].name + AfterAll { + $release | Remove-GitHubRelease -Force + + Remove-Item -Path $tempPath -Recurse -ErrorAction SilentlyContinue -Force + if (Get-Variable -Name downloadedZipFile -ErrorAction SilentlyContinue) + { + Remove-Item -Path $downloadedZipFile -ErrorAction SilentlyContinue + } + } + + $asset = $release | New-GitHubReleaseAsset -Path $zipFile -ContentType 'application/zip' + It "Has the expected content inside" { + $result = $asset | Get-GitHubReleaseAsset -Path $downloadedZipFile -Force + Expand-Archive -Path $downloadedZipFile -DestinationPath $tempPath + + $result.FullName | Should -BeExactly $downloadedZipFile + + $txtFileName = (Get-Item -Path $txtFile).Name + $downloadedTxtFile = (Get-ChildItem -Path $tempPath -Filter $txtFileName).FullName + + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $downloadedTxtFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + } + } + + Describe 'Set-GitHubReleaseAsset' { + BeforeAll { + $defaultTagName = '0.2.0' + + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName + + $tempFile = New-TemporaryFile + $txtFile = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $txtFile + Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 + + $label = 'mylabel' + } + + AfterAll { + $txtFile | Remove-Item | Out-Null + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + + Context 'Using parameters' { + $fileName = (Get-Item -Path $txtFile).Name + $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile -Label $label + + It 'Has the expected initial property values' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $label + } + + $setParams = @{ + OwnerName = $script:ownerName + RepositoryName = $repo.name + Asset = $asset.id + } + + $updated = Set-GitHubReleaseAsset @setParams + It 'Should have the original property values' { + $updated.name | Should -BeExactly $fileName + $updated.label | Should -BeExactly $label } It 'Should have expected type and additional properties' { - $latest[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $latest[0].html_url.StartsWith($latest[0].RepositoryUrl) | Should -BeTrue - $latest[0].id | Should -Be $latest[0].ReleaseId + $elements = Split-GitHubUri -Uri $updated.url + $repositoryUrl = Join-GitHubUri @elements + + $updated.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $updated.RepositoryUrl | Should -Be $repositoryUrl + $updated.AssetId | Should -Be $updated.id + $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } - $latestAgain = @($latest | Get-GitHubRelease) - It 'Should be the same release' { - $latest[0].ReleaseId | Should -Be $latestAgain[0].ReleaseId + $updatedFileName = 'updated1.txt' + $setParams = @{ + OwnerName = $script:ownerName + RepositoryName = $repo.name + Asset = $asset.id + Name = $updatedFileName + } + + $updated = Set-GitHubReleaseAsset @setParams + It 'Should have a new name and the original label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $label + } + + $updatedLabel = 'updatedLabel2' + $setParams = @{ + OwnerName = $script:ownerName + RepositoryName = $repo.name + Asset = $asset.id + Label = $updatedLabel + } + + $updated = Set-GitHubReleaseAsset @setParams + It 'Should have the current name and a new label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + + $updatedFileName = 'updated3parameter.txt' + $updatedLabel = 'updatedLabel3parameter' + $setParams = @{ + OwnerName = $script:ownerName + RepositoryName = $repo.name + Asset = $asset.id + Name = $updatedFileName + Label = $updatedLabel + } + + $updated = Set-GitHubReleaseAsset @setParams + It 'Should have a new name and a new label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel } } - Context 'When getting a specific release' { - $specificIndex = 5 - $specific = @(Get-GitHubRelease -OwnerName $ownerName -RepositoryName $repositoryName -ReleaseId $releases[$specificIndex].id) + Context 'Using the repo on the pipeline' { + $fileName = (Get-Item -Path $txtFile).Name + $asset = $repo | New-GitHubReleaseAsset -Release $release.id -Path $txtFile -Label $label + + It 'Has the expected initial property values' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $label + } + + $setParams = @{ + Asset = $asset.id + } + + $updated = $repo | Set-GitHubReleaseAsset @setParams + It 'Should have the original property values' { + $updated.name | Should -BeExactly $fileName + $updated.label | Should -BeExactly $label + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $updated.url + $repositoryUrl = Join-GitHubUri @elements + + $updated.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $updated.RepositoryUrl | Should -Be $repositoryUrl + $updated.AssetId | Should -Be $updated.id + $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + $updatedFileName = 'updated1.txt' + $setParams = @{ + Asset = $asset.id + Name = $updatedFileName + } + + $updated = $repo | Set-GitHubReleaseAsset @setParams + It 'Should have a new name and the original label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $label + } + + $updatedLabel = 'updatedLabel2' + $setParams = @{ + Asset = $asset.id + Label = $updatedLabel + } + + $updated = $repo | Set-GitHubReleaseAsset @setParams + It 'Should have the current name and a new label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + + $updatedFileName = 'updated3repo.txt' + $updatedLabel = 'updatedLabel3repo' + $setParams = @{ + Asset = $asset.id + Name = $updatedFileName + Label = $updatedLabel + } + + $updated = $repo | Set-GitHubReleaseAsset @setParams + It 'Should have a new name and a new label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + } + + Context 'Using the release on the pipeline' { + $fileName = (Get-Item -Path $txtFile).Name + $asset = $release | New-GitHubReleaseAsset -Path $txtFile -Label $label + + It 'Has the expected initial property values' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $label + } - It 'Should return one value' { - $specific.Count | Should -Be 1 + $setParams = @{ + Asset = $asset.id } - It 'Should return the correct release' { - $specific.name | Should -Be $releases[$specificIndex].name + $updated = $release | Set-GitHubReleaseAsset @setParams + It 'Should have the original property values' { + $updated.name | Should -BeExactly $fileName + $updated.label | Should -BeExactly $label } It 'Should have expected type and additional properties' { - $specific[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $specific[0].html_url.StartsWith($specific[0].RepositoryUrl) | Should -BeTrue - $specific[0].id | Should -Be $specific[0].ReleaseId + $elements = Split-GitHubUri -Uri $updated.url + $repositoryUrl = Join-GitHubUri @elements + + $updated.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $updated.RepositoryUrl | Should -Be $repositoryUrl + $updated.AssetId | Should -Be $updated.id + $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + $updatedFileName = 'updated1.txt' + $setParams = @{ + Asset = $asset.id + Name = $updatedFileName + } + + $updated = $release | Set-GitHubReleaseAsset @setParams + It 'Should have a new name and the original label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $label + } + + $updatedLabel = 'updatedLabel2' + $setParams = @{ + Asset = $asset.id + Label = $updatedLabel + } + + $updated = $release | Set-GitHubReleaseAsset @setParams + It 'Should have the current name and a new label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + + $updatedFileName = 'updated3release.txt' + $updatedLabel = 'updatedLabel3release' + $setParams = @{ + Asset = $asset.id + Name = $updatedFileName + Label = $updatedLabel + } + + $updated = $release | Set-GitHubReleaseAsset @setParams + It 'Should have a new name and a new label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel } } - Context 'When getting a tagged release' { - $taggedIndex = 8 - $tagged = @(Get-GitHubRelease -OwnerName $ownerName -RepositoryName $repositoryName -Tag $releases[$taggedIndex].tag_name) + Context 'Using the asset on the pipeline' { + $fileName = (Get-Item -Path $txtFile).Name + $asset = $release | New-GitHubReleaseAsset -Path $txtFile -Label $label - It 'Should return one value' { - $tagged.Count | Should -Be 1 + It 'Has the expected initial property values' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $label } - It 'Should return the correct release' { - $tagged.name | Should -Be $releases[$taggedIndex].name + $updated = $asset | Set-GitHubReleaseAsset + It 'Should have the original property values' { + $updated.name | Should -BeExactly $fileName + $updated.label | Should -BeExactly $label } It 'Should have expected type and additional properties' { - $tagged[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $tagged[0].html_url.StartsWith($tagged[0].RepositoryUrl) | Should -BeTrue - $tagged[0].id | Should -Be $tagged[0].ReleaseId + $elements = Split-GitHubUri -Uri $updated.url + $repositoryUrl = Join-GitHubUri @elements + + $updated.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $updated.RepositoryUrl | Should -Be $repositoryUrl + $updated.AssetId | Should -Be $updated.id + $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + $updatedFileName = 'updated1.txt' + $updated = $asset | Set-GitHubReleaseAsset -Name $updatedFileName + It 'Should have a new name and the original label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $label + } + + $updatedLabel = 'updatedLabel2' + $updated = $asset | Set-GitHubReleaseAsset -Label $updatedLabel + It 'Should have the current name and a new label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + + $updatedFileName = 'updated3asset.txt' + $updatedLabel = 'updatedLabel3asset' + $updated = $asset | Set-GitHubReleaseAsset -Name $updatedFileName -Label $updatedLabel + It 'Should have a new name and a new label' { + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel } } } - Describe 'Getting releases from default owner/repository' { - $originalOwnerName = Get-GitHubConfiguration -Name DefaultOwnerName - $originalRepositoryName = Get-GitHubConfiguration -Name DefaultRepositoryName + Describe 'Remove-GitHubReleaseAsset' { + BeforeAll { + $defaultTagName = '0.2.0' - try { - Set-GitHubConfiguration -DefaultOwnerName "dotnet" - Set-GitHubConfiguration -DefaultRepositoryName "core" - $releases = @(Get-GitHubRelease) + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName - Context 'When getting all releases' { - It 'Should return multiple releases' { - $releases.Count | Should -BeGreaterThan 1 - } + $tempFile = New-TemporaryFile + $txtFile = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $txtFile + Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 + } + + AfterAll { + $txtFile | Remove-Item | Out-Null + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + + Context 'Using parameters' { + $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile + + $params = @{ + OwnerName = $script:ownerName + RepositoryName = $repo.name + Asset = $asset.id + Force = $true + } + + Remove-GitHubReleaseAsset @params + It 'Should be successfully deleted' { + { Remove-GitHubReleaseAsset @params } | Should -Throw + } + } + + Context 'Using the repo on the pipeline' { + $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile + + $repo | Remove-GitHubReleaseAsset -Asset $asset.id -Force + It 'Should be successfully deleted' { + { $repo | Remove-GitHubReleaseAsset -Asset $asset.id -Force } | Should -Throw + } + } + + Context 'Using the release on the pipeline' { + $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile + + $release | Remove-GitHubReleaseAsset -Asset $asset.id -Force + It 'Should be successfully deleted' { + { $release | Remove-GitHubReleaseAsset -Asset $asset.id -Force } | Should -Throw + } + } + + Context 'Using the asset on the pipeline' { + $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile + + $asset | Remove-GitHubReleaseAsset -Force + It 'Should be successfully deleted' { + { $asset | Remove-GitHubReleaseAsset -Force } | Should -Throw } - } finally { - Set-GitHubConfiguration -DefaultOwnerName $originalOwnerName - Set-GitHubConfiguration -DefaultRepositoryName $originalRepositoryName } } } @@ -145,4 +1100,4 @@ finally Restore-GitHubConfiguration -Path $script:originalConfigFile $script:originalConfigFile = $null } -} +} \ No newline at end of file diff --git a/USAGE.md b/USAGE.md index bdd04488..8e93a1c5 100644 --- a/USAGE.md +++ b/USAGE.md @@ -86,6 +86,17 @@ * [Add an existing issue as a card to a column](#add-an-existing-issue-as-a-card-to-a-column) * [Move a card to be after a certain card in the same column](Move-a-card-to-be-after-a-certain-card-in-the-same-column) * [Move a card to the bottom of another column](Move-a-card-to-the-bottom-of-another-column) + * [Releases](#Releases) + * [Get releases for a repository](#get-releases-for-a-repository) + * [Get an individual release for a repository](#get-an-individual-release-for-a-repository) + * [Create a new release](#create-a-new-release) + * [Update a release](#update-a-release) + * [Remove a release](#remove-a-release) + * [List assets for a release](#list-assets-for-a-release) + * [Download a release asset](#download-a-release-asset) + * [Create a release asset](#create-a-release-asset) + * [Update a release asset](#update-a-release-asset) + * [Remove a release asset](#remove-a-release-asset) * [Advanced](#advanced) * [Migrating blog comments to GitHub issues](#migrating-blog-comments-to-github-issues) @@ -728,6 +739,140 @@ Move-GitHubProjectCard -Card 4 -ColumnId 6 -Bottom ---------- +### Releases + +#### Get releases for a repository +```powershell +Get-GitHubRelease -OwnerName PowerShell -RepositoryName PowerShell +``` + +or with pipelining... + +```powershell +Get-GitHubRepository -OwnerName PowerShell -RepositoryName PowerShell | + Get-GitHubRelease +``` + +#### Get an individual release for a repository +```powershell +Get-GitHubRelease -OwnerName PowerShell -RepositoryName PowerShell | + Select-Object -First 1 | + Get-GitHubRelease +``` + +#### Create a new release +```powershell +New-GitHubRelease -OwnerName PowerShell -RepositoryName PowerShell -Tag 11.0 +``` + +or with pipelining... + +```powershell +Get-GitHubRepository -OwnerName PowerShell -RepositoryName PowerShell | + New-GitHubRelease -Tag 11.0 +``` + +#### Update a release +```powershell +Set-GitHubRelease -OwnerName PowerShell -RepositoryName PowerShell -Release 123456 -Body 'Updated body' +``` + +or with pipelining... + +```powershell +$repo | Set-GitHubRelease -Release 123456 -Body 'Updated body' + +# or + +$release | Set-GitHubRelease -Body 'Updated body' +``` + +#### Remove a release +```powershell +Remove-GitHubRelease -OwnerName PowerShell -RepositoryName PowerShell -Release 123456 -Force +``` + +or with pipelining... + +```powershell +$repo | Remove-GitHubRelease -Release 123456 -Force + +# or + +$release | Remove-GitHubRelease -Force +``` + +#### List assets for a release +```powershell +Get-GitHubReleaseAsset -OwnerName PowerShell -RepositoryName PowerShell -Release 123456 +``` + +or with pipelining... + +```powershell +$repo | Get-GitHubReleaseAsset -Release 123456 + +# or + +$release | Get-GitHubReleaseAsset +``` + +#### Download a release asset +```powershell +Get-GitHubReleaseAsset -OwnerName PowerShell -RepositoryName PowerShell -Asset 123456 -Path 'c:\downloads\asset' +``` + +or with pipelining... + +```powershell +# Downloads the first asset of the latest release from PowerShell\PowerShell to the file located +# at c:\downloads\asset +Get-GitHubRelease -OwnerName PowerShell -RepositoryName PowerShell -Latest | + Get-GitHubReleaseAsset | + Select-Object -First 1 | + Get-GitHubReleaseAsset -Path 'c:\downloads\asset' +``` + +#### Create a release asset +```powershell +New-GitHubReleaseAsset -OwnerName PowerShell -RepositoryName PowerShell -Release 123456 -Path 'c:\foo.zip' +``` + +or with pipelining... + +```powershell +$release | New-GitHubReleaseAsset -Path 'c:\foo.zip' + +# or + +@('c:\foo.zip', 'c:\bar.txt') | + New-GitHubReleaseAsset -OwnerName PowerShell -RepositoryName PowerShell -Release 123456 +``` + +#### Update a release asset +```powershell +Set-GitHubReleaseAsset -OwnerName PowerShell -RepositoryName PowerShell -Asset 123456 -Name 'newFileName.zip' +``` + +or with pipelining... + +```powershell +$asset | Set-GitHubReleaseAsset -Name 'newFileName.zip' +``` + +#### Remove a release asset +```powershell +Remove-GitHubReleaseAsset -OwnerName PowerShell -RepositoryName PowerShell -Asset 123456 -Force +``` + +or with pipelining... + +```powershell +$asset | Remove-GitHubReleaseAsset -force +``` + +---------- + ### Advanced #### Migrating blog comments to GitHub issues