diff --git a/.github/PSModule.yml b/.github/PSModule.yml
index ed2d635e9..80afa1153 100644
--- a/.github/PSModule.yml
+++ b/.github/PSModule.yml
@@ -1,3 +1,18 @@
Test:
+ SourceCode:
+ Skip: true
+ PSModule:
+ Skip: true
+ Module:
+ Windows:
+ Skip: true
+ MacOS:
+ Skip: true
CodeCoverage:
- PercentTarget: 40
+ Skip: true
+ PercentTarget: 50
+ TestResults:
+ Skip: true
+Build:
+ Docs:
+ Skip: true
diff --git a/Coverage.md b/Coverage.md
index 82f272f63..0c13d6fca 100644
--- a/Coverage.md
+++ b/Coverage.md
@@ -5,19 +5,19 @@
Available functions |
- 1026 |
+ 1027 |
Covered functions |
- 221 |
+ 220 |
Missing functions |
- 805 |
+ 807 |
Coverage |
- 21.54% |
+ 21.42% |
@@ -51,6 +51,7 @@
| `/classrooms/{classroom_id}/assignments` | | :x: | | | |
| `/codes_of_conduct` | | :x: | | | |
| `/codes_of_conduct/{key}` | | :x: | | | |
+| `/credentials/revoke` | | | | :x: | |
| `/emojis` | | :white_check_mark: | | | |
| `/enterprises/{enterprise}/code-security/configurations` | | :x: | | :x: | |
| `/enterprises/{enterprise}/code-security/configurations/defaults` | | :x: | | | |
@@ -539,10 +540,10 @@
| `/repos/{owner}/{repo}/releases` | | :white_check_mark: | | :white_check_mark: | |
| `/repos/{owner}/{repo}/releases/assets/{asset_id}` | :white_check_mark: | :white_check_mark: | :white_check_mark: | | |
| `/repos/{owner}/{repo}/releases/generate-notes` | | | | :white_check_mark: | |
-| `/repos/{owner}/{repo}/releases/latest` | | :white_check_mark: | | | |
-| `/repos/{owner}/{repo}/releases/tags/{tag}` | | :white_check_mark: | | | |
+| `/repos/{owner}/{repo}/releases/latest` | | :x: | | | |
+| `/repos/{owner}/{repo}/releases/tags/{tag}` | | :x: | | | |
| `/repos/{owner}/{repo}/releases/{release_id}` | :white_check_mark: | :white_check_mark: | :white_check_mark: | | |
-| `/repos/{owner}/{repo}/releases/{release_id}/assets` | | :white_check_mark: | | :x: | |
+| `/repos/{owner}/{repo}/releases/{release_id}/assets` | | :white_check_mark: | | :white_check_mark: | |
| `/repos/{owner}/{repo}/releases/{release_id}/reactions` | | :x: | | :x: | |
| `/repos/{owner}/{repo}/releases/{release_id}/reactions/{reaction_id}` | :x: | | | | |
| `/repos/{owner}/{repo}/rules/branches/{branch}` | | :x: | | | |
diff --git a/examples/Releases/Releases.ps1 b/examples/Releases/Releases.ps1
new file mode 100644
index 000000000..1b38c9adf
--- /dev/null
+++ b/examples/Releases/Releases.ps1
@@ -0,0 +1,60 @@
+# Get all the releases for a specific repository
+Get-GitHubRelease -Owner PSModule -Repository GitHub
+
+# Get the latest release for a specific repository
+Get-GitHubRelease -Owner PSModule -Repository GitHub
+
+# Get all the releases for all repos in the organization
+'PSModule' | Get-GitHubOrganization | Get-GitHubRepository | Get-GitHubRelease
+
+# Get the latest releases for all repos in the organization
+'PSModule' | Get-GitHubOrganization | Get-GitHubRepository | ForEach-Object -ThrottleLimit ([Environment]::ProcessorCount) -Parallel {
+ do {
+ Import-Module -Name GitHub
+ } until ($? -eq $true)
+ $_ | Get-GitHubRelease
+}
+
+'PSModule' | Get-GitHubOrganization | Get-GitHubRepository | Get-GitHubRelease -Latest
+Get-GitHubUser | Get-GitHubRepository | Get-GitHubRelease -Latest
+
+# Create a new release for a specific repository
+$repoName = 'mytest'
+
+$repo = Get-GitHubUser | Get-GitHubRepository -Name $repoName
+$repo | Get-GitHubRelease
+$repo | New-GitHubRelease -Tag 'v1.0' -Latest
+$repo | New-GitHubRelease -Tag 'v1.1' -Latest -Name 'test'
+$repo | New-GitHubRelease -Tag 'v1.2' -Latest -Name 'test' -Notes 'Release notes'
+$repo | New-GitHubRelease -Tag 'v1.3' -Latest -Name 'test' -GenerateReleaseNotes
+$repo | Get-GitHubRelease -Tag 'v1.3' | Format-List
+$repo | Get-GitHubRelease -Tag 'v1.3' | Update-GithubRelease -Notes 'Release notes1'
+$repo | Update-GitHubRelease -Tag 'v1.3' -Name 'test123' -Debug
+
+$repo | New-GitHubRelease -Tag 'v1.3.2' -Latest -GenerateReleaseNotes -Debug
+$repo | Get-GitHubRelease -Tag 'v1.3.1' | Format-List
+$repo | Set-GitHubRelease -Tag 'v1.3.1' -Latest -GenerateReleaseNotes -Debug
+$repo | Set-GitHubRelease -Tag 'v1.3.1' -Latest -GenerateReleaseNotes -Notes 'Release notes'
+$repo | Get-GitHubRelease -Tag 'v1.3.1' | Format-List
+Get-GitHubReleaseAsset -Owner MariusStorhaug -Repository mytest -ReleaseID
+
+$repo | Set-GitHubRelease -Tag 'v1.5' -Latest -Name 'test' -Notes 'Release notes' | Select-Object *
+$repo | Get-GitHubRelease -Tag 'v1.4' | Select-Object Tag, Name, Latest, Prerelease, Draft
+$repo | Set-GitHubRelease -Tag 'v1.4' | Select-Object Tag, Name, Latest, Prerelease, Draft
+$repo | Set-GitHubRelease -Tag 'v1.4' -Name 'test2' -Draft | Select-Object Tag, Name, Latest, Prerelease, Draft
+$repo | Set-GitHubRelease -Tag 'v1.4' -Name 'test2' -Draft -Prerelease | Select-Object Tag, Name, Latest, Prerelease, Draft
+$repo | Set-GitHubRelease -Tag 'v1.4' -Name 'test2' -Prerelease | Select-Object Tag, Name, Latest, Prerelease, Draft
+$repo | Set-GitHubRelease -Tag 'v1.4' -Name 'test2' -Latest | Select-Object Tag, Name, Latest, Prerelease, Draft
+$repo | Set-GitHubRelease -Tag 'v1.4' -Name 'test2' | Select-Object Tag, Name, Latest, Prerelease, Draft
+
+$repo | Get-GitHubRelease -Tag 'v1.4' | Select-Object *
+
+$repo | Set-GitHubRelease -Tag 'v1.4' -Name 'test2'
+
+
+New-GitHubReleaseNote -Owner PSModule -Repository GitHub -Tag 'v0.22.0' -Target 'main' -PreviousTag 'v0.20.0' | Format-List
+
+$repo | Get-GitHubRelease | Remove-GitHubRelease
+
+
+$repo | Remove-GitHubRepository -Confirm:$false
diff --git a/src/classes/public/Releases/GitHubRelease.ps1 b/src/classes/public/Releases/GitHubRelease.ps1
new file mode 100644
index 000000000..8ef7adbaf
--- /dev/null
+++ b/src/classes/public/Releases/GitHubRelease.ps1
@@ -0,0 +1,93 @@
+class GitHubRelease : GitHubNode {
+ # Name of the release, can be null
+ # Example: "v0.22.1"
+ [string] $Name
+
+ # The repository where the environment is.
+ [string] $Repository
+
+ # The owner of the environment.
+ [string] $Owner
+
+ # The name of the tag
+ # Example: "v0.22.1"
+ [string] $Tag
+
+ # Release notes or changelog, can be null
+ # Example: "## What's Changed\n### Other Changes\n* Fix: Enhance repository deletion feedback and fix typo..."
+ [string] $Notes
+
+ # Specifies the commitish value that determines where the Git tag is created from
+ # Example: "main"
+ [string] $Target
+
+ # True if the release is the latest release on the repo.
+ # Example: true
+ [bool] $IsLatest
+
+ # True to create a draft (unpublished) release, false to create a published one
+ # Example: false
+ [bool] $IsDraft
+
+ # Whether to identify the release as a prerelease or a full release
+ # Example: false
+ [bool] $IsPrerelease
+
+ # GitHub URL for the release
+ # Example: "https://github.com/PSModule/GitHub/releases/tag/v0.22.1"
+ [string] $Url
+
+ # User who authored the release
+ [GitHubUser] $Author
+
+ # Timestamp when the release was created
+ # Example: "2025-04-11T09:03:38Z"
+ [System.Nullable[datetime]] $CreatedAt
+
+ # Timestamp when the release was published
+ # Example: "2025-04-11T13:41:34Z"
+ [System.Nullable[datetime]] $PublishedAt
+
+ # Timestamp when the release was updated
+ # Example: "2025-04-11T13:41:34Z"
+ [System.Nullable[datetime]] $UpdatedAt
+
+ GitHubRelease() {}
+
+ GitHubRelease([PSCustomObject] $Object, [string] $Owner, [string] $Repository, [System.Nullable[bool]] $Latest) {
+ if ($null -ne $Object.node_id) {
+ $this.ID = $Object.id
+ $this.NodeID = $Object.node_id
+ $this.Tag = $Object.tag_name
+ $this.Name = $Object.name
+ $this.Notes = $Object.body
+ $this.IsLatest = $Latest
+ $this.IsDraft = $Object.draft
+ $this.IsPrerelease = $Object.prerelease
+ $this.Url = $Object.html_url
+ $this.Owner = $Owner
+ $this.Repository = $Repository
+ $this.Target = $Object.target_commitish
+ $this.CreatedAt = $Object.created_at
+ $this.PublishedAt = $Object.published_at
+ $this.Author = [GitHubUser]::new($Object.author)
+ } else {
+ $this.ID = $Object.databaseId
+ $this.NodeID = $Object.id
+ $this.Tag = $Object.tagName
+ $this.Name = $Object.name
+ $this.Notes = $Object.description
+ $this.IsLatest = $Object.isLatest
+ $this.IsDraft = $Object.isDraft
+ $this.IsPrerelease = $Object.isPrerelease
+ $this.Url = $Object.url
+ $this.Owner = $Owner
+ $this.Repository = $Repository
+ # $this.Target = $Object.target_commitish
+ $this.CreatedAt = $Object.createdAt
+ $this.PublishedAt = $Object.publishedAt
+ $this.UpdatedAt = $Object.updatedAt
+ $this.Author = [GitHubUser]::new($Object.author)
+ }
+ }
+}
diff --git a/src/classes/public/Releases/GitHubReleaseAsset.ps1 b/src/classes/public/Releases/GitHubReleaseAsset.ps1
new file mode 100644
index 000000000..1382ae2d4
--- /dev/null
+++ b/src/classes/public/Releases/GitHubReleaseAsset.ps1
@@ -0,0 +1,73 @@
+class GitHubReleaseAsset : GitHubNode {
+ # Description: URL for downloading the asset
+ # Example: "https://github.com/PSModule/GitHub/releases/download/v0.22.1/asset.zip"
+ [string] $Url
+
+ # Description: The file name of the asset
+ # Example: "Team Environment"
+ [string] $Name
+
+ # Description: Label for the asset, can be null
+ # Example: null
+ [string] $Label
+
+ # Description: State of the release asset (e.g., uploaded, open)
+ # Example: "uploaded"
+ [string] $State
+
+ # Description: MIME type of the asset
+ # Example: "application/zip"
+ [string] $ContentType
+
+ # Description: Size of the asset in bytes
+ # Example: 1024
+ [int] $Size
+
+ # Description: Number of times the asset was downloaded
+ # Example: 100
+ [int] $Downloads
+
+ # Description: Timestamp when the asset was created
+ # Example: "2025-04-11T09:03:38Z"
+ [System.Nullable[datetime]] $CreatedAt
+
+ # Description: Timestamp when the asset was last updated
+ # Example: "2025-04-11T09:03:38Z"
+ [System.Nullable[datetime]] $UpdatedAt
+
+ # Description: User who uploaded the asset, can be null
+ # Example: GitHubUser object or null
+ [GitHubUser] $UploadedBy
+
+ GitHubReleaseAsset() {}
+
+ GitHubReleaseAsset([PSCustomObject]$Object) {
+ if ($null -ne $Object.node_id) {
+ $this.ID = $Object.id
+ $this.NodeID = $Object.node_id
+ $this.Url = $Object.browser_download_url
+ $this.Name = $Object.name
+ $this.Label = $Object.label
+ $this.State = $Object.state
+ $this.ContentType = $Object.content_type
+ $this.Size = $Object.size
+ $this.Downloads = $Object.download_count
+ $this.CreatedAt = [datetime]::Parse($Object.created_at)
+ $this.UpdatedAt = [datetime]::Parse($Object.updated_at)
+ $this.UploadedBy = [GitHubUser]::new($Object.uploader)
+ } else {
+ $this.ID = $Object.databaseId
+ $this.NodeID = $Object.id
+ $this.Url = $Object.downloadUrl
+ $this.Name = $Object.name
+ $this.Label = $Object.label
+ $this.State = $Object.state
+ $this.ContentType = $Object.contentType
+ $this.Size = $Object.size
+ $this.Downloads = $Object.downloadCount
+ $this.CreatedAt = [datetime]::Parse($Object.createdAt)
+ $this.UpdatedAt = [datetime]::Parse($Object.updatedAt)
+ $this.UploadedBy = [GitHubUser]::new($Object.uploadedBy)
+ }
+ }
+}
diff --git a/src/formats/GitHubRelease.Format.ps1xml b/src/formats/GitHubRelease.Format.ps1xml
new file mode 100644
index 000000000..223919863
--- /dev/null
+++ b/src/formats/GitHubRelease.Format.ps1xml
@@ -0,0 +1,119 @@
+
+
+
+
+ GitHubReleaseTable
+
+ GitHubRelease
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tag
+
+
+ Owner
+
+
+ Repository
+
+
+ Url
+
+
+ IsLatest
+
+
+ IsPrerelease
+
+
+ IsDraft
+
+
+
+
+
+
+
+ GitHubReleaseList
+
+ GitHubRelease
+
+
+
+
+
+
+ Tag
+
+
+ Owner
+
+
+ Repository
+
+
+ Url
+
+
+ Author
+
+
+ Target
+
+
+ IsLatest
+
+
+ IsDraft
+
+
+ IsPrerelease
+
+
+ CreatedAt
+
+
+ PublishedAt
+
+
+ Assets
+
+
+ Name
+
+
+ Notes
+
+
+
+
+
+
+
+
diff --git a/src/functions/private/Auth/Context/Resolve-GitHubContextSetting.ps1 b/src/functions/private/Auth/Context/Resolve-GitHubContextSetting.ps1
index bcfc2f646..b152c6e96 100644
--- a/src/functions/private/Auth/Context/Resolve-GitHubContextSetting.ps1
+++ b/src/functions/private/Auth/Context/Resolve-GitHubContextSetting.ps1
@@ -58,6 +58,10 @@
[object] $Context
)
+ if ($Name -eq 'PerPage' -and $Value -eq 0) {
+ $Value = $null
+ }
+
Write-Debug "Resolving setting [$Name]"
[pscustomobject]@{
'Name' = $Name
diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1
index e7a739fba..464d7df2f 100644
--- a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1
+++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByID.ps1
@@ -14,10 +14,13 @@
Gets the release asset with the ID '1234567' for the repository 'octocat/hello-world'.
+ .OUTPUTS
+ GitHubReleaseAsset
+
.NOTES
https://docs.github.com/rest/releases/assets#get-a-release-asset
-
#>
+ [OutputType([GitHubReleaseAsset])]
[CmdletBinding()]
param(
# The account owner of the repository. The name is not case sensitive.
@@ -30,7 +33,6 @@
# The unique identifier of the asset.
[Parameter(Mandatory)]
- [Alias('asset_id')]
[string] $ID,
# The context to run the command in. Used to get the details for the API call.
@@ -53,7 +55,7 @@
}
Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
+ [GitHubReleaseAsset]($_.Response)
}
}
diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1
index 512f93e4a..69e22f23a 100644
--- a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1
+++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByReleaseID.ps1
@@ -30,7 +30,6 @@
Mandatory,
ParameterSetName = 'ID'
)]
- [Alias('release_id')]
[string] $ID,
# The number of results per page (max 100).
@@ -63,7 +62,9 @@
}
Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
+ foreach ($asset in $_.Response) {
+ [GitHubReleaseAsset]($asset)
+ }
}
}
end {
diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByTag.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByTag.ps1
new file mode 100644
index 000000000..2a7649382
--- /dev/null
+++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetByTag.ps1
@@ -0,0 +1,113 @@
+filter Get-GitHubReleaseAssetByTag {
+ <#
+ .SYNOPSIS
+ Get release assets by tag name
+
+ .DESCRIPTION
+ Gets all assets from a release identified by its tag name.
+ Uses pagination to retrieve all assets even if there are more than the maximum per page.
+
+ .EXAMPLE
+ Get-GitHubReleaseAssetByTag -Owner 'octocat' -Repository 'hello-world' -Tag 'v1.0.0'
+
+ Gets all release assets for the release with the tag 'v1.0.0' for the repository 'octocat/hello-world'.
+
+ .OUTPUTS
+ GitHubReleaseAsset
+ #>
+ [OutputType([GitHubReleaseAsset])]
+ [CmdletBinding()]
+ param(
+ # The account owner of the repository. The name is not case sensitive.
+ [Parameter(Mandatory)]
+ [string] $Owner,
+
+ # The name of the repository without the .git extension. The name is not case sensitive.
+ [Parameter(Mandatory)]
+ [string] $Repository,
+
+ # The name of the tag to get a release from.
+ [Parameter(Mandatory)]
+ [string] $Tag,
+
+ # The number of results per page (max 100).
+ [Parameter()]
+ [ValidateRange(0, 100)]
+ [int] $PerPage,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter(Mandatory)]
+ [object] $Context
+ )
+
+ begin {
+ $stackPath = Get-PSCallStackPath
+ Write-Debug "[$stackPath] - Start"
+ Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
+ }
+
+ process {
+ $hasNextPage = $true
+ $after = $null
+ $perPageSetting = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context
+
+ do {
+ $inputObject = @{
+ Query = @'
+query($owner: String!, $repository: String!, $tag: String!, $perPage: Int, $after: String) {
+ repository(owner: $owner, name: $repository) {
+ release(tagName: $tag) {
+ releaseAssets(first: $perPage, after: $after) {
+ nodes {
+ id
+ databaseId
+ name
+ label
+ state
+ contentType
+ size
+ downloadCount
+ downloadUrl
+ url
+ createdAt
+ updatedAt
+ uploadedBy {
+ login
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+ }
+}
+'@
+ Variables = @{
+ owner = $Owner
+ repository = $Repository
+ tag = $Tag
+ perPage = $perPageSetting
+ after = $after
+ }
+ Context = $Context
+ }
+
+ Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object {
+ $release = $_.repository.release
+ $assets = $release.releaseAssets
+ foreach ($asset in $assets.nodes) {
+ [GitHubReleaseAsset]::new($asset)
+ }
+ $hasNextPage = $assets.pageInfo.hasNextPage
+ $after = $assets.pageInfo.endCursor
+ }
+ } while ($hasNextPage)
+ }
+
+ end {
+ Write-Debug "[$stackPath] - End"
+ }
+}
diff --git a/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetFromLatest.ps1 b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetFromLatest.ps1
new file mode 100644
index 000000000..fc2205836
--- /dev/null
+++ b/src/functions/private/Releases/Assets/Get-GitHubReleaseAssetFromLatest.ps1
@@ -0,0 +1,112 @@
+filter Get-GitHubReleaseAssetFromLatest {
+ <#
+ .SYNOPSIS
+ Get the assets of the latest release
+
+ .DESCRIPTION
+ Gets all assets for the latest published full release for the repository.
+ The latest release is the most recent non-prerelease, non-draft release, sorted by the `created_at` attribute.
+ The `created_at` attribute is the date of the commit used for the release, and not the date when the release was drafted or published.
+
+ .EXAMPLE
+ Get-GitHubReleaseAssetFromLatest -Owner 'octocat' -Repository 'hello-world'
+
+ Gets the assets for the latest release of the repository 'hello-world' owned by 'octocat'.
+
+ .INPUTS
+ GitHubRepository
+
+ .OUTPUTS
+ GitHubReleaseAsset
+ #>
+ [OutputType([GitHubReleaseAsset])]
+ [CmdletBinding()]
+ param(
+ # The account owner of the repository. The name is not case sensitive.
+ [Parameter(Mandatory)]
+ [string] $Owner,
+
+ # The name of the repository without the .git extension. The name is not case sensitive.
+ [Parameter(Mandatory)]
+ [string] $Repository,
+
+ # The number of results per page (max 100).
+ [Parameter()]
+ [ValidateRange(0, 100)]
+ [int] $PerPage,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter(Mandatory)]
+ [object] $Context
+ )
+
+ begin {
+ $stackPath = Get-PSCallStackPath
+ Write-Debug "[$stackPath] - Start"
+ Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
+ }
+
+ process {
+ $hasNextPage = $true
+ $after = $null
+ $perPageSetting = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context
+
+ do {
+ $inputObject = @{
+ Query = @'
+query($owner: String!, $repository: String!, $perPage: Int, $after: String) {
+ repository(owner: $owner, name: $repository) {
+ latestRelease {
+ releaseAssets(first: $perPage, after: $after) {
+ nodes {
+ id
+ databaseId
+ name
+ label
+ state
+ contentType
+ size
+ downloadCount
+ downloadUrl
+ url
+ createdAt
+ updatedAt
+ uploadedBy {
+ login
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+ }
+}
+'@
+ Variables = @{
+ owner = $Owner
+ repository = $Repository
+ perPage = $perPageSetting
+ after = $after
+ }
+ Context = $Context
+ }
+
+ Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object {
+ $release = $_.repository.latestRelease
+ $assets = $release.releaseAssets
+ foreach ($asset in $assets.nodes) {
+ [GitHubReleaseAsset]::new($asset)
+ }
+ $hasNextPage = $assets.pageInfo.hasNextPage
+ $after = $assets.pageInfo.endCursor
+ }
+ } while ($hasNextPage)
+ }
+
+ end {
+ Write-Debug "[$stackPath] - End"
+ }
+}
diff --git a/src/functions/private/Releases/Get-GitHubReleaseAll.ps1 b/src/functions/private/Releases/Get-GitHubReleaseAll.ps1
new file mode 100644
index 000000000..b20f6bc04
--- /dev/null
+++ b/src/functions/private/Releases/Get-GitHubReleaseAll.ps1
@@ -0,0 +1,111 @@
+filter Get-GitHubReleaseAll {
+ <#
+ .SYNOPSIS
+ List releases
+
+ .DESCRIPTION
+ This returns a list of releases, which does not include regular Git tags that have not been associated with a release.
+ To get a list of Git tags, use the [Repository Tags API](https://docs.github.com/rest/repos/repos#list-repository-tags).
+ Information about published releases are available to everyone. Only users with push access will receive listings for draft releases.
+
+ .EXAMPLE
+ Get-GitHubReleaseAll -Owner 'octocat' -Repository 'hello-world'
+
+ Gets all the releases for the repository 'hello-world' owned by 'octocat'.
+
+ .INPUTS
+ GitHubRepository
+
+ .OUTPUTS
+ GitHubRelease
+
+ .LINK
+ [List releases](https://docs.github.com/rest/releases/releases#list-releases)
+ #>
+ [OutputType([GitHubRelease])]
+ [CmdletBinding(SupportsPaging)]
+ param(
+ # The account owner of the repository. The name is not case sensitive.
+ [Parameter(Mandatory)]
+ [string] $Owner,
+
+ # The name of the repository without the .git extension. The name is not case sensitive.
+ [Parameter(Mandatory)]
+ [string] $Repository,
+
+ # The number of results per page (max 100).
+ [Parameter()]
+ [ValidateRange(0, 100)]
+ [int] $PerPage,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter(Mandatory)]
+ [object] $Context
+ )
+
+ begin {
+ $stackPath = Get-PSCallStackPath
+ Write-Debug "[$stackPath] - Start"
+ Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
+ }
+
+ process {
+ $hasNextPage = $true
+ $after = $null
+ $perPageSetting = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context
+
+ do {
+ $inputObject = @{
+ Query = @'
+query($owner: String!, $repository: String!, $perPage: Int, $after: String) {
+ repository(owner: $owner, name: $repository) {
+ releases(first: $perPage, after: $after) {
+ nodes {
+ id
+ databaseId
+ tagName
+ name
+ description
+ isLatest
+ isDraft
+ isPrerelease
+ url
+ createdAt
+ publishedAt
+ updatedAt
+ author {
+ login
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+}
+'@
+ Variables = @{
+ owner = $Owner
+ repository = $Repository
+ perPage = $perPageSetting
+ after = $after
+ }
+ Context = $Context
+ }
+
+ Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object {
+ foreach ($release in $_.repository.releases.nodes) {
+ [GitHubRelease]::new($release, $Owner, $Repository, $null)
+ }
+ $hasNextPage = $_.repository.releases.pageInfo.hasNextPage
+ $after = $_.repository.releases.pageInfo.endCursor
+ }
+ } while ($hasNextPage)
+ }
+
+ end {
+ Write-Debug "[$stackPath] - End"
+ }
+}
diff --git a/src/functions/private/Releases/Releases/Get-GitHubReleaseByID.ps1 b/src/functions/private/Releases/Get-GitHubReleaseByID.ps1
similarity index 73%
rename from src/functions/private/Releases/Releases/Get-GitHubReleaseByID.ps1
rename to src/functions/private/Releases/Get-GitHubReleaseByID.ps1
index dc0c5c030..350bed5f1 100644
--- a/src/functions/private/Releases/Releases/Get-GitHubReleaseByID.ps1
+++ b/src/functions/private/Releases/Get-GitHubReleaseByID.ps1
@@ -12,10 +12,16 @@
Gets the release with the ID '1234567' for the repository 'hello-world' owned by 'octocat'.
- .NOTES
- https://docs.github.com/rest/releases/releases#get-a-release
+ .INPUTS
+ GitHubRepository
+ .OUTPUTS
+ GitHubRelease
+
+ .LINK
+ [Get a release](https://docs.github.com/rest/releases/releases#get-a-release)
#>
+ [OutputType([GitHubRelease])]
[CmdletBinding()]
param(
# The account owner of the repository. The name is not case sensitive.
@@ -28,7 +34,6 @@
# The unique identifier of the release.
[Parameter(Mandatory)]
- [Alias('release_id')]
[string] $ID,
# The context to run the command in. Used to get the details for the API call.
@@ -44,15 +49,20 @@
}
process {
+ $latest = Get-GitHubReleaseLatest -Owner $Owner -Repository $Repository -Context $Context
+
$inputObject = @{
Method = 'GET'
APIEndpoint = "/repos/$Owner/$Repository/releases/$ID"
Context = $Context
}
- Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
- }
+ try {
+ Invoke-GitHubAPI @inputObject | ForEach-Object {
+ $isLatest = $_.Response.id -eq $latest.id
+ [GitHubRelease]::new($_.Response, $Owner, $Repository, $isLatest)
+ }
+ } catch { return }
}
end {
diff --git a/src/functions/private/Releases/Releases/Get-GitHubReleaseByTagName.ps1 b/src/functions/private/Releases/Get-GitHubReleaseByTagName.ps1
similarity index 56%
rename from src/functions/private/Releases/Releases/Get-GitHubReleaseByTagName.ps1
rename to src/functions/private/Releases/Get-GitHubReleaseByTagName.ps1
index 519cf54f4..cad6a7d30 100644
--- a/src/functions/private/Releases/Releases/Get-GitHubReleaseByTagName.ps1
+++ b/src/functions/private/Releases/Get-GitHubReleaseByTagName.ps1
@@ -11,10 +11,16 @@
Gets the release with the tag 'v1.0.0' for the repository 'hello-world' owned by 'octocat'.
- .NOTES
- https://docs.github.com/rest/releases/releases#get-a-release-by-tag-name
+ .INPUTS
+ GitHubRepository
+ .OUTPUTS
+ GitHubRelease
+
+ .LINK
+ [Get a release by tag name](https://docs.github.com/rest/releases/releases#get-a-release-by-tag-name)
#>
+ [OutputType([GitHubRelease])]
[CmdletBinding()]
param(
# The account owner of the repository. The name is not case sensitive.
@@ -27,7 +33,6 @@
# The name of the tag to get a release from.
[Parameter(Mandatory)]
- [Alias('tag_name')]
[string] $Tag,
# The context to run the command in. Used to get the details for the API call.
@@ -44,13 +49,42 @@
process {
$inputObject = @{
- Method = 'GET'
- APIEndpoint = "/repos/$Owner/$Repository/releases/tags/$Tag"
- Context = $Context
+ Query = @'
+query($owner: String!, $repository: String!, $tag: String!) {
+ repository(owner: $owner, name: $repository) {
+ release(tagName: $tag) {
+ id
+ databaseId
+ tagName
+ name
+ description
+ isLatest
+ isDraft
+ isPrerelease
+ url
+ createdAt
+ publishedAt
+ updatedAt
+ author {
+ login
+ }
+ }
+ }
+}
+'@
+ Variables = @{
+ owner = $Owner
+ repository = $Repository
+ tag = $Tag
+ }
+ Context = $Context
}
- Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
+ Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object {
+ $release = $_.repository.release
+ if ($release) {
+ [GitHubRelease]::new($release, $Owner, $Repository, $null)
+ }
}
}
diff --git a/src/functions/private/Releases/Releases/Get-GitHubReleaseLatest.ps1 b/src/functions/private/Releases/Get-GitHubReleaseLatest.ps1
similarity index 59%
rename from src/functions/private/Releases/Releases/Get-GitHubReleaseLatest.ps1
rename to src/functions/private/Releases/Get-GitHubReleaseLatest.ps1
index 80f7a6936..d4421fd51 100644
--- a/src/functions/private/Releases/Releases/Get-GitHubReleaseLatest.ps1
+++ b/src/functions/private/Releases/Get-GitHubReleaseLatest.ps1
@@ -13,10 +13,16 @@
Gets the latest releases for the repository 'hello-world' owned by 'octocat'.
- .NOTES
- https://docs.github.com/rest/releases/releases#get-the-latest-release
+ .INPUTS
+ GitHubRepository
+ .OUTPUTS
+ GitHubRelease
+
+ .LINK
+ [Get the latest release](https://docs.github.com/rest/releases/releases#get-the-latest-release)
#>
+ [OutputType([GitHubRelease])]
[CmdletBinding()]
param(
# The account owner of the repository. The name is not case sensitive.
@@ -41,13 +47,41 @@
process {
$inputObject = @{
- Method = 'GET'
- APIEndpoint = "/repos/$Owner/$Repository/releases/latest"
- Context = $Context
+ Query = @'
+query($owner: String!, $repository: String!) {
+ repository(owner: $owner, name: $repository) {
+ latestRelease {
+ id
+ databaseId
+ tagName
+ name
+ description
+ isLatest
+ isDraft
+ isPrerelease
+ url
+ createdAt
+ publishedAt
+ updatedAt
+ author {
+ login
+ }
+ }
+ }
+}
+'@
+ Variables = @{
+ owner = $Owner
+ repository = $Repository
+ }
+ Context = $Context
}
- Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
+ Invoke-GitHubGraphQLQuery @inputObject | ForEach-Object {
+ $release = $_.repository.latestRelease
+ if ($release) {
+ [GitHubRelease]::new($release, $Owner, $Repository, $null)
+ }
}
}
diff --git a/src/functions/private/Releases/Releases/Get-GitHubReleaseAll.ps1 b/src/functions/private/Releases/Releases/Get-GitHubReleaseAll.ps1
deleted file mode 100644
index bd5c52614..000000000
--- a/src/functions/private/Releases/Releases/Get-GitHubReleaseAll.ps1
+++ /dev/null
@@ -1,66 +0,0 @@
-filter Get-GitHubReleaseAll {
- <#
- .SYNOPSIS
- List releases
-
- .DESCRIPTION
- This returns a list of releases, which does not include regular Git tags that have not been associated with a release.
- To get a list of Git tags, use the [Repository Tags API](https://docs.github.com/rest/repos/repos#list-repository-tags).
- Information about published releases are available to everyone. Only users with push access will receive listings for draft releases.
-
- .EXAMPLE
- Get-GitHubReleaseAll -Owner 'octocat' -Repository 'hello-world'
-
- Gets all the releases for the repository 'hello-world' owned by 'octocat'.
-
- .NOTES
- https://docs.github.com/rest/releases/releases#list-releases
-
- #>
- [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')]
- param(
- # The account owner of the repository. The name is not case sensitive.
- [Parameter(Mandatory)]
- [string] $Owner,
-
- # The name of the repository without the .git extension. The name is not case sensitive.
- [Parameter(Mandatory)]
- [string] $Repository,
-
- # The number of results per page (max 100).
- [Parameter(ParameterSetName = 'AllUsers')]
- [ValidateRange(0, 100)]
- [int] $PerPage,
-
- # The context to run the command in. Used to get the details for the API call.
- # Can be either a string or a GitHubContext object.
- [Parameter(Mandatory)]
- [object] $Context
- )
-
- begin {
- $stackPath = Get-PSCallStackPath
- Write-Debug "[$stackPath] - Start"
- Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
- }
-
- process {
- $body = @{
- per_page = $PerPage
- }
-
- $inputObject = @{
- Method = 'GET'
- APIEndpoint = "/repos/$Owner/$Repository/releases"
- Body = $body
- Context = $Context
- }
-
- Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
- }
- }
- end {
- Write-Debug "[$stackPath] - End"
- }
-}
diff --git a/src/functions/public/API/Invoke-GitHubAPI.ps1 b/src/functions/public/API/Invoke-GitHubAPI.ps1
index 0cf5d8996..2967876fa 100644
--- a/src/functions/public/API/Invoke-GitHubAPI.ps1
+++ b/src/functions/public/API/Invoke-GitHubAPI.ps1
@@ -177,9 +177,9 @@ filter Invoke-GitHubAPI {
if (-not $Body) {
$Body = @{}
}
-
$Body['per_page'] = Resolve-GitHubContextSetting -Name 'PerPage' -Value $PerPage -Context $Context
-
+ $APICall.Uri = New-Uri -BaseUri $Uri -Query $Body -AsString
+ } elseif (($Method -eq 'POST') -and -not [string]::IsNullOrEmpty($UploadFilePath)) {
$APICall.Uri = New-Uri -BaseUri $Uri -Query $Body -AsString
} elseif ($Body) {
if ($Body -is [hashtable]) {
@@ -279,6 +279,7 @@ filter Invoke-GitHubAPI {
} while ($APICall['Uri'])
} catch {
$failure = $_
+ $failure | Out-String -Stream | ForEach-Object { Write-Debug $_ }
$headers = @{}
foreach ($item in $failure.Exception.Response.Headers.GetEnumerator()) {
$headers[$item.Key] = ($item.Value).Trim() -join ', '
diff --git a/src/functions/public/Organization/Get-GitHubOrganization.ps1 b/src/functions/public/Organization/Get-GitHubOrganization.ps1
index 84afe544a..999d44558 100644
--- a/src/functions/public/Organization/Get-GitHubOrganization.ps1
+++ b/src/functions/public/Organization/Get-GitHubOrganization.ps1
@@ -36,7 +36,7 @@
https://psmodule.io/GitHub/Functions/Organization/Get-GitHubOrganization
#>
[OutputType([GitHubOrganization])]
- [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')]
+ [CmdletBinding(DefaultParameterSetName = 'List organizations for the authenticated user')]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'All', Justification = 'Required for parameter set')]
param(
# The organization name. The name is not case sensitive.
@@ -71,7 +71,7 @@
# The number of results per page (max 100).
[Parameter(ParameterSetName = 'AllOrg')]
[Parameter(ParameterSetName = 'UserOrg')]
- [Parameter(ParameterSetName = '__AllParameterSets')]
+ [Parameter(ParameterSetName = 'List organizations for the authenticated user')]
[ValidateRange(0, 100)]
[int] $PerPage,
@@ -99,7 +99,7 @@
'AllOrg' {
Get-GitHubAllOrganization -Since $Since -PerPage $PerPage -Context $Context
}
- default {
+ 'List organizations for the authenticated user' {
Get-GitHubMyOrganization -PerPage $PerPage -Context $Context
}
}
diff --git a/src/functions/public/Organization/completers.ps1 b/src/functions/public/Organization/completers.ps1
new file mode 100644
index 000000000..43b6a920f
--- /dev/null
+++ b/src/functions/public/Organization/completers.ps1
@@ -0,0 +1,14 @@
+Register-ArgumentCompleter -CommandName ($script:PSModuleInfo.FunctionsToExport) -ParameterName Name -ScriptBlock {
+ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
+ $null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter
+
+ if ($fakeBoundParameter.ContainsKey('Context')) {
+ $orgs = Get-GitHubOrganization -Verbose:$false -Debug:$false -Context $fakeBoundParameter.Context
+ } else {
+ $orgs = Get-GitHubOrganization -Verbose:$false -Debug:$false
+ }
+
+ $orgs | Where-Object { $_.CompletionText -like "$wordToComplete*" } | ForEach-Object {
+ [System.Management.Automation.CompletionResult]::new($_, ($_ | Format-Table -HideTableHeaders), 'ParameterValue', $_.Description)
+ }
+}
diff --git a/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1
index b52da2c5e..cdf97b05e 100644
--- a/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1
+++ b/src/functions/public/Releases/Assets/Add-GitHubReleaseAsset.ps1
@@ -37,29 +37,38 @@
the old file before you can re-upload the new asset.
.EXAMPLE
- Add-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -ID '7654321' -FilePath 'C:\Users\octocat\Downloads\hello-world.zip'
+ Add-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -ID '7654321' -Path 'C:\Users\octocat\Downloads\hello-world.zip'
Gets the release assets for the release with the ID '1234567' for the repository 'octocat/hello-world'.
+ .EXAMPLE
+ Add-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -ID '7654321' -Path 'C:\Users\octocat\Projects\MyApp'
+
+ Automatically creates a zip file from the contents of the MyApp directory and uploads it as a release asset.
+
+ .INPUTS
+ GitHubRelease
+
+ .OUTPUTS
+ GitHubReleaseAsset
+
.NOTES
[Upload a release asset](https://docs.github.com/rest/releases/assets#upload-a-release-asset)
#>
[CmdletBinding()]
param(
# The account owner of the repository. The name is not case sensitive.
- [Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias('Organization', 'User')]
[string] $Owner,
# The name of the repository without the .git extension. The name is not case sensitive.
- [Parameter(Mandatory)]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string] $Repository,
- # The unique identifier of the release.
- [Parameter(Mandatory)]
- [Alias('release_id')]
- [string] $ID,
+ # The name of the tag to get a release from.
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [string] $Tag,
#The name of the file asset.
[Parameter()]
@@ -69,14 +78,14 @@
[Parameter()]
[string] $Label,
- # The content type of the asset.
- [Parameter()]
- [string] $ContentType,
-
# The path to the asset file.
[Parameter(Mandatory)]
[alias('FullName')]
- [string] $FilePath,
+ [string] $Path,
+
+ # The 'Content-Type' for the payload.
+ [Parameter()]
+ [string] $ContentType,
# The context to run the command in. Used to get the details for the API call.
# Can be either a string or a GitHubContext object.
@@ -92,19 +101,36 @@
}
process {
- # If name is not provided, use the name of the file
+ try {
+ $item = Get-Item $Path
+ $isDirectory = $item.PSIsContainer
+ } catch {
+ throw "Error accessing the path: $_"
+ }
+ $fileToUpload = $Path
+ # If the path is a directory, create a zip file from the contents of the folder
+ if ($isDirectory) {
+ Write-Verbose 'Path is a directory. Zipping contents...'
+ $dirName = $item.Name
+ $TempFilePath = "$dirName.zip"
+
+ Write-Verbose "Creating temporary zip file: $TempFilePath"
+ try {
+ Get-ChildItem -Path $Path | Compress-Archive -DestinationPath $TempFilePath -ErrorAction Stop -Force
+ $fileToUpload = $TempFilePath
+ } catch {
+ Remove-Item -Path $TempFilePath -Force -ErrorAction SilentlyContinue
+ }
+ }
if (!$Name) {
- $Name = (Get-Item $FilePath).Name
+ $Name = (Get-Item $Path).Name
}
-
- # If label is not provided, use the name of the file
if (!$Label) {
- $Label = (Get-Item $FilePath).Name
+ $Label = (Get-Item $Path).Name
}
- # If content type is not provided, use the file extension
if (!$ContentType) {
- $ContentType = switch ((Get-Item $FilePath).Extension) {
+ $ContentType = switch ((Get-Item $fileToUpload).Extension) {
'.zip' { 'application/zip' }
'.tar' { 'application/x-tar' }
'.gz' { 'application/gzip' }
@@ -127,24 +153,45 @@
}
}
- $release = Get-GitHubRelease -Owner $Owner -Repository $Repository -ID $ID
- $uploadURI = $release.upload_url -replace '{\?name,label}', "?name=$($Name)&label=$($Label)"
+ $release = Get-GitHubReleaseByTagName -Owner $Owner -Repository $Repository -Tag $Tag -Context $Context
+
+ $body = @{
+ name = $Name
+ label = $Label
+ }
+ $body | Remove-HashtableEntry -NullOrEmptyValues
+
+ $urlParams = @{
+ BaseUri = "https://uploads.$($Context.HostName)"
+ Path = "/repos/$Owner/$Repository/releases/$($release.id)/assets"
+ Query = $body
+ }
+ $uploadUrl = New-Uri @urlParams
$inputObject = @{
Method = 'POST'
- URI = $uploadURI
+ Uri = $uploadUrl
ContentType = $ContentType
- UploadFilePath = $FilePath
+ UploadFilePath = $fileToUpload
+ Context = $Context
}
Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
+ [GitHubReleaseAsset]($_.Response)
}
}
end {
Write-Debug "[$stackPath] - End"
}
+
+ clean {
+ # Clean up temporary file if created
+ if ($isDirectory) {
+ Write-Verbose "Cleaning up temporary zip file: $TempFilePath"
+ Remove-Item -Path $TempFilePath -Force -ErrorAction SilentlyContinue
+ }
+ }
}
#SkipTest:FunctionTest:Will add a test for this function in a future PR
diff --git a/src/functions/public/Releases/Assets/Get-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Get-GitHubReleaseAsset.ps1
index 5106d462b..4d1693a09 100644
--- a/src/functions/public/Releases/Assets/Get-GitHubReleaseAsset.ps1
+++ b/src/functions/public/Releases/Assets/Get-GitHubReleaseAsset.ps1
@@ -1,11 +1,13 @@
filter Get-GitHubReleaseAsset {
<#
.SYNOPSIS
- List release assets based on a release ID or asset ID
+ List release assets based on a release ID, asset ID, or asset name
.DESCRIPTION
If an asset ID is provided, the asset is returned.
If a release ID is provided, all assets for the release are returned.
+ If a release ID and name are provided, the specific named asset from that release is returned.
+ If a tag and name are provided, the specific named asset from the release with that tag is returned.
.EXAMPLE
Get-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -ID '1234567'
@@ -15,39 +17,62 @@
.EXAMPLE
Get-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -ReleaseID '7654321'
- Gets the release assets for the release with the ID '7654321' for the repository 'octocat/hello-world'.
+ Gets all release assets for the release with the ID '7654321' for the repository 'octocat/hello-world'.
- .NOTES
- [Get a release asset](https://docs.github.com/rest/releases/assets#get-a-release-asset)
+ .EXAMPLE
+ Get-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -ReleaseID '7654321' -Name 'example.zip'
+
+ Gets the release asset named 'example.zip' from the release with ID '7654321' for the repository 'octocat/hello-world'.
+
+ .EXAMPLE
+ Get-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -Tag 'v1.0.0' -Name 'example.zip'
+
+ Gets the release asset named 'example.zip' from the release tagged as 'v1.0.0' for the repository 'octocat/hello-world'.
+
+ .INPUTS
+ GitHubRelease
+
+ .OUTPUTS
+ GitHubReleaseAsset
+
+ .LINK
+ https://psmodule.io/GitHub/Functions/Releases/Assets/Get-GitHubReleaseAsset
#>
- [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')]
+ [OutputType([GitHubReleaseAsset])]
+ [CmdletBinding(DefaultParameterSetName = 'List assets from the latest release')]
param(
# The account owner of the repository. The name is not case sensitive.
- [Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias('Organization', 'User')]
[string] $Owner,
# The name of the repository without the .git extension. The name is not case sensitive.
- [Parameter(Mandatory)]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string] $Repository,
# The unique identifier of the asset.
- [Parameter(
- Mandatory,
- ParameterSetName = 'ID'
- )]
- [Alias('asset_id')]
+ [Parameter(Mandatory, ParameterSetName = 'Get a specific asset by ID')]
[string] $ID,
# The unique identifier of the release.
- [Parameter(
- Mandatory,
- ParameterSetName = 'ReleaseID'
- )]
- [Alias('release_id')]
+ [Parameter(Mandatory, ParameterSetName = 'List assets from a release', ValueFromPipelineByPropertyName)]
+ [Parameter(Mandatory, ParameterSetName = 'Get a specific asset by name from a release ID', ValueFromPipelineByPropertyName)]
[string] $ReleaseID,
+ # The tag name of the release.
+ [Parameter(Mandatory, ParameterSetName = 'Get a specific asset by name from a tag')]
+ [string] $Tag,
+
+ # The name of the asset to find.
+ [Parameter(Mandatory, ParameterSetName = 'Get a specific asset by name from a release ID')]
+ [Parameter(Mandatory, ParameterSetName = 'Get a specific asset by name from a tag')]
+ [string] $Name,
+
+ # The number of results per page (max 100).
+ [Parameter()]
+ [ValidateRange(0, 100)]
+ [int] $PerPage,
+
# The context to run the command in. Used to get the details for the API call.
# Can be either a string or a GitHubContext object.
[Parameter()]
@@ -62,12 +87,35 @@
}
process {
+ $params = @{
+ Owner = $Owner
+ Repository = $Repository
+ PerPage = $PerPage
+ Context = $Context
+ }
+ $params | Remove-HashtableEntry -NullOrEmptyValues
+
switch ($PSCmdlet.ParameterSetName) {
- 'ReleaseID' {
- Get-GitHubReleaseAssetByReleaseID -Owner $Owner -Repository $Repository -ReleaseID $ReleaseID -Context $Context
+ 'List assets from the latest release' {
+ Get-GitHubReleaseAssetFromLatest @params
+ }
+ 'List assets from a release' {
+ Get-GitHubReleaseAssetByReleaseID @params -ID $ReleaseID
+ }
+ 'Get a specific asset by ID' {
+ Get-GitHubReleaseAssetByID @params -ID $ID
+ }
+ 'Get a specific asset by name from a release ID' {
+ $assets = Get-GitHubReleaseAssetByReleaseID @params -ID $ReleaseID
+ $asset = $assets | Where-Object { $_.Name -eq $Name }
+ if ($asset) {
+ $asset
+ } else {
+ Write-Warning "Asset with name '$Name' not found in release with ID '$ReleaseID'"
+ }
}
- 'ID' {
- Get-GitHubReleaseAssetByID -Owner $Owner -Repository $Repository -ID $ID -Context $Context
+ 'Get a specific asset by name from a tag' {
+ Get-GitHubReleaseAssetByTag @params -Tag $Tag -Name $Name
}
}
}
diff --git a/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1
index b6eaecfe8..a9a589ebb 100644
--- a/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1
+++ b/src/functions/public/Releases/Assets/Remove-GitHubReleaseAsset.ps1
@@ -11,6 +11,9 @@
Deletes the release asset with the ID '1234567' for the repository 'octocat/hello-world'.
+ .LINK
+ https://psmodule.io/GitHub/Functions/Releases/Assets/Remove-GitHubReleaseAsset
+
.NOTES
[Delete a release asset](https://docs.github.com/rest/releases/assets#delete-a-release-asset)
#>
@@ -18,8 +21,7 @@
param(
# The account owner of the repository. The name is not case sensitive.
[Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
+ [Alias('Organization', 'User')]
[string] $Owner,
# The name of the repository without the .git extension. The name is not case sensitive.
@@ -28,7 +30,6 @@
# The unique identifier of the asset.
[Parameter(Mandatory)]
- [Alias('asset_id')]
[string] $ID,
# The context to run the command in. Used to get the details for the API call.
diff --git a/src/functions/public/Releases/Assets/Set-GitHubReleaseAsset.ps1 b/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1
similarity index 88%
rename from src/functions/public/Releases/Assets/Set-GitHubReleaseAsset.ps1
rename to src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1
index a5def48de..2988f4371 100644
--- a/src/functions/public/Releases/Assets/Set-GitHubReleaseAsset.ps1
+++ b/src/functions/public/Releases/Assets/Update-GitHubReleaseAsset.ps1
@@ -1,4 +1,4 @@
-filter Set-GitHubReleaseAsset {
+filter Update-GitHubReleaseAsset {
<#
.SYNOPSIS
Update a release asset
@@ -7,11 +7,14 @@
Users with push access to the repository can edit a release asset.
.EXAMPLE
- Set-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -ID '1234567' -Name 'new_asset_name' -Label 'new_asset_label'
+ Update-GitHubReleaseAsset -Owner 'octocat' -Repository 'hello-world' -ID '1234567' -Name 'new_asset_name' -Label 'new_asset_label'
Updates the release asset with the ID '1234567' for the repository 'octocat/hello-world' with the new name 'new_asset_name' and
label 'new_asset_label'.
+ .LINK
+ https://psmodule.io/GitHub/Functions/Releases/Assets/Update-GitHubReleaseAsset
+
.NOTES
[Update a release asset](https://docs.github.com/rest/releases/assets#update-a-release-asset)
#>
@@ -19,8 +22,7 @@
param(
# The account owner of the repository. The name is not case sensitive.
[Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
+ [Alias('Organization', 'User')]
[string] $Owner,
# The name of the repository without the .git extension. The name is not case sensitive.
@@ -29,7 +31,6 @@
# The unique identifier of the asset.
[Parameter(Mandatory)]
- [Alias('asset_id')]
[string] $ID,
#The name of the file asset.
diff --git a/src/functions/public/Releases/Releases/Get-GitHubRelease.ps1 b/src/functions/public/Releases/Get-GitHubRelease.ps1
similarity index 55%
rename from src/functions/public/Releases/Releases/Get-GitHubRelease.ps1
rename to src/functions/public/Releases/Get-GitHubRelease.ps1
index ede7522d6..a52b1a424 100644
--- a/src/functions/public/Releases/Releases/Get-GitHubRelease.ps1
+++ b/src/functions/public/Releases/Get-GitHubRelease.ps1
@@ -1,7 +1,7 @@
filter Get-GitHubRelease {
<#
.SYNOPSIS
- List releases
+ Retrieves GitHub release information for a repository.
.DESCRIPTION
This returns a list of releases, which does not include regular Git tags that have not been associated with a release.
@@ -11,12 +11,12 @@
.EXAMPLE
Get-GitHubRelease -Owner 'octocat' -Repository 'hello-world'
- Gets the releases for the repository 'hello-world' owned by 'octocat'.
+ Gets the latest release for the repository 'hello-world' owned by 'octocat'.
.EXAMPLE
- Get-GitHubRelease -Owner 'octocat' -Repository 'hello-world' -Latest
+ Get-GitHubRelease -Owner 'octocat' -Repository 'hello-world' -AllVersions
- Gets the latest releases for the repository 'hello-world' owned by 'octocat'.
+ Gets all releases for the repository 'hello-world' owned by 'octocat'.
.EXAMPLE
Get-GitHubRelease -Owner 'octocat' -Repository 'hello-world' -Tag 'v1.0.0'
@@ -28,51 +28,48 @@
Gets the release with the ID '1234567' for the repository 'hello-world' owned by 'octocat'.
- .NOTES
- [List releases](https://docs.github.com/rest/releases/releases#list-releases)
- [Get the latest release](https://docs.github.com/rest/releases/releases#get-the-latest-release)
+ .INPUTS
+ GitHubRepository
+
+ .OUTPUTS
+ GitHubRelease
+
+ .LINK
+ https://psmodule.io/GitHub/Functions/Releases/Get-GitHubRelease/
#>
- [CmdletBinding(DefaultParameterSetName = 'All')]
- [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Latest', Justification = 'Required for parameter set')]
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
+ 'PSReviewUnusedParameter', 'AllVersions',
+ Justification = 'Using the ParameterSetName to determine the context of the command.'
+ )]
+ [OutputType([GitHubRelease])]
+ [CmdletBinding(DefaultParameterSetName = 'Latest')]
param(
# The account owner of the repository. The name is not case sensitive.
- [Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias('Organization', 'User')]
[string] $Owner,
# The name of the repository without the .git extension. The name is not case sensitive.
- [Parameter(Mandatory)]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string] $Repository,
- # The number of results per page (max 100).
- [Parameter(ParameterSetName = 'All')]
- [ValidateRange(0, 100)]
- [int] $PerPage,
-
- # Get the latest release only
- [Parameter(
- Mandatory,
- ParameterSetName = 'Latest'
- )]
- [switch] $Latest,
+ # Get all releases instead of just the latest.
+ [Parameter(Mandatory, ParameterSetName = 'AllVersions')]
+ [switch] $AllVersions,
# The name of the tag to get a release from.
- [Parameter(
- Mandatory,
- ParameterSetName = 'Tag'
- )]
- [Alias('tag_name')]
+ [Parameter(Mandatory, ParameterSetName = 'Tag')]
[string] $Tag,
# The unique identifier of the release.
- [Parameter(
- Mandatory,
- ParameterSetName = 'ID'
- )]
- [Alias('release_id')]
+ [Parameter(Mandatory, ParameterSetName = 'ID')]
[string] $ID,
+ # The number of results per page (max 100).
+ [Parameter(ParameterSetName = 'AllVersions')]
+ [ValidateRange(0, 100)]
+ [int] $PerPage,
+
# The context to run the command in. Used to get the details for the API call.
# Can be either a string or a GitHubContext object.
[Parameter()]
@@ -87,26 +84,34 @@
}
process {
+ $params = @{
+ Owner = $Owner
+ Repository = $Repository
+ Context = $Context
+ }
+ Write-Debug "ParameterSet: $($PSCmdlet.ParameterSetName)"
switch ($PSCmdlet.ParameterSetName) {
- 'All' {
- Get-GitHubReleaseAll -Owner $Owner -Repository $Repository -PerPage $PerPage -Context $Context
- }
- 'Latest' {
- Get-GitHubReleaseLatest -Owner $Owner -Repository $Repository -Context $Context
+ 'AllVersions' {
+ Get-GitHubReleaseAll @params -PerPage $PerPage
}
'Tag' {
- Get-GitHubReleaseByTagName -Owner $Owner -Repository $Repository -Tag $Tag -Context $Context
+ $release = Get-GitHubReleaseByTagName @params -Tag $Tag
+ if ($release) {
+ $release
+ } else {
+ Get-GithubReleaseAll @params -PerPage $PerPage | Where-Object { $_.Tag -eq $Tag }
+ }
}
'ID' {
- Get-GitHubReleaseByID -Owner $Owner -Repository $Repository -ID $ID -Context $Context
+ Get-GitHubReleaseByID @params -ID $ID
+ }
+ 'Latest' {
+ Get-GitHubReleaseLatest @params
}
}
-
}
end {
Write-Debug "[$stackPath] - End"
}
}
-
-#SkipTest:FunctionTest:Will add a test for this function in a future PR
diff --git a/src/functions/public/Releases/Releases/New-GitHubRelease.ps1 b/src/functions/public/Releases/New-GitHubRelease.ps1
similarity index 67%
rename from src/functions/public/Releases/Releases/New-GitHubRelease.ps1
rename to src/functions/public/Releases/New-GitHubRelease.ps1
index 021a3900a..cbbead9a3 100644
--- a/src/functions/public/Releases/Releases/New-GitHubRelease.ps1
+++ b/src/functions/public/Releases/New-GitHubRelease.ps1
@@ -11,38 +11,44 @@
and "[Dealing with secondary rate limits](https://docs.github.com/rest/guides/best-practices-for-integrators#dealing-with-secondary-rate-limits)" for details.
.EXAMPLE
- New-GitHubRelease -Owner 'octocat' -Repository 'hello-world' -TagName 'v1.0.0' -TargetCommitish 'main' -Body 'Release notes'
+ New-GitHubRelease -Owner 'octocat' -Repository 'hello-world' -Tag 'v1.0.0' -Target 'main' -Notes 'Release notes'
- Creates a release for the repository 'octocat/hello-world' with the tag 'v1.0.0' and the target commitish 'main'.
+ Creates a release for the repository 'octocat/hello-world' on the 'main' branch with the tag 'v1.0.0'.
- .NOTES
+ .INPUTS
+ GitHubRepository
+
+ .OUTPUTS
+ GitHubRelease
+
+ .LINK
+ https://psmodule.io/GitHub/Functions/Releases/New-GitHubRelease/
+
+ .LINK
[Create a release](https://docs.github.com/rest/releases/releases#create-a-release)
#>
- [OutputType([pscustomobject])]
+ [OutputType([GitHubRelease])]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')]
- [CmdletBinding(SupportsShouldProcess)]
+ [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Not latest')]
param(
# The account owner of the repository. The name is not case sensitive.
- [Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias('Organization', 'User')]
[string] $Owner,
# The name of the repository without the .git extension. The name is not case sensitive.
- [Parameter(Mandatory)]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string] $Repository,
# The name of the tag.
[Parameter(Mandatory)]
- [Alias('tag_name')]
- [string] $TagName,
+ [string] $Tag,
- # Specifies the commitish value that determines where the Git tag is created from.
+ # Specifies the reference value that determines where the Git tag is created from.
# Can be any branch or commit SHA. Unused if the Git tag already exists.
# API Default: the repository's default branch.
[Parameter()]
- [Alias('target_commitish')]
- [string] $TargetCommitish = 'main',
+ [string] $Target = 'main',
# The name of the release.
[Parameter()]
@@ -50,33 +56,33 @@
# Text describing the contents of the tag.
[Parameter()]
- [string] $Body,
+ [string] $Notes,
# Whether the release is a draft.
- [Parameter()]
+ [Parameter(ParameterSetName = 'Not latest')]
[switch] $Draft,
# Whether to identify the release as a prerelease.
- [Parameter()]
+ [Parameter(ParameterSetName = 'Not latest')]
[switch] $Prerelease,
# If specified, a discussion of the specified category is created and linked to the release.
# The value must be a category that already exists in the repository.
# For more information, see [Managing categories for discussions in your repository](https://docs.github.com/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository).
[Parameter()]
- [Alias('discussion_category_name')]
[string] $DiscussionCategoryName,
- # Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise,a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes.
+ # Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise,
+ # a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes.
[Parameter()]
- [Alias('generate_release_notes')]
[switch] $GenerateReleaseNotes,
- # Specifies whether this release should be set as the latest release for the repository. Drafts and prereleases cannot be set as latest. Defaults to true for newly published releases. legacy specifies that the latest release should be determined based on the release creation date and higher semantic version.
- [Parameter()]
- [Alias('make_latest')]
- [ValidateSet('true', 'false', 'legacy')]
- [string] $MakeLatest = 'true',
+ # Specifies whether this release should be set as the latest release for the repository. Drafts and prereleases cannot be set as latest.
+ # If not specified the latest release is determined based on the release creation date and higher semantic version.
+ # If set to true, the release will be set as the latest release for the repository.
+ # If set to false, the release will not be set as the latest release for the repository.
+ [Parameter(ParameterSetName = 'Set latest')]
+ [switch] $Latest,
# The context to run the command in. Used to get the details for the API call.
# Can be either a string or a GitHubContext object.
@@ -93,15 +99,15 @@
process {
$body = @{
- tag_name = $TagName
- target_commitish = $TargetCommitish
+ tag_name = $Tag
+ target_commitish = $Target
name = $Name
- body = $Body
+ body = $Notes
discussion_category_name = $DiscussionCategoryName
- make_latest = $MakeLatest
- generate_release_notes = $GenerateReleaseNotes
- draft = $Draft
- prerelease = $Prerelease
+ generate_release_notes = [bool]$GenerateReleaseNotes
+ make_latest = ([bool]$Latest).ToString().ToLower()
+ draft = [bool]$Draft
+ prerelease = [bool]$Prerelease
}
$body | Remove-HashtableEntry -NullOrEmptyValues
@@ -114,7 +120,7 @@
if ($PSCmdlet.ShouldProcess("$Owner/$Repository", 'Create a release')) {
Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
+ [GitHubRelease]::new($_.Response , $Owner, $Repository, $Latest)
}
}
}
@@ -123,5 +129,3 @@
Write-Debug "[$stackPath] - End"
}
}
-
-#SkipTest:FunctionTest:Will add a test for this function in a future PR
diff --git a/src/functions/public/Releases/Releases/New-GitHubReleaseNote.ps1 b/src/functions/public/Releases/New-GitHubReleaseNote.ps1
similarity index 67%
rename from src/functions/public/Releases/Releases/New-GitHubReleaseNote.ps1
rename to src/functions/public/Releases/New-GitHubReleaseNote.ps1
index 849b1ed34..db375f580 100644
--- a/src/functions/public/Releases/Releases/New-GitHubReleaseNote.ps1
+++ b/src/functions/public/Releases/New-GitHubReleaseNote.ps1
@@ -1,19 +1,18 @@
filter New-GitHubReleaseNote {
<#
.SYNOPSIS
- List releases
+ Generate release notes content for a release.
.DESCRIPTION
- Generate a name and body describing a [release](https://docs.github.com/rest/releases/releases#get-a-release).
- The body content will be Markdown formatted and contain information like
- the changes since last release and users who contributed. The generated release notes are not saved anywhere. They are
- intended to be generated and used when creating a new release.
+ Generate a name and body describing a [release](https://docs.github.com/rest/releases/releases#get-a-release). The body content will be
+ markdown formatted and contain information like the changes since last release and users who contributed. The generated release notes are not
+ saved anywhere. They are intended to be generated and used when creating a new release.
.EXAMPLE
$params = @{
- Owner = 'octocat'
- Repo = 'hello-world'
- TagName = 'v1.0.0'
+ Owner = 'octocat'
+ Repo = 'hello-world'
+ Tag = 'v1.0.0'
}
New-GitHubReleaseNote @params
@@ -23,10 +22,10 @@
.EXAMPLE
$params = @{
- Owner = 'octocat'
- Repo = 'hello-world'
- TagName = 'v1.0.0'
- TargetCommitish = 'main'
+ Owner = 'octocat'
+ Repo = 'hello-world'
+ Tag = 'v1.0.0'
+ Target = 'main'
}
New-GitHubReleaseNote @params
@@ -37,9 +36,9 @@
$params = @{
Owner = 'octocat'
Repo = 'hello-world'
- TagName = 'v1.0.0'
- TargetCommitish = 'main'
- PreviousTagName = 'v0.9.2'
+ Tag = 'v1.0.0'
+ Target = 'main'
+ PreviousTag = 'v0.9.2'
ConfigurationFilePath = '.github/custom_release_config.yml'
}
New-GitHubReleaseNote @params
@@ -48,8 +47,19 @@
The release notes will be based on the changes between the tags 'v0.9.2' and 'v1.0.0' and generated based on the
configuration file located in the repository at '.github/custom_release_config.yml'.
+ .OUTPUTS
+ pscustomobject
+
.NOTES
- [Generate release notes content for a release](https://docs.github.com/rest/releases/releases#list-releases)
+ The returned object contains the following properties:
+ - Name: The name of the release.
+ - Notes: The body of the release notes.
+
+ .LINK
+ https://psmodule.io/GitHub/Functions/Releases/New-GitHubReleaseNote/
+
+ .LINK
+ [Generate release notes content for a release](https://docs.github.com/rest/releases/releases#generate-release-notes-content-for-a-release)
#>
[OutputType([pscustomobject])]
[Alias('Generate-GitHubReleaseNotes')]
@@ -57,39 +67,33 @@
[CmdletBinding(SupportsShouldProcess)]
param(
# The account owner of the repository. The name is not case sensitive.
- [Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias('Organization', 'User')]
[string] $Owner,
# The name of the repository without the .git extension. The name is not case sensitive.
- [Parameter(Mandatory)]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string] $Repository,
# The tag name for the release. This can be an existing tag or a new one.
- [Parameter(Mandatory)]
- [Alias('tag_name')]
- [string] $TagName,
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [string] $Tag,
# Specifies the commitish value that will be the target for the release's tag.
# Required if the supplied tag_name does not reference an existing tag.
# Ignored if the tag_name already exists.
[Parameter()]
- [Alias('target_commitish')]
- [string] $TargetCommitish,
+ [string] $Target,
# The name of the previous tag to use as the starting point for the release notes.
# Use to manually specify the range for the set of changes considered as part this release.
[Parameter()]
- [Alias('previous_tag_name')]
- [string] $PreviousTagName,
-
+ [string] $PreviousTag,
# Specifies a path to a file in the repository containing configuration settings used for generating the release notes.
# If unspecified, the configuration file located in the repository at '.github/release.yml' or '.github/release.yaml' will be used.
# If that is not present, the default configuration will be used.
[Parameter()]
- [Alias('configuration_file_path')]
[string] $ConfigurationFilePath,
# The context to run the command in. Used to get the details for the API call.
@@ -107,9 +111,9 @@
process {
$body = @{
- tag_name = $TagName
- target_commitish = $TargetCommitish
- previous_tag_name = $PreviousTagName
+ tag_name = $Tag
+ target_commitish = $Target
+ previous_tag_name = $PreviousTag
configuration_file_path = $ConfigurationFilePath
}
$body | Remove-HashtableEntry -NullOrEmptyValues
@@ -118,11 +122,15 @@
Method = 'POST'
APIEndpoint = "/repos/$Owner/$Repository/releases/generate-notes"
Body = $body
+ Context = $Context
}
- if ($PSCmdlet.ShouldProcess("$Owner/$Repository", 'Create release notes')) {
+ if ($PSCmdlet.ShouldProcess("release notes for release on $Owner/$Repository", 'Create')) {
Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
+ [PSCustomObject]@{
+ Name = $_.Response.name
+ Notes = $_.Response.body
+ }
}
}
}
diff --git a/src/functions/public/Releases/Releases/Set-GitHubRelease.ps1 b/src/functions/public/Releases/Releases/Set-GitHubRelease.ps1
deleted file mode 100644
index 1559ef234..000000000
--- a/src/functions/public/Releases/Releases/Set-GitHubRelease.ps1
+++ /dev/null
@@ -1,124 +0,0 @@
-filter Set-GitHubRelease {
- <#
- .SYNOPSIS
- Update a release
-
- .DESCRIPTION
- Users with push access to the repository can edit a release.
-
- .EXAMPLE
- Set-GitHubRelease -Owner 'octocat' -Repository 'hello-world' -ID '1234567' -Body 'Release notes'
-
- Updates the release with the ID '1234567' for the repository 'octocat/hello-world' with the body 'Release notes'.
-
- .NOTES
- [Update a release](https://docs.github.com/rest/releases/releases#update-a-release)
- #>
- [OutputType([pscustomobject])]
- [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')]
- [CmdletBinding(SupportsShouldProcess)]
- param(
- # The account owner of the repository. The name is not case sensitive.
- [Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
- [string] $Owner,
-
- # The name of the repository without the .git extension. The name is not case sensitive.
- [Parameter(Mandatory)]
- [string] $Repository,
-
- # The unique identifier of the release.
- [Parameter(Mandatory)]
- [Alias('release_id')]
- [string] $ID,
-
- # The name of the tag.
- [Parameter()]
- [Alias('tag_name')]
- [string] $TagName,
-
- # Specifies the commitish value that determines where the Git tag is created from.
- # Can be any branch or commit SHA. Unused if the Git tag already exists.
- # API Default: the repository's default branch.
- [Parameter()]
- [Alias('target_commitish')]
- [string] $TargetCommitish,
-
- # The name of the release.
- [Parameter()]
- [string] $Name,
-
- # Text describing the contents of the tag.
- [Parameter()]
- [string] $Body,
-
- # Whether the release is a draft.
- [Parameter()]
- [switch] $Draft,
-
- # Whether to identify the release as a prerelease.
- [Parameter()]
- [switch] $Prerelease,
-
- # If specified, a discussion of the specified category is created and linked to the release.
- # The value must be a category that already exists in the repository.
- # For more information, see [Managing categories for discussions in your repository](https://docs.github.com/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository).
- [Parameter()]
- [Alias('discussion_category_name')]
- [string] $DiscussionCategoryName,
-
- # Specifies whether this release should be set as the latest release for the repository. Drafts and prereleases cannot be set as latest.
- # Defaults to true for newly published releases. legacy specifies that the latest release should be determined based on the release creation
- # date and higher semantic version.
- [Parameter()]
- [Alias('make_latest')]
- [ValidateSet('true', 'false', 'legacy')]
- [string] $MakeLatest = 'true',
-
- # The context to run the command in. Used to get the details for the API call.
- # Can be either a string or a GitHubContext object.
- [Parameter()]
- [object] $Context = (Get-GitHubContext)
- )
-
- begin {
- $stackPath = Get-PSCallStackPath
- Write-Debug "[$stackPath] - Start"
- $Context = Resolve-GitHubContext -Context $Context
- Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
- }
-
- process {
- $body = @{
- tag_name = $TagName
- target_commitish = $TargetCommitish
- name = $Name
- body = $Body
- discussion_category_name = $DiscussionCategoryName
- make_latest = $MakeLatest
- draft = $Draft
- prerelease = $Prerelease
- }
- $body | Remove-HashtableEntry -NullOrEmptyValues
-
- $inputObject = @{
- Method = 'PATCH'
- APIEndpoint = "/repos/$Owner/$Repository/releases/$ID"
- Body = $body
- Context = $Context
- }
-
- if ($PSCmdlet.ShouldProcess("release with ID [$ID] in [$Owner/$Repository]", 'Update')) {
- Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
- }
- }
- }
-
- end {
- Write-Debug "[$stackPath] - End"
- }
-}
-
-#SkipTest:FunctionTest:Will add a test for this function in a future PR
diff --git a/src/functions/public/Releases/Releases/Remove-GitHubRelease.ps1 b/src/functions/public/Releases/Remove-GitHubRelease.ps1
similarity index 77%
rename from src/functions/public/Releases/Releases/Remove-GitHubRelease.ps1
rename to src/functions/public/Releases/Remove-GitHubRelease.ps1
index 1184c427e..c6b045dcb 100644
--- a/src/functions/public/Releases/Releases/Remove-GitHubRelease.ps1
+++ b/src/functions/public/Releases/Remove-GitHubRelease.ps1
@@ -11,27 +11,29 @@
Deletes the release with the ID '1234567' for the repository 'octocat/hello-world'.
- .NOTES
+ .INPUTS
+ GitHubRelease
+
+ .LINK
+ https://psmodule.io/GitHub/Functions/Releases/Get-GitHubRelease/
+
+ .LINK
[Delete a release](https://docs.github.com/rest/releases/releases#delete-a-release)
#>
- [OutputType([pscustomobject])]
+ [OutputType([void])]
[CmdletBinding(SupportsShouldProcess)]
param(
# The account owner of the repository. The name is not case sensitive.
- [Parameter(Mandatory)]
- [Alias('Organization')]
- [Alias('User')]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias('Organization', 'User')]
[string] $Owner,
# The name of the repository without the .git extension. The name is not case sensitive.
- [Parameter(Mandatory)]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string] $Repository,
# The unique identifier of the release.
- [Parameter(
- Mandatory
- )]
- [Alias('release_id')]
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string] $ID,
# The context to run the command in. Used to get the details for the API call.
@@ -54,10 +56,8 @@
Context = $Context
}
- if ($PSCmdlet.ShouldProcess("Release with ID [$ID] in [$Owner/$Repository]", 'DELETE')) {
- Invoke-GitHubAPI @inputObject | ForEach-Object {
- Write-Output $_.Response
- }
+ if ($PSCmdlet.ShouldProcess("Release with ID [$ID] in [$Owner/$Repository]", 'Delete')) {
+ $null = Invoke-GitHubAPI @inputObject
}
}
@@ -65,5 +65,3 @@
Write-Debug "[$stackPath] - End"
}
}
-
-#SkipTest:FunctionTest:Will add a test for this function in a future PR
diff --git a/src/functions/public/Releases/Set-GitHubRelease.ps1 b/src/functions/public/Releases/Set-GitHubRelease.ps1
new file mode 100644
index 000000000..98d1a376e
--- /dev/null
+++ b/src/functions/public/Releases/Set-GitHubRelease.ps1
@@ -0,0 +1,126 @@
+filter Set-GitHubRelease {
+ <#
+ .SYNOPSIS
+ Creates or updates a release.
+
+ .DESCRIPTION
+
+
+ .EXAMPLE
+ Set-GitHubRelease -Owner 'octocat' -Repository 'hello-world' -Tag 'v1.0.0' -Target 'main' -Notes 'Release notes'
+
+ .INPUTS
+ GitHubRepository
+
+ .OUTPUTS
+ GitHubRelease
+
+ .LINK
+ https://psmodule.io/GitHub/Functions/Releases/Set-GitHubRelease/
+ #>
+ [OutputType([GitHubRelease])]
+ [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Not latest')]
+ param(
+ # The account owner of the repository. The name is not case sensitive.
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias('Organization', 'User')]
+ [string] $Owner,
+
+ # The name of the repository without the .git extension. The name is not case sensitive.
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [string] $Repository,
+
+ # The name of the tag.
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [string] $Tag,
+
+ # Specifies the reference value that determines where the Git tag is created from.
+ # Can be any branch or commit SHA. Unused if the Git tag already exists.
+ # API Default: the repository's default branch.
+ [Parameter()]
+ [string] $Target = 'main',
+
+ # The name of the release.
+ [Parameter()]
+ [string] $Name = '',
+
+ # Text describing the contents of the tag.
+ [Parameter()]
+ [string] $Notes = '',
+
+ # Whether the release is a draft.
+ [Parameter(ParameterSetName = 'Not latest')]
+ [switch] $Draft,
+
+ # Whether to identify the release as a prerelease.
+ [Parameter(ParameterSetName = 'Not latest')]
+ [switch] $Prerelease,
+
+ # If specified, a discussion of the specified category is created and linked to the release.
+ # The value must be a category that already exists in the repository.
+ [Parameter()]
+ [string] $DiscussionCategoryName,
+
+ # Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise,
+ # a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes.
+ [Parameter()]
+ [switch] $GenerateReleaseNotes,
+
+ # Specifies whether this release should be set as the latest release for the repository. If the release is a draft or a prerelease, setting
+ # this parameters will promote the release to a release, setting the draft and prerelease parameters to false.
+ [Parameter(Mandatory, ParameterSetName = 'Set latest')]
+ [switch] $Latest,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+
+ begin {
+ $stackPath = Get-PSCallStackPath
+ Write-Debug "[$stackPath] - Start"
+ $Context = Resolve-GitHubContext -Context $Context
+ Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
+ }
+
+ process {
+ $scope = @{
+ Owner = $Owner
+ Repository = $Repository
+ Context = $Context
+ }
+
+ $params = @{
+ Tag = $Tag
+ Target = $Target
+ Name = $Name
+ Notes = $Notes
+ GenerateReleaseNotes = [bool]$GenerateReleaseNotes
+ DiscussionCategoryName = $DiscussionCategoryName
+ }
+
+ switch ($PSCmdlet.ParameterSetName) {
+ 'Set latest' {
+ $params['Latest'] = [bool]$Latest
+ }
+ 'Not latest' {
+ $params['Draft'] = [bool]$Draft
+ $params['Prerelease'] = [bool]$Prerelease
+ }
+ }
+
+ $release = Get-GitHubRelease @scope -Tag $Tag
+ if ($release) {
+ $ID = $release.ID
+ $params['ID'] = $ID
+ Update-GitHubRelease @scope @params -Declare
+ } else {
+ New-GitHubRelease @scope @params
+ }
+ }
+
+ end {
+ Write-Debug "[$stackPath] - End"
+ }
+}
diff --git a/src/functions/public/Releases/Update-GitHubRelease.ps1 b/src/functions/public/Releases/Update-GitHubRelease.ps1
new file mode 100644
index 000000000..8382b6fa8
--- /dev/null
+++ b/src/functions/public/Releases/Update-GitHubRelease.ps1
@@ -0,0 +1,171 @@
+filter Update-GitHubRelease {
+ <#
+ .SYNOPSIS
+ Update a release
+
+ .DESCRIPTION
+ Users with push access to the repository can edit a release.
+
+ .EXAMPLE
+ Update-GitHubRelease -Owner 'octocat' -Repository 'hello-world' -ID '1234567' -Notes 'Release notes'
+
+ Updates the release with the ID '1234567' for the repository 'octocat/hello-world' with the note 'Release notes'.
+
+ .LINK
+ https://psmodule.io/github/Functions/Releases/Update-GitHubRelease
+
+ .NOTES
+ [Update a release](https://docs.github.com/rest/releases/releases#update-a-release)
+ #>
+ [OutputType([pscustomobject])]
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')]
+ [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Not latest')]
+ param(
+ # The account owner of the repository. The name is not case sensitive.
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [Alias('Organization', 'User')]
+ [string] $Owner,
+
+ # The name of the repository without the .git extension. The name is not case sensitive.
+ [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
+ [string] $Repository,
+
+ # The unique identifier of the release.
+ [Parameter()]
+ [string] $ID,
+
+ # The name of the tag.
+ [Parameter()]
+ [string] $Tag,
+
+ # Specifies the commitish value that determines where the Git tag is created from.
+ # Can be any branch or commit SHA. Unused if the Git tag already exists.
+ # API Default: the repository's default branch.
+ [Parameter()]
+ [string] $Target,
+
+ # The name of the release.
+ [Parameter()]
+ [string] $Name,
+
+ # Text describing the contents of the tag.
+ [Parameter()]
+ [string] $Notes,
+
+ # Whether the release is a draft.
+ [Parameter(ParameterSetName = 'Not latest')]
+ [System.Nullable[switch]] $Draft,
+
+ # Whether to identify the release as a prerelease.
+ [Parameter(ParameterSetName = 'Not latest')]
+ [System.Nullable[switch]] $Prerelease,
+
+ # If specified, a discussion of the specified category is created and linked to the release.
+ # The value must be a category that already exists in the repository.
+ # For more information, see [Managing categories for discussions in your repository](https://docs.github.com/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository).
+ [Parameter()]
+ [string] $DiscussionCategoryName,
+
+ # Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise,
+ # a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes.
+ [Parameter()]
+ [switch] $GenerateReleaseNotes,
+
+ # Specifies whether this release should be set as the latest release for the repository. If the release is a draft or a prerelease, setting
+ # this parameters will promote the release to a release, setting the draft and prerelease parameters to false.
+ [Parameter(Mandatory, ParameterSetName = 'Set latest')]
+ [System.Nullable[switch]] $Latest,
+
+ # Takes all parameters and updates the release with the provided _AND_ the default values of the non-provided parameters.
+ # Used for Set-GitHubRelease.
+ [Parameter()]
+ [switch] $Declare,
+
+ # The release to update
+ [Parameter(ValueFromPipeline)]
+ [GitHubRelease] $ReleaseObject,
+
+ # The context to run the command in. Used to get the details for the API call.
+ # Can be either a string or a GitHubContext object.
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+
+ begin {
+ $stackPath = Get-PSCallStackPath
+ Write-Debug "[$stackPath] - Start"
+ $Context = Resolve-GitHubContext -Context $Context
+ Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
+ }
+
+ process {
+ $ID = $ReleaseObject.ID
+
+ if (-not $ID -and -not $Tag) {
+ throw 'You must specify either the ID or the Tag parameter.'
+ }
+
+ if ($GenerateReleaseNotes) {
+ $generated = New-GitHubReleaseNote -Owner $Owner -Repository $Repository -Tag $Tag -Context $Context
+ $Name = -not [string]::IsNullOrEmpty($Name) ? $Name : $generated.Name
+ $Notes = -not [string]::IsNullOrEmpty($Notes) ? $Notes, $generated.Notes -join "`n" : $generated.Notes
+ }
+
+ $body = @{
+ tag_name = $Tag
+ target_commitish = $Target
+ name = $Name
+ body = $Notes
+ }
+
+ if ([string]::IsNullOrEmpty($ID) -and -not [string]::IsNullOrEmpty($Tag)) {
+ $release = if ($ReleaseObject) {
+ $ReleaseObject
+ } else {
+ Get-GitHubRelease -Owner $Owner -Repository $Repository -Tag $Tag -Context $Context
+ }
+ if (-not $release) {
+ throw "Release with tag [$Tag] not found in [$Owner/$Repository]."
+ }
+ $ID = $release.ID
+ $body.Remove('tag_name')
+ }
+
+ $repo = Get-GitHubRepositoryByName -Owner $Owner -Name $Repository -Context $Context
+ if ($repo.HasDiscussions) {
+ $body['discussion_category_name'] = $DiscussionCategoryName
+ }
+ if (-not $Declare) {
+ $body | Remove-HashtableEntry -NullOrEmptyValues
+ }
+
+ if ($Latest) {
+ $body['make_latest'] = [bool]$Latest.ToString().ToLower()
+ $body['prerelease'] = $false
+ $body['draft'] = $false
+ }
+ if ($Draft -or $Prerelease) {
+ $body['make_latest'] = $false
+ $body['prerelease'] = [bool]$Prerelease
+ $body['draft'] = [bool]$Draft
+ }
+
+ $inputObject = @{
+ Method = 'PATCH'
+ APIEndpoint = "/repos/$Owner/$Repository/releases/$ID"
+ Body = $body
+ Context = $Context
+ }
+
+ if ($PSCmdlet.ShouldProcess("release with ID [$ID] in [$Owner/$Repository]", 'Update')) {
+ $resultLatest = $PSBoundParameters.ContainsKey('Latest') ? $Latest : $release.IsLatest
+ Invoke-GitHubAPI @inputObject | ForEach-Object {
+ [GitHubRelease]::new($_.Response , $Owner, $Repository, $resultLatest)
+ }
+ }
+ }
+
+ end {
+ Write-Debug "[$stackPath] - End"
+ }
+}
diff --git a/src/functions/public/Users/completers.ps1 b/src/functions/public/Users/completers.ps1
new file mode 100644
index 000000000..a32def765
--- /dev/null
+++ b/src/functions/public/Users/completers.ps1
@@ -0,0 +1,31 @@
+Register-ArgumentCompleter -CommandName ($script:PSModuleInfo.FunctionsToExport) -ParameterName Owner -ScriptBlock {
+ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
+ $null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter
+
+ if ($fakeBoundParameter.ContainsKey('Context')) {
+ $orgs = Get-GitHubOrganization -Verbose:$false -Debug:$false -Context $fakeBoundParameter.Context
+ } else {
+ $orgs = Get-GitHubOrganization -Verbose:$false -Debug:$false
+ }
+ $orgs += Get-GitHubMyUser -Verbose:$false -Debug:$false -Context $fakeBoundParameter.Context
+
+ $orgs | Where-Object { $_.CompletionText -like "$wordToComplete*" } | ForEach-Object {
+ [System.Management.Automation.CompletionResult]::new($_, ($_ | Format-Table -HideTableHeaders), 'ParameterValue', $_.Description)
+ }
+}
+
+Register-ArgumentCompleter -CommandName Get-GitHubUser -ParameterName Name -ScriptBlock {
+ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)
+ $null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter
+
+ if ($fakeBoundParameter.ContainsKey('Context')) {
+ $orgs = Get-GitHubOrganization -Verbose:$false -Debug:$false -Context $fakeBoundParameter.Context
+ } else {
+ $orgs = Get-GitHubOrganization -Verbose:$false -Debug:$false
+ }
+ $orgs += Get-GitHubMyUser -Verbose:$false -Debug:$false -Context $fakeBoundParameter.Context
+
+ $orgs | Where-Object { $_.CompletionText -like "$wordToComplete*" } | ForEach-Object {
+ [System.Management.Automation.CompletionResult]::new($_, ($_ | Format-Table -HideTableHeaders), 'ParameterValue', $_.Description)
+ }
+}
diff --git a/src/types/GitHubRelease.Types.ps1xml b/src/types/GitHubRelease.Types.ps1xml
new file mode 100644
index 000000000..1c1acc885
--- /dev/null
+++ b/src/types/GitHubRelease.Types.ps1xml
@@ -0,0 +1,12 @@
+
+
+
+ GitHubRelease
+
+
+ Release
+ $this.ID
+
+
+
+
diff --git a/tests/Artifacts.Tests.ps1 b/tests copy/Artifacts.Tests.ps1
similarity index 100%
rename from tests/Artifacts.Tests.ps1
rename to tests copy/Artifacts.Tests.ps1
diff --git a/tests copy/Data/AuthCases.ps1 b/tests copy/Data/AuthCases.ps1
new file mode 100644
index 000000000..63c7f1438
--- /dev/null
+++ b/tests copy/Data/AuthCases.ps1
@@ -0,0 +1,83 @@
+@(
+ @{
+ AuthType = 'PAT'
+ Type = 'a user'
+ Case = 'Fine-grained PAT token'
+ TokenType = 'USER_FG_PAT'
+ Target = 'it self (user account)'
+ Owner = 'psmodule-user'
+ OwnerType = 'user'
+ ConnectParams = @{
+ Token = $env:TEST_USER_USER_FG_PAT
+ }
+ }
+ @{
+ AuthType = 'PAT'
+ Type = 'a user'
+ Case = 'Fine-grained PAT token'
+ TokenType = 'ORG_FG_PAT'
+ Target = 'organization account'
+ Owner = 'psmodule-test-org2'
+ OwnerType = 'organization'
+ ConnectParams = @{
+ Token = $env:TEST_USER_ORG_FG_PAT
+ }
+ }
+ @{
+ AuthType = 'PAT'
+ Type = 'a user'
+ Case = 'Classic PAT token'
+ TokenType = 'PAT'
+ Target = 'user account'
+ Owner = 'psmodule-user'
+ OwnerType = 'user'
+ ConnectParams = @{
+ Token = $env:TEST_USER_PAT
+ }
+ }
+ @{
+ AuthType = 'IAT'
+ Type = 'GitHub Actions'
+ Case = 'GITHUB_TOKEN'
+ TokenType = 'GITHUB_TOKEN'
+ Target = 'this repository (GitHub)'
+ Owner = 'PSModule'
+ Repo = 'GitHub'
+ OwnerType = 'repository'
+ ConnectParams = @{
+ Token = $env:GITHUB_TOKEN
+ }
+ }
+ @{
+ AuthType = 'App'
+ Type = 'a GitHub App from an Enterprise'
+ Case = 'PEM + IAT'
+ TokenType = 'APP_ENT'
+ Target = 'organization account'
+ Owner = 'psmodule-test-org3'
+ OwnerType = 'organization'
+ ConnectParams = @{
+ ClientID = $env:TEST_APP_ENT_CLIENT_ID
+ PrivateKey = $env:TEST_APP_ENT_PRIVATE_KEY
+ }
+ ConnectAppParams = @{
+ Organization = 'psmodule-test-org3'
+ }
+ }
+ @{
+ AuthType = 'App'
+ Type = 'a GitHub App from an Organization'
+ Case = 'PEM + IAT'
+ TokenType = 'APP_ORG'
+ Target = 'organization account'
+ Owner = 'psmodule-test-org'
+ OwnerType = 'organization'
+ ConnectParams = @{
+ ClientID = $env:TEST_APP_ORG_CLIENT_ID
+ PrivateKey = $env:TEST_APP_ORG_PRIVATE_KEY
+ }
+ ConnectAppParams = @{
+ Organization = 'psmodule-test-org'
+ }
+ }
+)
diff --git a/tests copy/Data/IssueForm.md b/tests copy/Data/IssueForm.md
new file mode 100644
index 000000000..83b1b3967
--- /dev/null
+++ b/tests copy/Data/IssueForm.md
@@ -0,0 +1,19 @@
+
+### Type with spaces
+
+Action
+
+### Multiline
+
+test
+is multi
+ line
+
+### OS
+
+- [x] Windows
+- [x] Linux
+- [ ] macOS
+
diff --git a/tests/Environments.Tests.ps1 b/tests copy/Environments.Tests.ps1
similarity index 100%
rename from tests/Environments.Tests.ps1
rename to tests copy/Environments.Tests.ps1
diff --git a/tests/GitHub.Tests.ps1 b/tests copy/GitHub.Tests.ps1
similarity index 100%
rename from tests/GitHub.Tests.ps1
rename to tests copy/GitHub.Tests.ps1
diff --git a/tests/Organizations.Tests.ps1 b/tests copy/Organizations.Tests.ps1
similarity index 100%
rename from tests/Organizations.Tests.ps1
rename to tests copy/Organizations.Tests.ps1
diff --git a/tests/README.md b/tests copy/README.md
similarity index 100%
rename from tests/README.md
rename to tests copy/README.md
diff --git a/tests/Repositories.Tests.ps1 b/tests copy/Repositories.Tests.ps1
similarity index 100%
rename from tests/Repositories.Tests.ps1
rename to tests copy/Repositories.Tests.ps1
diff --git a/tests/Secrets.Tests.ps1 b/tests copy/Secrets.Tests.ps1
similarity index 100%
rename from tests/Secrets.Tests.ps1
rename to tests copy/Secrets.Tests.ps1
diff --git a/tests/TEMPLATE.ps1 b/tests copy/TEMPLATE.ps1
similarity index 100%
rename from tests/TEMPLATE.ps1
rename to tests copy/TEMPLATE.ps1
diff --git a/tests/Teams.Tests.ps1 b/tests copy/Teams.Tests.ps1
similarity index 100%
rename from tests/Teams.Tests.ps1
rename to tests copy/Teams.Tests.ps1
diff --git a/tests/Users.Tests.ps1 b/tests copy/Users.Tests.ps1
similarity index 100%
rename from tests/Users.Tests.ps1
rename to tests copy/Users.Tests.ps1
diff --git a/tests/Variables.Tests.ps1 b/tests copy/Variables.Tests.ps1
similarity index 100%
rename from tests/Variables.Tests.ps1
rename to tests copy/Variables.Tests.ps1
diff --git a/tests/Releases.Tests.ps1 b/tests/Releases.Tests.ps1
new file mode 100644
index 000000000..6643675db
--- /dev/null
+++ b/tests/Releases.Tests.ps1
@@ -0,0 +1,499 @@
+#Requires -Modules @{ ModuleName = 'Pester'; RequiredVersion = '5.7.1' }
+
+[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
+ 'PSUseDeclaredVarsMoreThanAssignments', '',
+ Justification = 'Pester grouping syntax: known issue.'
+)]
+[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
+ 'PSAvoidUsingConvertToSecureStringWithPlainText', '',
+ Justification = 'Used to create a secure string for testing.'
+)]
+[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
+ 'PSAvoidUsingWriteHost', '',
+ Justification = 'Log outputs to GitHub Actions logs.'
+)]
+[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
+ 'PSAvoidLongLines', '',
+ Justification = 'Long test descriptions and skip switches'
+)]
+[CmdletBinding()]
+param()
+
+BeforeAll {
+ $testName = 'ReleasesTests'
+ $os = $env:RUNNER_OS
+ $guid = [guid]::NewGuid().ToString()
+}
+
+Describe 'Releases' {
+ $authCases = . "$PSScriptRoot/Data/AuthCases.ps1"
+
+ Context 'As using on ' -ForEach $authCases {
+ BeforeAll {
+ $context = Connect-GitHubAccount @connectParams -PassThru -Silent
+ LogGroup 'Context' {
+ Write-Host ($context | Format-Table | Out-String)
+ }
+ if ($AuthType -eq 'APP') {
+ LogGroup 'Context - Installation' {
+ $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent
+ Write-Host ($context | Format-Table | Out-String)
+ }
+ }
+ $repoPrefix = "$testName-$os-$TokenType"
+ $repoName = "$repoPrefix-$guid"
+
+ $params = @{
+ Name = $repoName
+ Context = $context
+ AllowSquashMerge = $true
+ AddReadme = $true
+ License = 'mit'
+ Gitignore = 'VisualStudio'
+ }
+ switch ($OwnerType) {
+ 'user' {
+ $repo = New-GitHubRepository @params
+ }
+ 'organization' {
+ $repo = New-GitHubRepository @params -Organization $owner
+ }
+ }
+ LogGroup "Repository - [$repoName]" {
+ Write-Host ($repo | Format-Table | Out-String)
+ }
+ }
+
+ AfterAll {
+ switch ($OwnerType) {
+ 'user' {
+ Get-GitHubRepository | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false
+ }
+ 'organization' {
+ Get-GitHubRepository -Organization $Owner | Where-Object { $_.Name -like "$repoPrefix*" } | Remove-GitHubRepository -Confirm:$false
+ }
+ }
+ Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent
+ }
+
+ Context 'Releases' -Skip:($OwnerType -eq 'repository') {
+ It 'New-GitHubRelease - Creates a new release' {
+ $release = New-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.0' -Latest
+ LogGroup 'Release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ }
+
+ It 'New-GitHubRelease - Throws when tag already exists' {
+ { New-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.0' -Latest } | Should -Throw
+ }
+
+ It 'New-GitHubRelease - Creates a new release with a draft' {
+ $release = New-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.2' -Draft
+ LogGroup 'Release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.IsDraft | Should -BeTrue
+ $release.IsLatest | Should -BeFalse
+ $release.IsPrerelease | Should -BeFalse
+ }
+
+ It 'New-GitHubRelease - Creates a new release with a pre-release' {
+ $release = New-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.1' -Prerelease
+ LogGroup 'Release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Tag | Should -Be 'v1.1'
+ $release.IsDraft | Should -BeFalse
+ $release.IsLatest | Should -BeFalse
+ $release.IsPrerelease | Should -BeTrue
+ }
+
+ It 'New-GitHubRelease - Creates a new release with a name' {
+ $release = New-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.3' -Name 'Test Release' -GenerateReleaseNotes -Latest
+ LogGroup 'Release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ }
+
+ It 'Get-GitHubRelease - Gets latest release' {
+ $release = Get-GitHubRelease -Owner $Owner -Repository $repo
+ LogGroup 'Latest release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Count | Should -Be 1
+ $release | Should -BeOfType 'GitHubRelease'
+ $release.Tag | Should -Be 'v1.3'
+ $release.IsLatest | Should -BeTrue
+ }
+
+ It 'Get-GitHubRelease - Gets all releases' {
+ $releases = Get-GitHubRelease -Owner $Owner -Repository $repo -All
+ LogGroup 'All releases' {
+ Write-Host ($releases | Format-List -Property * | Out-String)
+ }
+ $releases | Should -Not -BeNullOrEmpty
+ $releases.Count | Should -BeGreaterThan 1
+ $releases | Should -BeOfType 'GitHubRelease'
+ }
+
+ It 'Get-GitHubRelease - Gets release by tag' {
+ $release = Get-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.2'
+ LogGroup 'Release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Count | Should -Be 1
+ $release | Should -BeOfType 'GitHubRelease'
+ $release.Tag | Should -Be 'v1.2'
+ $release.IsLatest | Should -BeFalse
+ $release.IsDraft | Should -BeTrue
+ }
+
+ It 'Get-GitHubRelease - Gets release by ID' {
+ $specificRelease = Get-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.0'
+ $release = Get-GitHubRelease -Owner $Owner -Repository $repo -ID $specificRelease.ID
+ LogGroup 'Release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Count | Should -Be 1
+ $release | Should -BeOfType 'GitHubRelease'
+ $release.Tag | Should -Be 'v1.0'
+ $release.IsLatest | Should -BeFalse
+ $release.IsDraft | Should -BeFalse
+ $release.IsPrerelease | Should -BeFalse
+ }
+
+ It 'Get-GitHubRelease - Gets release by ID using Pipeline' {
+ $specificRelease = Get-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.2'
+ $release = Get-GitHubRelease -Owner $Owner -Repository $repo -ID $specificRelease.ID
+ LogGroup 'Release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Count | Should -Be 1
+ $release | Should -BeOfType 'GitHubRelease'
+ $release.Tag | Should -Be 'v1.2'
+ }
+
+ It 'Update-GitHubRelease - Update release v1.0' {
+ $release = Update-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.0' -Name 'Updated Release' -Notes 'Updated release notes'
+ LogGroup 'Updated release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Name | Should -Be 'Updated Release'
+ $release.Notes | Should -Be 'Updated release notes'
+ $release.Tag | Should -Be 'v1.0'
+ $release.IsLatest | Should -BeFalse
+ $release.IsDraft | Should -BeFalse
+ $release.IsPrerelease | Should -BeFalse
+ }
+
+ It 'Update-GitHubRelease - Update release v1.1' {
+ $release = Update-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.1' -Name 'Updated Release' -Notes 'Updated release notes'
+ LogGroup 'Updated release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Name | Should -Be 'Updated Release'
+ $release.Notes | Should -Be 'Updated release notes'
+ $release.Tag | Should -Be 'v1.1'
+ $release.IsLatest | Should -BeFalse
+ $release.IsDraft | Should -BeFalse
+ $release.IsPrerelease | Should -BeTrue
+ }
+
+ It 'Update-GitHubRelease - Update release v1.2' {
+ $release = Update-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.2' -Name 'Updated Release' -Notes 'Updated release notes'
+ LogGroup 'Updated release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Name | Should -Be 'Updated Release'
+ $release.Notes | Should -Be 'Updated release notes'
+ $release.IsLatest | Should -BeFalse
+ $release.IsDraft | Should -BeTrue
+ $release.IsPrerelease | Should -BeFalse
+ }
+
+ It 'Update-GitHubRelease - Update release v1.3' {
+ $release = Update-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.3' -Name 'Updated Release' -Notes 'Updated release notes'
+ LogGroup 'Updated release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Name | Should -Be 'Updated Release'
+ $release.Notes | Should -Be 'Updated release notes'
+ $release.Tag | Should -Be 'v1.3'
+ $release.IsLatest | Should -BeTrue
+ $release.IsDraft | Should -BeFalse
+ $release.IsPrerelease | Should -BeFalse
+ }
+
+ It 'Set-GitHubRelease - Sets release v1.0 as latest' {
+ $release = Set-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.0' -Latest -Name 'Updated Release again' -Notes 'Updated release notes to something else'
+ LogGroup 'Set release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Tag | Should -Be 'v1.0'
+ $release.IsLatest | Should -BeTrue
+ $release.IsDraft | Should -BeFalse
+ $release.IsPrerelease | Should -BeFalse
+ $release.Name | Should -Be 'Updated Release again'
+ $release.Notes | Should -Be 'Updated release notes to something else'
+ }
+
+ It 'Set-GitHubRelease - Sets a new release as latest - v1.4' {
+ $release = Set-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.4' -Latest -Name 'New Release' -Notes 'New release notes'
+ LogGroup 'Set release' {
+ Write-Host ($release | Format-List -Property * | Out-String)
+ }
+ $release | Should -Not -BeNullOrEmpty
+ $release.Tag | Should -Be 'v1.4'
+ $release.IsLatest | Should -BeTrue
+ $release.IsDraft | Should -BeFalse
+ $release.IsPrerelease | Should -BeFalse
+ $release.Name | Should -Be 'New Release'
+ $release.Notes | Should -Be 'New release notes'
+ }
+
+ It 'Remove-GitHubRelease - Removes release v1.0' {
+ $release = Get-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.0'
+ $release | Should -Not -BeNullOrEmpty
+ $release.Count | Should -Be 1
+ $release | Should -BeOfType 'GitHubRelease'
+ $release.Tag | Should -Be 'v1.0'
+ $release.IsLatest | Should -BeFalse
+ $release.IsDraft | Should -BeFalse
+ $release.IsPrerelease | Should -BeFalse
+
+ Remove-GitHubRelease -Owner $Owner -Repository $repo -ID $release.ID -Confirm:$false
+
+ $release = Get-GitHubRelease -Owner $Owner -Repository $repo -Tag 'v1.0'
+ $release | Should -BeNullOrEmpty
+ }
+ }
+ Context 'Release Assets' -Skip:($OwnerType -eq 'repository') {
+ BeforeAll {
+ $testFolderGuid = [Guid]::NewGuid().ToString().Substring(0, 8)
+ $testFolderName = "GHAssetTest-$testFolderGuid"
+ $testFolderPath = Join-Path -Path $PSScriptRoot -ChildPath $testFolderName
+ New-Item -Path $testFolderPath -ItemType Directory -Force
+ $testFiles = @{
+ TextFile = @{
+ Name = 'TextFile.txt'
+ Path = Join-Path -Path $testFolderPath -ChildPath 'TextFile.txt'
+ Content = @'
+This is a simple text file for testing GitHub release assets
+'@
+ ContentType = 'text/plain'
+ }
+ MarkdownFile = @{
+ Name = 'Documentation.md'
+ Path = Join-Path -Path $testFolderPath -ChildPath 'Documentation.md'
+ Content = @'
+# Test Documentation
+## Introduction
+This is a markdown file used for testing GitHub release assets
+'@
+ ContentType = 'text/markdown'
+ }
+ JsonFile = @{
+ Name = 'Config.json'
+ Path = Join-Path -Path $testFolderPath -ChildPath 'Config.json'
+ Content = @'
+{
+ "name": "GitHub Release Asset Test",
+ "version": "1.0.0",
+ "description": "Test file for GitHub release assets"
+}
+'@
+ ContentType = 'application/json'
+ }
+ XmlFile = @{
+ Name = 'Data.xml'
+ Path = Join-Path -Path $testFolderPath -ChildPath 'Data.xml'
+ Content = @'
+
+ -
+ Test Item
+ 100
+
+
+'@
+ ContentType = 'application/xml'
+ }
+ CsvFile = @{
+ Name = 'Records.csv'
+ Path = Join-Path -Path $testFolderPath -ChildPath 'Records.csv'
+ Content = @'
+ID,Name,Value
+1,Item1,100
+2,Item2,200
+3,Item3,300
+'@
+ ContentType = 'text/csv'
+ }
+ }
+ foreach ($file in $testFiles.Values) {
+ Set-Content -Path $file.Path -Value $file.Content
+ }
+
+ # Create a zip file of all test files
+ $zipFileName = "$testFolderName.zip"
+ $zipFilePath = Join-Path -Path $PSScriptRoot -ChildPath $zipFileName
+ Compress-Archive -Path "$testFolderPath\*" -DestinationPath $zipFilePath -Force
+
+ # Add the zip file to the test files collection
+ $testFiles['ZipFile'] = @{
+ Name = $zipFileName
+ Path = $zipFilePath
+ ContentType = 'application/zip'
+ }
+
+ # Get the latest release to use for tests
+ $release = Get-GitHubRelease -Owner $Owner -Repository $repo
+ }
+
+ It 'Add-GitHubReleaseAsset - Creates a new release asset' {
+ $asset = $release | Add-GitHubReleaseAsset -Path $testFiles.TextFile.Path
+ LogGroup 'Added asset' {
+ Write-Host ($asset | Format-List -Property * | Out-String)
+ }
+ $asset | Should -Not -BeNullOrEmpty
+ $asset | Should -BeOfType 'GitHubReleaseAsset'
+ $asset.Name | Should -Be $testFiles.TextFile.Name
+ $asset.Label | Should -Be $testFiles.TextFile.Name
+ $asset.Size | Should -BeGreaterThan 0
+ $asset.ContentType | Should -Be $testFiles.TextFile.ContentType
+
+ $downloadPath = Join-Path -Path $PSScriptRoot -ChildPath "Downloaded-$($testFiles.TextFile.Name)"
+ Invoke-WebRequest -Uri $asset.Url -OutFile $downloadPath -RetryIntervalSec 5 -MaximumRetryCount 5
+ Get-Content -Path $downloadPath | Should -Be $testFiles.TextFile.Content
+ }
+
+ It 'Add-GitHubReleaseAsset - Creates a release asset with custom parameters' {
+ $customName = "Custom-$($testFiles.MarkdownFile.Name)"
+ $label = 'Test Markdown Documentation'
+ $asset = $release | Add-GitHubReleaseAsset -Path $testFiles.MarkdownFile.Path -Name $customName -Label $label
+ LogGroup 'Added markdown asset' {
+ Write-Host ($asset | Format-List -Property * | Out-String)
+ }
+ $asset | Should -Not -BeNullOrEmpty
+ $asset | Should -BeOfType 'GitHubReleaseAsset'
+ $asset.Name | Should -Be $customName
+ $asset.ContentType | Should -Be $testFiles.MarkdownFile.ContentType
+ $asset.Label | Should -Be $label
+ $asset.Size | Should -BeGreaterThan 0
+
+ $downloadPath = Join-Path -Path $PSScriptRoot -ChildPath "Downloaded-$customName"
+ Invoke-WebRequest -Uri $asset.Url -OutFile $downloadPath -RetryIntervalSec 5 -MaximumRetryCount 5
+ (Get-Content -Path $downloadPath -Raw) | Should -Match '# Test Documentation'
+ }
+
+ It 'Add-GitHubReleaseAsset - Adds a folder as a zipped asset to a release' {
+ $label = 'Test Files Collection'
+ $asset = $release | Add-GitHubReleaseAsset -Label $label -Path $testFiles.ZipFile.Path
+ LogGroup 'Added zip asset' {
+ Write-Host ($asset | Format-List -Property * | Out-String)
+ }
+ $asset | Should -Not -BeNullOrEmpty
+ $asset.Name | Should -Be $testFiles.ZipFile.Name
+ $asset.Label | Should -Be $label
+ $asset.ContentType | Should -Be $testFiles.ZipFile.ContentType
+ $asset.Size | Should -BeGreaterThan 0
+
+ $downloadPath = Join-Path -Path $PSScriptRoot -ChildPath "Downloaded-$($testFiles.ZipFile.Name)"
+ Invoke-WebRequest -Uri $asset.Url -OutFile $downloadPath -RetryIntervalSec 5 -MaximumRetryCount 5
+ Test-Path -Path $downloadPath | Should -BeTrue
+ }
+
+ It 'Get-GitHubReleaseAsset - Gets all assets from a release ID' {
+ $release = Get-GitHubRelease -Owner $Owner -Repository $repo
+ $assets = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ReleaseID $release.ID
+ LogGroup 'Release assets by release ID' {
+ Write-Host ($assets | Format-List -Property * | Out-String)
+ }
+ $assets | Should -Not -BeNullOrEmpty
+ $assets.Count | Should -Be 3
+ $assets | Should -BeOfType 'GitHubReleaseAsset'
+ }
+
+ It 'Get-GitHubReleaseAsset - Gets all assets from the latest release' {
+ $assets = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo
+ LogGroup 'Release assets from latest release' {
+ Write-Host ($assets | Format-List -Property * | Out-String)
+ }
+ $assets | Should -Not -BeNullOrEmpty
+ $assets | Should -BeOfType 'GitHubReleaseAsset'
+ }
+
+ # It 'Get-GitHubReleaseAsset - Gets a specific asset by ID' {
+ # $release = Get-GitHubRelease -Owner $Owner -Repository $repo
+ # $assets = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ReleaseID $release.ID
+ # $asset = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ID $assets[0].ID
+ # LogGroup 'Release asset by asset ID' {
+ # Write-Host ($asset | Format-List -Property * | Out-String)
+ # }
+ # $asset | Should -Not -BeNullOrEmpty
+ # $asset | Should -BeOfType 'GitHubReleaseAsset'
+ # $asset.ID | Should -Be $assets[0].ID
+ # }
+
+ # It 'Get-GitHubReleaseAsset - Gets a specific asset by name from a release ID' {
+ # $release = Get-GitHubRelease -Owner $Owner -Repository $repo
+ # $assets = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ReleaseID $release.ID
+ # $assetName = $assets[0].Name
+ # $asset = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ReleaseID $release.ID -Name $assetName
+ # LogGroup 'Release asset by name from release ID' {
+ # Write-Host ($asset | Format-List -Property * | Out-String)
+ # }
+ # $asset | Should -Not -BeNullOrEmpty
+ # $asset | Should -BeOfType 'GitHubReleaseAsset'
+ # $asset.Name | Should -Be $assetName
+ # }
+
+ # It 'Get-GitHubReleaseAsset - Gets a specific asset by name from a tag' {
+ # $release = Get-GitHubRelease -Owner $Owner -Repository $repo
+ # $assets = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ReleaseID $release.ID
+ # $assetName = $assets[0].Name
+ # $asset = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -Tag $release.Tag -Name $assetName
+ # LogGroup 'Release asset by name from tag' {
+ # Write-Host ($asset | Format-List -Property * | Out-String)
+ # }
+ # $asset | Should -Not -BeNullOrEmpty
+ # $asset.Name | Should -Be $assetName
+ # }
+
+ # It 'Update-GitHubReleaseAsset - Updates a release asset' {
+ # $release = Get-GitHubRelease -Owner $Owner -Repository $repo
+ # $assets = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ReleaseID $release.ID
+ # $newLabel = 'Updated test asset'
+ # $asset = Update-GitHubReleaseAsset -Owner $Owner -Repository $repo -ID $assets[0].ID -Label $newLabel
+ # LogGroup 'Updated asset' {
+ # Write-Host ($asset | Format-List -Property * | Out-String)
+ # }
+ # $asset | Should -Not -BeNullOrEmpty
+ # $asset.Label | Should -Be $newLabel
+ # }
+
+ # It 'Remove-GitHubReleaseAsset - Removes a release asset' {
+ # $release = Get-GitHubRelease -Owner $Owner -Repository $repo
+ # $assets = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ReleaseID $release.ID
+ # $assetID = $assets[0].ID
+ # Remove-GitHubReleaseAsset -Owner $Owner -Repository $repo -ID $assetID -Confirm:$false
+ # $updatedAssets = Get-GitHubReleaseAsset -Owner $Owner -Repository $repo -ReleaseID $release.ID
+ # $remainingAsset = $updatedAssets | Where-Object { $_.ID -eq $assetID }
+ # $remainingAsset | Should -BeNullOrEmpty
+ # }
+ }
+ }
+}
diff --git a/tools/dev/Get-GitHubReleaseQL.ps1 b/tools/dev/Get-GitHubReleaseQL.ps1
new file mode 100644
index 000000000..64dcb4a92
--- /dev/null
+++ b/tools/dev/Get-GitHubReleaseQL.ps1
@@ -0,0 +1,124 @@
+function Get-GitHubReleaseQL {
+ <#
+ .SYNOPSIS
+ Get all releases with nested pagination for assets
+
+ .DESCRIPTION
+ Gets all releases with their complete asset lists using nested pagination through both releases and their assets.
+
+ .EXAMPLE
+ Get-GitHubRelease -Owner 'github' -Repository 'my-repo' -PerPage 10 -Context $context
+ #>
+ [OutputType([GitHubRelease])]
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory)]
+ [string] $Owner,
+
+ [Parameter(Mandatory)]
+ [string] $Repository,
+
+ [ValidateRange(1, 100)]
+ [int] $PerPage,
+
+ [Parameter()]
+ [object] $Context = (Get-GitHubContext)
+ )
+
+ begin {
+ $stackPath = Get-PSCallStackPath
+ Write-Debug "[$stackPath] - Start"
+ Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT
+
+ $releaseCursor = $null
+ $releaseQuery = @'
+query($owner: String!, $repository: String!, $releaseCursor: String, $perPage: Int!) {
+ repository(owner: $owner, name: $repository) {
+ releases(first: $perPage, after: $releaseCursor, orderBy: {field: CREATED_AT, direction: DESC}) {
+ nodes {
+ id
+ databaseId
+ name
+ tagName
+ description
+ isDraft
+ isPrerelease
+ isLatest
+ createdAt
+ publishedAt
+ updatedAt
+ tag {
+ name
+ id
+ }
+ tagCommit {
+ oid
+ }
+ url
+ author {
+ login
+ id
+ databaseId
+ }
+ releaseAssets(first: $perPage) {
+ nodes {
+ name
+ downloadCount
+ downloadUrl
+ contentType
+ createdAt
+ updatedAt
+ uploadedBy {
+ login
+ name
+ id
+ databaseId
+ }
+ size
+ url
+ id
+ }
+ }
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+}
+'@
+
+ $PerPage = $PSBoundParameters.ContainsKey('PerPage') ? $PerPage : $Context.PerPage
+ }
+
+ process {
+ do {
+ $releaseVariables = @{
+ owner = $Owner
+ repository = $Repository
+ releaseCursor = $releaseCursor
+ perPage = $PerPage
+ }
+
+ $result = Invoke-GitHubGraphQLQuery -Query $releaseQuery -Variables $releaseVariables -Context $Context
+ if (-not $result) { break }
+
+ $repositoryData = $result.repository
+ if (-not $repositoryData) { break }
+
+ $releases = $repositoryData.releases
+ if (-not $releases) { break }
+
+ $releases.nodes | ForEach-Object {
+ # [GitHubRelease]::new($_)
+ }
+
+ $releaseCursor = $releases.pageInfo.endCursor
+ } while ($releases.pageInfo.hasNextPage)
+ }
+
+ end {
+ Write-Debug "[$stackPath] - End"
+ }
+}