From 200f4bd947da05379080ed6c0aaee54da945e80f Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Thu, 20 Aug 2020 12:36:51 -0700 Subject: [PATCH 01/51] Fix README Table of Contents `Logging` is in USAGE.md, not README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 0488dc54..391405d0 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ * [Installation](#installation) * [Configuration](#configuration) * [Usage](#usage) -* [Logging](#logging) * [Developing and Contributing](#developing-and-contributing) * [Legal and Licensing](#legal-and-licensing) * [Governance](#governance) From 458d07c8f2a0d63bf5b014371fbdeda98bf49a01 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Thu, 20 Aug 2020 12:54:04 -0700 Subject: [PATCH 02/51] Update README's listing of current API support Updated the summary of the current API support in the README to account for the recent `0.15.0` changes. Also added a direct link to the CHANGELOG as well. --- README.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 391405d0..b148af10 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ #### Table of Contents * [Overview](#overview) +* [What's New](#whats-new) * [Current API Support](#current-api-support) * [Installation](#installation) * [Configuration](#configuration) @@ -43,15 +44,24 @@ virtually any command into any other command within the module.** ---------- +## What's New + +Check out [CHANGELOG.md](./CHANGELOG.md) to review the details of the current release as well as +all past releases. + +---------- + ## Current API Support At present, this module can: * Query, create, update and remove [Repositories](https://developer.github.com/v3/repos/) including - * Query [Branches](https://developer.github.com/v3/repos/branches/) + * Query, create and remove [Branches](https://developer.github.com/v3/repos/branches/), as well + as the associated branch protection rules. * Query and create new [Forks](https://developer.github.com/v3/repos/forks/) - * Query/retrieve [Content](https://developer.github.com/v3/repos/contents/) from a repo. + * Query and create [Content](https://developer.github.com/v3/repos/contents/) in a repo. * Query the languages and tags in a repository, and and query/update its topics. * Change repository ownership. + * Query, enable and disable security and vulnerability alerts. * Query various [traffic reports](https://developer.github.com/v3/repos/traffic/) including referral sources and paths, page views and clones. * Query, create, edit, lock/unlock [Issues](https://developer.github.com/v3/issues/) and @@ -67,11 +77,17 @@ At present, this module can: * Query [contributors](https://developer.github.com/v3/repos/statistics/) * Query [organizations](https://developer.github.com/v3/orgs/) and their members. * Query and update [Users](https://developer.github.com/v3/users/) - * Query [Teams](https://developer.github.com/v3/teams/) and their members. + * Query, create, edit and remove [Teams](https://developer.github.com/v3/teams/), + and Query their members. * Query, create, edit and remove [Projects](https://developer.github.com/v3/projects/), along with [Project Columns](https://developer.github.com/v3/projects/columns/) and [Project Cards](https://developer.github.com/v3/projects/cards/) - * Query [Releases](https://developer.github.com/v3/repos/releases/) + * Query, create, edit and remove [Releases](https://developer.github.com/v3/repos/releases/) and + associated content/assets. + * Query, create, edit, remove, fork, and (un)star [gists](https://developer.github.com/v3/gists/), + as well as gist comments. + * Query, edit and remove [reactions](https://developer.github.com/v3/reactions/) on Issues and + Pull Requests. * Miscellaneous functionality: * Get all [Codes of Conduct](https://developer.github.com/v3/codes_of_conduct/) as well as that of a specific repo. From 3094c9789caf00382134a0703344f655b13a1e33 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Thu, 27 Aug 2020 12:32:42 -0700 Subject: [PATCH 03/51] Fixing README badges/links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b148af10..88b36463 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![powershellgallery](https://img.shields.io/powershellgallery/v/PowerShellForGitHub)](https://www.powershellgallery.com/packages/PowerShellForGitHub) [![downloads](https://img.shields.io/powershellgallery/dt/PowerShellForGitHub.svg?label=downloads)](https://www.powershellgallery.com/packages/PowerShellForGitHub) [![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/microsoft/PowerShellForGitHub)](https://github.com/microsoft/PowerShellForGitHub) -[![downloads](https://img.shields.io/badge/license-MIT-green)](https://github.com/HowardWolosky/PowerShellForGitHub/blob/master/LICENSE) +[![downloads](https://img.shields.io/badge/license-MIT-green)](https://github.com/microsoft/PowerShellForGitHub/blob/master/LICENSE) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3990/badge)](https://bestpractices.coreinfrastructure.org/projects/3990) [![tweet](https://img.shields.io/twitter/url?url=https%3A%2F%2Ftwitter.com%2FQuackFu)](https://twitter.com/intent/tweet?text=%23PowerShellForGitHub%20%40QuackFu%20&original_referer=https://github.com/microsoft/PowerShellForGitHub)
@@ -13,7 +13,7 @@ [![Azure DevOps coverage](https://img.shields.io/azure-devops/coverage/ms/PowerShellForGitHub/109/master)](https://dev.azure.com/ms/PowerShellForGitHub/_build/latest?definitionId=109&branchName=master)
[![Help Wanted Issues](https://img.shields.io/github/issues/microsoft/PowerShellForGitHub/help%20wanted)](https://github.com/microsoft/PowerShellForGitHub/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) -[![GitHub last commit](https://img.shields.io/github/last-commit/microsoft/PowerShellForGitHub)](https://github.com/HowardWolosky/PowerShellForGitHub/commits/master) +[![GitHub last commit](https://img.shields.io/github/last-commit/microsoft/PowerShellForGitHub)](https://github.com/microsoft/PowerShellForGitHub/commits/master) #### Table of Contents From 5ee03650b8225d6aedbd5159d5a84a32bc32d771 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Tue, 8 Sep 2020 21:42:33 -0700 Subject: [PATCH 04/51] Increase max runtime for CI pipeline jobs --- build/pipelines/azure-pipelines.ci.yaml | 8 ++++---- build/pipelines/azure-pipelines.release.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pipelines/azure-pipelines.ci.yaml b/build/pipelines/azure-pipelines.ci.yaml index 33cf7f74..d5847424 100644 --- a/build/pipelines/azure-pipelines.ci.yaml +++ b/build/pipelines/azure-pipelines.ci.yaml @@ -35,7 +35,7 @@ jobs: pool: vmImage: 'windows-latest' dependsOn: waitForRunningBuilds - timeoutInMinutes: 120 + timeoutInMinutes: 240 steps: - template: ./templates/verify-testConfigSettingsHash.yaml parameters: @@ -56,7 +56,7 @@ jobs: pool: vmImage: 'windows-latest' dependsOn: waitForRunningBuilds - timeoutInMinutes: 120 + timeoutInMinutes: 240 steps: - template: ./templates/verify-testConfigSettingsHash.yaml - template: ./templates/run-staticAnalysis.yaml @@ -72,7 +72,7 @@ jobs: pool: vmImage: 'ubuntu-latest' dependsOn: waitForRunningBuilds - timeoutInMinutes: 120 + timeoutInMinutes: 240 steps: - template: ./templates/verify-testConfigSettingsHash.yaml - template: ./templates/run-staticAnalysis.yaml @@ -88,7 +88,7 @@ jobs: pool: vmImage: 'macOS-latest' dependsOn: waitForRunningBuilds - timeoutInMinutes: 120 + timeoutInMinutes: 240 steps: - template: ./templates/verify-testConfigSettingsHash.yaml - template: ./templates/run-staticAnalysis.yaml diff --git a/build/pipelines/azure-pipelines.release.yaml b/build/pipelines/azure-pipelines.release.yaml index 9bdfa841..0fef296d 100644 --- a/build/pipelines/azure-pipelines.release.yaml +++ b/build/pipelines/azure-pipelines.release.yaml @@ -28,7 +28,7 @@ jobs: - job: Validate pool: vmImage: 'windows-latest' - timeoutInMinutes: 120 + timeoutInMinutes: 240 steps: - template: ./templates/run-staticAnalysis.yaml - template: ./templates/run-unitTests.yaml From e9a6810b3c1a3c6b2ec798bc06f4fa50be154e87 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 9 Sep 2020 08:15:35 -0700 Subject: [PATCH 05/51] Fix default logPath when no user profile is available (#283) In Azure Function Apps, the special `MyDocuments` folder resolves to an empty string, which means that the default `logPath` gets stored as an empty string. https://github.com/microsoft/PowerShellForGitHub/blob/3094c9789caf00382134a0703344f655b13a1e33/GitHubConfiguration.ps1#L650-L657 https://github.com/microsoft/PowerShellForGitHub/blob/3094c9789caf00382134a0703344f655b13a1e33/GitHubConfiguration.ps1#L671 This causes problems when `Write-Log` is called by any other function, because we directly assign the current configuration value for `LogPath` as the parameter's default, which throws an exception when an empty string is assigned. https://github.com/microsoft/PowerShellForGitHub/blob/3094c9789caf00382134a0703344f655b13a1e33/Helpers.ps1#L142 In this scenario, we'll fall back to using the `LocalApplicationDataFolder` folder and writing a verbose message to the user letting them know this has happened. I've opted for a verbose message as opposed to a warning to avoid a constant annoying warning for users. The alternate path is documented in the updated USAGE.md, and it's also retrievable by calling `Get-GitHubConfiguration -Name LogPath`. Documentation has also been updated to reflect this behavior change. Fixes #282 --- GitHubConfiguration.ps1 | 25 +++++++++++++++++++++---- USAGE.md | 4 +++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/GitHubConfiguration.ps1 b/GitHubConfiguration.ps1 index 06a8e252..917422ba 100644 --- a/GitHubConfiguration.ps1 +++ b/GitHubConfiguration.ps1 @@ -6,7 +6,7 @@ # The location of the file that we'll store any settings that can/should roam with the user. [string] $script:configurationFilePath = [System.IO.Path]::Combine( - [Environment]::GetFolderPath('ApplicationData'), + [System.Environment]::GetFolderPath('ApplicationData'), 'Microsoft', 'PowerShellForGitHub', 'config.json') @@ -14,7 +14,7 @@ # The location of the file that we'll store the Access Token SecureString # which cannot/should not roam with the user. [string] $script:accessTokenFilePath = [System.IO.Path]::Combine( - [Environment]::GetFolderPath('LocalApplicationData'), + [System.Environment]::GetFolderPath('LocalApplicationData'), 'Microsoft', 'PowerShellForGitHub', 'accessToken.txt') @@ -650,10 +650,16 @@ function Import-GitHubConfiguration # Create a configuration object with all the default values. We can then update the values # with any that we find on disk. $logPath = [String]::Empty + $logName = 'PowerShellForGitHub.log' $documentsFolder = [System.Environment]::GetFolderPath('MyDocuments') - if (-not [System.String]::IsNullOrEmpty($documentsFolder)) + $logToLocalAppDataFolder = [System.String]::IsNullOrEmpty($documentsFolder) + if ($logToLocalAppDataFolder) { - $logPath = Join-Path -Path $documentsFolder -ChildPath 'PowerShellForGitHub.log' + $logPath = Join-Path -Path ([System.Environment]::GetFolderPath('LocalApplicationData')) -ChildPath $logName + } + else + { + $logPath = Join-Path -Path $documentsFolder -ChildPath $logName } $config = [PSCustomObject]@{ @@ -697,6 +703,17 @@ function Import-GitHubConfiguration $config.$name = Resolve-PropertyValue -InputObject $jsonObject -Name $name -Type $type -DefaultValue $config.$name } + # Let the user know when we had to revert to using the LocalApplicationData folder for the + # log location (if they haven't already changed its path in their local config). + $configuredLogPath = $config.logPath + if ($logToLocalAppDataFolder -and ($logPath -eq $configuredLogPath)) + { + # Limited instance where we write the warning directly instead of using Write-Log, since + # Write-Log won't yet be configured. + $message = "Storing log at non-default location: [$logPath] (no user profile path was found). You can change this location by calling Set-GitHubConfiguration -LogPath " + Write-Verbose -Message $message + } + return $config } diff --git a/USAGE.md b/USAGE.md index 68da5e24..5a5371d5 100644 --- a/USAGE.md +++ b/USAGE.md @@ -137,7 +137,9 @@ The logging is affected by configuration properties (which can be checked with `Get-GitHubConfiguration` and changed with `Set-GitHubConfiguration`). **`LogPath`** [string] The logfile. Defaults to - `$env:USERPROFILE\Documents\PowerShellForGitHub.log` + `([System.Environment]::GetFolderPath('MyDocuments'))\PowerShellForGitHub.log`. Will default to + `([System.Environment]::GetFolderPath('LocalApplicationData'))\PowerShellForGitHub.log` when + there is no user profile (like in an Azure environment). **`DisableLogging`** [bool] Defaults to `$false`. From 5b835cd5437d7d9d58217034900c3400f617f5c1 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 9 Sep 2020 08:35:39 -0700 Subject: [PATCH 06/51] Update module to 0.15.1 (#284) --- CHANGELOG.md | 103 +++++++++++++++++++++++++++++++++------ PowerShellForGitHub.psd1 | 2 +- 2 files changed, 88 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c28410a..497e8f72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,29 @@ # PowerShellForGitHub PowerShell Module -## Changelog +# Changelog + +## [0.15.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.15.1) - (2020/09/09) + +### Fixes: + +- Fixed the default `LogPath` when no user profile is available (like in the situation of running + within the context of an Azure Function App). The alternate default log path in this scenario + will now be the `LocalApplicationDataFolder`. + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/283) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/e9a6810b3c1a3c6b2ec798bc06f4fa50be154e87) + +Authors: + * [**@HowardWolosky**](https://github.com/HowardWolosky) + +------ + +## [0.15.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.15.0) - (2020/08/16) - [0.15.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.15.0) - (2020/08/16) ### Overview: + This is a significant update that has a number of breaking changes amongst its payload that existing users need to be made aware of. ### Highlights: + + Complete pipeline support has been added to the module. You can now pipe the output of almost any command as input to almost any command. Every command output now has a specific `GitHub.*` type that is queryable as well. @@ -56,6 +73,7 @@ existing users need to be made aware of. ### Breaking Changes #### Stardized naming (and verb usage) throughout the module + * A number of commands have been renamed to follow the pattern that we're standardizing on: `Get` / `Set` / `New` / `Remove` (but we will continue to alias `Remove-*` as `Delete-*`). @@ -97,6 +115,7 @@ existing users need to be made aware of. * `Set-GitHubRepositoryTopic`: `Name` -> `Topic` (although we kept an alias for `Name`) #### Other breaking changes + * All `Remove-*` functions (and some `Rename-*`/`Set-*` functions) now prompt for confirmation before performing the requested action. This can be silently bypassed by passing-in `-Confirm:$false` or `-Force`. @@ -139,6 +158,7 @@ existing users need to be made aware of. functionality has been deprecated by GitHub. You can use `TeamSlug` instead. ### Features: + + Complete pipeline support has been added to the module. You can now pipe the output of almost any command as input to almost any command. Every command output now has a specific `GitHub.*` type that is queryable as well. @@ -241,8 +261,6 @@ existing users need to be made aware of. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/276) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/9600fc21120e17241e60606c5de3459d973026bb) ### Fixes: -- Example description - [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/xxx) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/xxxxxxx) - Module update check needs to be able to handle when the module in use is newer than the published version (since publication to PowerShellGallery happens a few hours after the version is updated @@ -309,8 +327,10 @@ Authors: ------ - [0.14.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.14.0) - (2020/05/30) +## [0.14.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.14.0) - (2020/05/30) + ### Features: + + The module will now asynchronously check for updates up to once per day. This can be disabled if desired with the `Set-GitHubConfiguration -DisableUpdateCheck`. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/185) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/a9f48a8aec796195664c3d86eb11755a1394d34e) @@ -319,6 +339,7 @@ Authors: [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/180) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/b7e1ea1cb912493e110b9854b0ec7700462254a0) ### Fixes: + - Fixes the behavior of `Get-GitHubRepository`. It actually had a number of issues: [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/179) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/c4c1ec344a357489d248b9cf1bc2837484d4915f) - `-GetAllPublicRepositories` didn't acutally work. Now it does, along with the newly @@ -354,8 +375,10 @@ Authors: ------ - [0.13.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.13.1) - (2020/05/12) +## [0.13.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.13.1) - (2020/05/12) + ### Fixes: + - Ensure progress bar for Wait-JobWithAnimation gets marked as Completed [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/169) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/bb2ad45f61f4e55ba763d5eb402c80de5991bb6b) @@ -364,8 +387,10 @@ Authors: ------ - [0.13.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.13.0) - (2020/05/12) +## [0.13.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.13.0) - (2020/05/12) + ### Improvement: + - Migrate REST API progress status to use Write-Progress [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/167) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/992f67871cd659dac20833487b326bdad7b85bd8) @@ -374,8 +399,10 @@ Authors: ------ - [0.12.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.12.0) - (2020/05/12) +## [0.12.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.12.0) - (2020/05/12) + ### Features: + + Added core support for Projects [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/160) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/1cdaac1a5af873589458bd0b40b3651187ec7e19) + Added suport for Project Columns @@ -386,6 +413,7 @@ Authors: [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/164) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/1556b8b39cd61735aad14be0fb237c14e763f696) ### Fixes: + - Minor spelling fixes in documentation throughout module [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/165) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/6735ba57a5a43b61a37ef09d4021296dcd417dba) - Fixed confirmation message for `Rename-GitHubRepository` @@ -397,8 +425,10 @@ Authors: ------ - [0.11.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.11.0) - (2020/04/03) +## [0.11.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.11.0) - (2020/04/03) + ### Features: + + Added `Get-GitHubContents` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/146) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/9a45908dc65b3e8dd0227083fab281099cf07b1b) @@ -406,8 +436,10 @@ Author: [**@Shazwazza**](https://github.com/Shazwazza) ------ - [0.10.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.10.0) - (2020/03/02) +## [0.10.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.10.0) - (2020/03/02) + ### Features: + + Added `Rename-GitHubRepository` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/145) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/536b762425d51a181166c2c47ad2b00014911d1d) @@ -415,8 +447,10 @@ Author: [**@mtboren**](https://github.com/mtboren) ------ - [0.9.2](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.2) - (2019/11/11) +## [0.9.2](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.2) - (2019/11/11) + ### Fixes: + - Reduces the warning noise seen during execution of the unit tests. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/130) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/89f69f1132505f04e6b2ac38b6f5a93aef6ac947) @@ -424,8 +458,10 @@ Author: [**@smaglio81**](https://github.com/smaglio81) ------ - [0.9.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.1) - (2019/09/24) +## [0.9.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.1) - (2019/09/24) + ### Fixes: + - Ensure Milestone `due_on` always gets set to the desired date. (Attempts to work around odd GitHub behavior which uses PST/PDT's midnight to determine the date instead of UTC.) [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/133) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/013452b5cd8a7d7655cb32031d5ebdb580af16d9) @@ -439,8 +475,10 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) ------ - [0.9.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.0) - (2019/09/19) +## [0.9.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.0) - (2019/09/19) + ### Features: + + Added `Get-GitHubRelease` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/125) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/7ea773c715525273dddd451d2a05f429e7fe69e1) + Added `New-GitHubPullRequest` @@ -461,13 +499,16 @@ Authors: ------ - [0.8.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.8.0) - (2019/04/12) +## [0.8.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.8.0) - (2019/04/12) + ### Features: + + Added support for GitHub Enterprise users by adding a new `ApiHostName` configuration value. ([more info](https://github.com/Microsoft/PowerShellForGitHub/blob/master/README.md#github-enterprise)) [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/101) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/d5acd0f73d97f6692914976ce9366456a59cbf70) ### Fixes: + - Renamed `ConvertFrom-Markdown` to `ConvertFrom-GitHubMarkdown` to avoid a conflict with PSCore's new `ConvertFrom-Markdown` command. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/100) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/088f95b5a1340c7ce570e6e68a41967fd5760c46) @@ -478,14 +519,17 @@ Authors: ------ - [0.7.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.7.0) - (2019/03/15) +## [0.7.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.7.0) - (2019/03/15) + ### Features: + + Added `Test-GitHubOrganizationMember` to test if a user is in an organization. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/90) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/c60bb29ac02e7ab9fcd2e29db865b63876cb0125) + Updated `Get-GitHubTeamMember` to optionally work directly with a TeamId. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/90) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/c60bb29ac02e7ab9fcd2e29db865b63876cb0125) ### Fixes: + - Modified all [int] parameters to be [int64] to avoid out of bounds issues with large ID's. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/94) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/a22739e7f535faf4c5f486694bd213782437e82a) - `Split-GitHubUri` updated to work with the `https://api.github.com/*` uri's included in some of @@ -496,8 +540,10 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) ------ - [0.6.4](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.4) - (2019/01/16) +## [0.6.4](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.4) - (2019/01/16) + ### Fixes: + - Updated the `*-GitHubIssue` functions to support specifying the `MediaType` that should be used for the returned result. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/83) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/e3b6c53017abd36fc70253e1a49c31046c885ad1) @@ -507,7 +553,9 @@ Author: [**@joseartrivera**](https://github.com/joseartrivera) ------ ## [0.6.3](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.3) - (2019/01/07) + ### Fixes: + - Updated all parameter sets to use `CamelCase` for the permitted options, and stopped any use of abbreviation, to be more consistent with the rest of PowerShell. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/81) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/185441078efeb0e6693eafeb023785388a1a5a69) @@ -517,7 +565,9 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.6.2](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.2) - (2018/12/13) + ### Fixes: + - Fixes a bug preventing Labels from being correctly added at the time of new Issue creation or modified when updating an issue. {[[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/76) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/3b6e84cbafaf044e2154a06612b1c43a873cd002) and @@ -530,7 +580,9 @@ Authors: ------ ## [0.6.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.1) - (2018/12/13) + ### Fixes: + - Fixes a bug with checking Issues. When trying to list all issues, it tried to speficially look for Issue 0. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/73) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/bf6764080ce1291cfe2530a39ffd292f38b37440) @@ -541,7 +593,9 @@ Authors: ------ ## [0.6.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.0) - (2018/12/13) + ### Features: + + Completes all support for GitHub Issue API's: + Added support for the [Issue Event](https://developer.github.com/v3/issues/events/) API's. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/64) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/06e25243086954013b50c1fa7e3eb11bc34a9501) @@ -561,13 +615,16 @@ Authors: ------ ## [0.5.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.5.0) - (2018/11/30) + ### Features: + + Added support for the [Issue Comment](https://developer.github.com/v3/issues/comments/) API's. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/53) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/28b314bd7c0a810848e1acb3df43a1d83291be7b) + Added support for the [Issue Assignee](https://developer.github.com/v3/issues/assignees/) API's. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/54) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/680696a833b3cc753e961fc8c723b0be9b39ecc2) ### Fixes: + - Fixed bug that caused single or empty arrays returned within objects to be flattened (instead of remaining as arrays) [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/56) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/6cf344fb38485275f94b1e85c1a5f932e1b519c3) @@ -579,11 +636,14 @@ Authors: ------ ## [0.4.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.4.0) - (2018/11/16) + ### Features: + + Added support for the [Repository Traffic API's](https://developer.github.com/v3/repos/traffic/). [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/49) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/8d2e76f9059f0939b892d08386fe43f0e2722bb0) ### Fixes: + - Made NuGet dll retrieval more robust by preventing potential file access problems from being written to the error stream. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/48) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/b614f4a0fbcb570ef462fea64f776ca85480de86) @@ -598,7 +658,9 @@ Authors: ------ ## [0.3.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.3.1) - (2018/11/13) + ### Fixes: + - Minor static analysis issues fixed. - Corrected name of the test file for `GitHubRepositoryForks` - Ensured the `getParams` are used during execution of `Get-GitHubRepositoryFork` @@ -610,10 +672,13 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.3.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.3.0) - (2018/11/13) + ### Features: + + Added support for querying forks and creating new ones. ### Fixes: + - Will only perform a retry when receiving a `202` response on a `GET` request. Previously, it would retry regardless of the method of the request. @@ -624,7 +689,9 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.2.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.2.0) - (2018/11/13) + ### Features: + + Significant restructing and refactoring of entire module to make future expansion easier. + Significant documentation updates ([CHANGELOG](./CHANGELOG.md), [CONTRIBUTING.md](./CONTRIBUTING.md), [GOVERNANCE.md](./GOVERNANCE.md), [README.md](./README.md), [USAGE.md](./USAGE.md)) @@ -644,6 +711,7 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) + Enhanced user query support as well as being able update information for the current user. ### Fixes: + - Made parameter ordering consistent across all functions (OwnerName is now first, then RepositoryName) - Normalized all parameters to use SentenceCase - All functions that can take a Uri or OwnerName/RepositoryName now support both options. @@ -656,6 +724,7 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) - Normalized usage of Verbose, Info and Error streams ### Functionality Modified from 0.1.0: + * `New-GitHubLabels` was renamed to `Set-GitHubLabel` and can now optionally take in the labels to apply to the Repository. * `Get-GitHubIssueForRepository` has been removed and replaced with `Get-GitHubIssue`. @@ -691,7 +760,9 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.1.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.1.0) - (2016/11/29) + ### Features: + + Initial public release More Info: [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/6a3b400019d6a97ccc2f08a951fd4b2d09282eb5) diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 851b81fa..680a9dea 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -7,7 +7,7 @@ CompanyName = 'Microsoft Corporation' Copyright = 'Copyright (C) Microsoft Corporation. All rights reserved.' - ModuleVersion = '0.15.0' + ModuleVersion = '0.15.1' Description = 'PowerShell wrapper for GitHub API' # Script module or binary module file associated with this manifest. From 35be16a9c4643d3d9e081682b1d4868fce780b8c Mon Sep 17 00:00:00 2001 From: Jack Samuel S Date: Sun, 27 Sep 2020 00:13:12 +0530 Subject: [PATCH 07/51] Fix typos in USAGE.md (#288) Fixes #287 --- USAGE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/USAGE.md b/USAGE.md index 5a5371d5..6117b1e9 100644 --- a/USAGE.md +++ b/USAGE.md @@ -422,8 +422,8 @@ Get-GitHubRepositoryContributor -OwnerName 'PowerShell' -RepositoryName 'PowerSh #### Querying Team and Organization Membership ```powershell -$organizationMembers = Get-GitHubOrganizationMembers -OrganizationName 'OrganizationName' -$teamMembers = Get-GitHubTeamMembers -OrganizationName 'OrganizationName' -TeamName 'TeamName' +$organizationMembers = Get-GitHubOrganizationMember -OrganizationName 'OrganizationName' +$teamMembers = Get-GitHubTeamMember -OrganizationName 'OrganizationName' -TeamName 'TeamName' ``` ---------- From 4379a46572c968ef3cd06f275d8b4be171fc8820 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Sun, 4 Oct 2020 23:07:59 -0700 Subject: [PATCH 08/51] Auto-generate documentation for Wiki (#292) This adds a new script utility, `Build-Wiki.ps1`, which can be used to auto-generate the documentation for the Wiki. This uses the [PlatyPS](https://github.com/PowerShell/PlatyPS) module to generate the actual help documentation. Relevant notes: * This will generate the `Home.md`, `_sidebar.md`, and `_footer.md` files for the Wiki if they don't already exist in the destination directory. * If they do already exist, it intelligently updates the content, only replacing the parts that it generated itself (denoted with comments in the markdown content itself). * At present, this is not being hooked-up to CI because I don't want to deal with storing credentials that have admin access to the actual repo. Tip of the hat to @X-Guardian for the suggestion and the initial help with writing this out. Resolves #208 --- build/scripts/Build-Wiki.ps1 | 514 +++++++++++++++++++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 build/scripts/Build-Wiki.ps1 diff --git a/build/scripts/Build-Wiki.ps1 b/build/scripts/Build-Wiki.ps1 new file mode 100644 index 00000000..f1b48a30 --- /dev/null +++ b/build/scripts/Build-Wiki.ps1 @@ -0,0 +1,514 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# + .SYNOPSIS + Builds the markdown documentation for the module. + + .DESCRIPTION + Builds the markdown documentation for the module using the PlatyPS PowerShell module. + + .PARAMETER Path + Specifies the output path for the function markdown files. + + .PARAMETER ModulePath + Specifies the path of the module to generate the help for. + + .PARAMETER ModuleName + Specifies the name of the already loaded module to generate the help for. + + .PARAMETER Description + Specifies the description for the module. + + .PARAMETER RemoveDeprecated + Removes any files that were previously generated but were not generated during this update. + Those files likely represent functions that were either renamed, removed or that stopped + being exported. + + .PARAMETER Force + Indicates that this should overwrite existing files that have the same names. + + .INPUTS + None + + .OUTPUTS + None + + .EXAMPLE + Build-Wiki -Path './' -ModuleName 'PowerShellForGitHub' -RemoveDeprecated +#> +[CmdletBinding(DefaultParameterSetName='ModuleName')] +param +( + [string] $Path = 'docs', + + [Parameter( + Mandatory, + ParameterSetName='ModulePath')] + [string] $ModulePath, + + [Parameter( + ParameterSetName='ModuleName')] + [string] $ModuleName = 'PowerShellForGitHub', + + [string] $Description = 'PowerShellForGitHub is a PowerShell module that provides command-line interaction and automation for the [GitHub v3 API](https://developer.github.com/v3/).', + + [switch] $RemoveDeprecated, + + [switch] $Force +) + +function Out-Utf8File +{ +<# + .DESCRIPTION + Writes a file using UTF8 (no BOM) encoding. + + .PARAMETER Path + The path to the file to write to. + + .PARAMETER Content + The string content for the file. + + .PARAMETER Force + Indicates that this should overwrite an existing file that has the same name. + + .INPUTS + String + + .EXAMPLE + Out-Utf8File -Path ./foo.txt -Content 'bar' + Creates a 'foo.txt' in the current working directory with the content 'bar' as a UTF-8 file + without BOM. + + .NOTES + This is being used because the PS5 Encoding options only include utf8 with BOM, and we + want to write without BOM. This is fixed in PS6+, but we need to support PS4+. +#> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(ValueFromPipeline)] + [string] $Content, + + [switch] $Force + ) + + begin + { + if (Test-Path -Path $Path -PathType Leaf) + { + if ($Force.IsPresent) + { + Remove-Item -Path $Path -Force | Out-Null + } + else + { + throw "[$Path] already exists and -Force was not specified." + } + } + + $stream = New-Object -TypeName System.IO.StreamWriter -ArgumentList ($Path, [System.Text.Encoding]::UTF8) + } + + process + { + + $stream.WriteLine($Content) + } + + end + { + $stream.Close(); + } +} + +function Build-SideBar +{ +<# + .DESCRIPTION + Generate the sidebar content file. + + .PARAMETER Path + The path where the file should be written to. + + .PARAMETER ModuleRootPageFileName + The filename for the root of the module documentation. + + .PARAMETER ModuleName + The name of the module the documentation is for. + + .PARAMETER ModulePages + The names of the module pages that have been generated. + + .EXAMPLE + Build-SideBar -Path ./docs -ModuleRootPageFileName 'root.md' -ModuleName 'PowerShellForGitHub' -ModulePages @('Foo', 'Bar') +#> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [string] $ModuleRootPageFileName, + + [Parameter(Mandatory)] + [string] $ModuleName, + + [string[]] $ModulePages + ) + + $sideBarFilePath = Join-Path -Path $Path -ChildPath '_sidebar.md' + + $moduleRootPageBaseName = $ModuleRootPageFileName.Substring(0, $ModuleRootPageFileName.lastIndexOf('.')) + + $moduleContentStartMarker = '' + $moduleContentEndMarker = '' + $moduleContent = @() + $moduleContent += $moduleContentStartMarker + $moduleContent += '### Docs' + $moduleContent += '' + $moduleContent += "[$ModuleName]($moduleRootPageBaseName)" + $moduleContent += '' + $moduleContent += '#### Functions' + $moduleContent += '' + foreach ($modulePage in $modulePages) + { + $moduleContent += "- [$modulePage]($modulePage)" + } + $moduleContent += $moduleContentEndMarker + $moduleContent += '' + + $content = '' + $docsSideBarRegEx = "$moduleContentStartMarker[\r\n]+(?:[^<]+[\r\n]+)*$moduleContentEndMarker[\r\n]+" + if (Test-Path -Path $sideBarFilePath -PathType Leaf) + { + $content = Get-Content -Path $sideBarFilePath -Raw -Encoding utf8 + if ($content -match $docsSideBarRegEx) + { + $content = $content -replace $docsSideBarRegEx,($moduleContent -join [Environment]::NewLine) + } + else + { + $content += [Environment]::NewLine + $content += ($moduleContent -join [Environment]::NewLine) + } + } + else + { + $newContent = @() + $newContent += "## $ModuleName" + $newContent += '' + $newContent += $moduleContent + $content = $newContent -join [Environment]::NewLine + } + + $content | Out-Utf8File -Path $sideBarFilePath -Force +} + +function Build-Footer +{ +<# + .DESCRIPTION + Generate the footer content file. + + .PARAMETER Path + The path where the file should be written to. + + .PARAMETER ModuleRootPageFileName + The filename for the root of the module documentation. + + .PARAMETER ModuleName + The name of the module the documentation is for. + + .EXAMPLE + Build-Footer -Path ./docs -ModuleRootPageFileName 'root.md' -ModuleName 'PowerShellForGitHub' +#> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [string] $ModuleRootPageFileName, + + [Parameter(Mandatory)] + [string] $ModuleName + ) + + $footerFilePath = Join-Path -Path $Path -ChildPath '_footer.md' + + $moduleRootPageBaseName = $ModuleRootPageFileName.Substring(0, $ModuleRootPageFileName.lastIndexOf('.')) + + $moduleContentStartMarker = '' + $moduleContentEndMarker = '' + $moduleContent = @() + $moduleContent += $moduleContentStartMarker + $moduleContent += '' + $moduleContent += "[Back to [$ModuleName]($moduleRootPageBaseName)]" + $moduleContent += '' + $moduleContent += $moduleContentEndMarker + $moduleContent += '' + + $content = '' + $docsFooterRegEx = "$moduleContentStartMarker[\r\n]+(?:[^<]+[\r\n]+)*$moduleContentEndMarker[\r\n]+" + if (Test-Path -Path $footerFilePath -PathType Leaf) + { + $content = Get-Content -Path $footerFilePath -Raw -Encoding utf8 + if ($content -match $docsFooterRegEx) + { + $content = $content -replace $docsFooterRegEx,($moduleContent -join [Environment]::NewLine) + } + else + { + $content += [Environment]::NewLine + $content += ($moduleContent -join [Environment]::NewLine) + } + } + else + { + $content = ($moduleContent -join [Environment]::NewLine) + } + + $content | Out-Utf8File -Path $footerFilePath -Force +} + +function Build-HomePage +{ +<# + .DESCRIPTION + Generate the home page file for the Wiki. + + .PARAMETER Path + The path where the file should be written to. + + .PARAMETER ModuleRootPageFileName + The filename for the root of the module documentation. + + .EXAMPLE + Build-HomePage -Path ./docs -ModuleRootPageFileName 'root.md' +#> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [string] $ModuleRootPageFileName + ) + + $homePageFilePath = Join-Path -Path $Path -ChildPath 'Home.md' + + $moduleRootPageBaseName = $ModuleRootPageFileName.Substring(0, $ModuleRootPageFileName.lastIndexOf('.')) + + $moduleContentStartMarker = '' + $moduleContentEndMarker = '' + $moduleContent = @() + $moduleContent += $moduleContentStartMarker + $moduleContent += '' + $moduleContent += "[Full Module Documentation]($moduleRootPageBaseName)" + $moduleContent += '' + $moduleContent += $moduleContentEndMarker + $moduleContent += '' + + $content = '' + $docsFooterRegEx = "$moduleContentStartMarker[\r\n]+(?:[^<]+[\r\n]+)*$moduleContentEndMarker[\r\n]+" + if (Test-Path -Path $homePageFilePath -PathType Leaf) + { + $content = Get-Content -Path $homePageFilePath -Raw -Encoding utf8 + if ($content -match $docsFooterRegEx) + { + $content = $content -replace $docsFooterRegEx,($moduleContent -join [Environment]::NewLine) + } + else + { + $content += [Environment]::NewLine + $content += ($moduleContent -join [Environment]::NewLine) + } + } + else + { + $content = ($moduleContent -join [Environment]::NewLine) + } + + $content | Out-Utf8File -Path $homePageFilePath -Force +} + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version 1.0 + +$Path = Resolve-Path -Path $Path + +$numSteps = 11 +$currentStep = 0 +$progressParams = @{ + 'Activity' = 'Generating documentation for wiki' + 'Id' = 1 +} + +####### +$currentStep++ +Write-Progress @progressParams -Status 'Ensuring PlatyPS installed' -PercentComplete (($currentStep / $numSteps) * 100) +if ($null -eq (Get-Module -Name 'PlatyPS')) +{ + Write-Verbose -Message 'Installing PlatyPS Module' + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force -Verbose:$false | Out-Null + Install-Module PlatyPS -Scope CurrentUser -Force +} + +####### +$currentStep++ +Write-Progress @progressParams -Status 'Ensuring source module is loaded' -PercentComplete (($currentStep / $numSteps) * 100) +if (-not [String]::IsNullOrEmpty($ModulePath)) +{ + Write-Verbose -Message "Importing [$ModulePath]" + $module = Import-Module -Name $ModulePath -PassThru -Force -Verbose:$false + $ModuleName = $module.Name +} + +$moduleRootPageFileName = "$ModuleName.md" + +# We generate the files to a _temp_ directory so that we can determine if there have been any +# files that should be _removed_ from the Wiki due to rename/removal of exports. +$tempFolder = Join-Path -Path $env:TEMP -ChildPath ([Guid]::NewGuid().Guid) +New-Item -Path $tempFolder -ItemType Directory | Out-Null + +####### +$currentStep++ +Write-Progress @progressParams -Status 'Creating the new module markdown help files' -PercentComplete (($currentStep / $numSteps) * 100) + +# The ModulePage is generated to the current working directory, so we need to be temporarily located +# at the temp folder. +Push-Location -Path $tempFolder + +$params = @{ + Module = $ModuleName + OutputFolder = $tempFolder + UseFullTypeName = $true + AlphabeticParamsOrder = $true + WithModulePage = $true + ModulePagePath = $moduleRootPageFileName + NoMetadata = $false # Otherwise was having issues with Update-MarkdownHelpModule + FwLink = 'N/A' + Encoding = ([System.Text.Encoding]::UTF8) + Force = $true +} +New-MarkdownHelp @params | Out-Null + +####### +$currentStep++ +Write-Progress @progressParams -Status 'Updating the generated documentation' -PercentComplete (($currentStep / $numSteps) * 100) +$params = @{ + Path = $tempFolder + RefreshModulePage = $true + ModulePagePath = $moduleRootPageFileName + UseFullTypeName = $true + AlphabeticParamsOrder = $true + Encoding = ([System.Text.Encoding]::UTF8) +} +Update-MarkdownHelpModule @params | Out-Null + +# The ModulePage is generated to the current working directory. Now that we're done generating, +# let's go back to our original location +Pop-Location + +####### +$currentStep++ +Write-Progress @progressParams -Status "Cleaning up content in $moduleRootPageFileName" -PercentComplete (($currentStep / $numSteps) * 100) +$moduleRootPageFilePath = Join-Path -Path $tempFolder -ChildPath $moduleRootPageFileName +$moduleRootPageContent = Get-Content -Path $moduleRootPageFilePath -Raw -Encoding utf8 +$moduleRootPageContent = $moduleRootPageContent.Replace('.md)', ')') + +$descriptionMarker = '{{ Fill in the Description }}' +$moduleRootPageContent = $moduleRootPageContent.Replace($descriptionMarker, $Description) +$moduleRootPageContent | Out-Utf8File -Path $moduleRootPageFilePath -Force | Out-Null + +####### +$currentStep++ +Write-Progress @progressParams -Status "Removing metadata from generated files" -PercentComplete (($currentStep / $numSteps) * 100) +$modulePages = @() +$generatedFiles = Get-ChildItem -Path $tempFolder -Filter '*.md' +$metadataRegEx = '^---[\r\n]+(?:[^-].+[\r\n]+){1,10}---[\r\n]{1,4}' +$generatedMarker = '' + [Environment]::NewLine +foreach ($file in $generatedFiles) +{ + $fileContent = Get-Content -Path $file.FullName -Raw -Encoding utf8 + if ($fileContent -match $metadataRegEx) + { + $fileContent = $fileContent -replace $metadataRegEx,$generatedMarker + $fileContent | Out-Utf8File -Path $file.FullName -Force + + if ($file.Name -ne $moduleRootPageFileName) + { + $modulePages += $file.BaseName + } + } +} + +####### +$currentStep++ +Write-Progress @progressParams -Status "Updating sidebar" -PercentComplete (($currentStep / $numSteps) * 100) +Build-SideBar -Path $Path -ModuleRootPageFileName $moduleRootPageFileName -ModuleName $ModuleName -ModulePages $modulePages + +####### +$currentStep++ +Write-Progress @progressParams -Status "Updating footer" -PercentComplete (($currentStep / $numSteps) * 100) +Build-Footer -Path $Path -ModuleRootPageFileName $moduleRootPageFileName -ModuleName $ModuleName + +####### +$currentStep++ +Write-Progress @progressParams -Status "Updating home page" -PercentComplete (($currentStep / $numSteps) * 100) +Build-HomePage -Path $Path -ModuleRootPageFileName $moduleRootPageFileName + +####### +$currentStep++ +Write-Progress @progressParams -Status "Detecting deprecated pages" -PercentComplete (($currentStep / $numSteps) * 100) +$deprecatedFiles = @() +$currentFiles = Get-ChildItem -Path $Path -Filter '*.md' +foreach ($file in $currentFiles) +{ + $content = Get-Content -Path $file -Raw -Encoding utf8 + if (($content -match $generatedMarker) -and + ($file.BaseName -notin $modulePages) -and + ($file.Name -ne $moduleRootPageFileName)) + { + $deprecatedFiles += $file + } +} + +if ($deprecatedFiles.Length -gt 0) +{ + if ($RemoveDeprecated.IsPresent) + { + Write-Verbose "The following files have been deprecated and will be removed:" + } + else + { + Write-Verbose "The following files have been deprecated. They can be removed automatically by specifying the -RemoveDeprecated switch." + } + + foreach ($file in $deprecatedFiles) + { + Write-Verbose "* $($file.Name)" + if ($RemoveDeprecated.IsPresent) + { + Remove-Item -Path $file.FullName -Force + } + } +} + +####### +$currentStep++ +Write-Progress @progressParams -Status "Moving generated content to final destination" -PercentComplete (($currentStep / $numSteps) * 100) +$files = Get-ChildItem -Path $tempFolder +foreach ($file in $files) +{ + Move-Item -Path $file -Destination $Path -Force:$Force.IsPresent +} + +Remove-Item -Path $tempFolder -Recurse -Force + +####### +Write-Progress @progressParams -Completed From ab536c772a7656f92166d13f5df9ef7bf6627a3f Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Mon, 5 Oct 2020 00:25:32 -0700 Subject: [PATCH 09/51] Add missing .SYNOPSIS to functions (#293) Now that we are generating help documentation for the module, we want to ensure that we have a .SYNOPSIS for every function CBH. --- GitHubAssignees.ps1 | 12 ++++++++++++ GitHubCore.ps1 | 5 ++++- GitHubEvents.ps1 | 5 ++++- GitHubIssueComments.ps1 | 18 +++++++++++++++--- GitHubLabels.ps1 | 9 +++++++++ GitHubMilestones.ps1 | 18 +++++++++++++++--- GitHubProjectCards.ps1 | 15 +++++++++++++++ GitHubProjectColumns.ps1 | 15 +++++++++++++++ GitHubProjects.ps1 | 14 +++++++++++++- 9 files changed, 102 insertions(+), 9 deletions(-) diff --git a/GitHubAssignees.ps1 b/GitHubAssignees.ps1 index 37bcc1ea..07e9649d 100644 --- a/GitHubAssignees.ps1 +++ b/GitHubAssignees.ps1 @@ -4,6 +4,9 @@ filter Get-GitHubAssignee { <# + .SYNOPSIS + Lists the available assignees for issues in a repository. + .DESCRIPTION Lists the available assignees for issues in a repository. @@ -103,6 +106,9 @@ filter Get-GitHubAssignee filter Test-GitHubAssignee { <# + .SYNOPSIS + Checks if a user has permission to be assigned to an issue in this repository. + .DESCRIPTION Checks if a user has permission to be assigned to an issue in this repository. @@ -230,6 +236,9 @@ filter Test-GitHubAssignee function Add-GitHubAssignee { <# + .SYNOPSIS + Adds a list of assignees to a GitHub Issue for the given repository. + .DESCRIPTION Adds a list of assignees to a GitHub Issue for the given repository. @@ -415,6 +424,9 @@ function Add-GitHubAssignee function Remove-GitHubAssignee { <# + .SYNOPSIS + Removes an assignee from a GitHub issue. + .DESCRIPTION Removes an assignee from a GitHub issue. diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index 04d4aa4a..eefbb02f 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -1046,8 +1046,11 @@ filter ConvertTo-SmarterObject function Get-MediaAcceptHeader { <# + .SYNOPSIS + Returns a formatted AcceptHeader based on the requested MediaType. + .DESCRIPTION - Returns a formatted AcceptHeader based on the requested MediaType + Returns a formatted AcceptHeader based on the requested MediaType. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub diff --git a/GitHubEvents.ps1 b/GitHubEvents.ps1 index 0a52683f..f231a4ff 100644 --- a/GitHubEvents.ps1 +++ b/GitHubEvents.ps1 @@ -10,8 +10,11 @@ filter Get-GitHubEvent { <# + .SYNOPSIS + Lists events for an issue, repository, or a single event. + .DESCRIPTION - Lists events for an issue, repository, or a single event + Lists events for an issue, repository, or a single event. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub diff --git a/GitHubIssueComments.ps1 b/GitHubIssueComments.ps1 index 3457bdf9..faf6dc34 100644 --- a/GitHubIssueComments.ps1 +++ b/GitHubIssueComments.ps1 @@ -11,6 +11,9 @@ filter Get-GitHubIssueComment { <# + .SYNOPSIS + Get the Issue comments for a given GitHub repository. + .DESCRIPTION Get the Issue comments for a given GitHub repository. @@ -279,8 +282,11 @@ filter Get-GitHubIssueComment filter New-GitHubIssueComment { <# + .SYNOPSIS + Creates a new GitHub comment for an issue for the given repository. + .DESCRIPTION - Creates a new GitHub comment for an issue for the given repository + Creates a new GitHub comment for an issue for the given repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub @@ -414,8 +420,11 @@ filter New-GitHubIssueComment filter Set-GitHubIssueComment { <# + .SYNOPSIS + Modifies an existing comment in an issue for the given repository. + .DESCRIPTION - Modifies an existing comment in an issue for the given repository + Modifies an existing comment in an issue for the given repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub @@ -565,8 +574,11 @@ filter Set-GitHubIssueComment filter Remove-GitHubIssueComment { <# + .SYNOPSIS + Deletes a GitHub comment from an Issue in the given repository. + .DESCRIPTION - Deletes a GitHub comment from an Issue in the given repository + Deletes a GitHub comment from an Issue in the given repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub diff --git a/GitHubLabels.ps1 b/GitHubLabels.ps1 index ce719091..7bb641a5 100644 --- a/GitHubLabels.ps1 +++ b/GitHubLabels.ps1 @@ -795,6 +795,9 @@ filter Initialize-GitHubLabel function Add-GitHubIssueLabel { <# + .SYNOPSIS + Adds a label to an issue in the given GitHub repository. + .DESCRIPTION Adds a label to an issue in the given GitHub repository. @@ -960,6 +963,9 @@ function Add-GitHubIssueLabel function Set-GitHubIssueLabel { <# + .SYNOPSIS + Replaces labels on an issue in the given GitHub repository. + .DESCRIPTION Replaces labels on an issue in the given GitHub repository. @@ -1159,6 +1165,9 @@ function Set-GitHubIssueLabel filter Remove-GitHubIssueLabel { <# + .SYNOPSIS + Deletes a label from an issue in the given GitHub repository. + .DESCRIPTION Deletes a label from an issue in the given GitHub repository. diff --git a/GitHubMilestones.ps1 b/GitHubMilestones.ps1 index 225f0a77..50adfbd7 100644 --- a/GitHubMilestones.ps1 +++ b/GitHubMilestones.ps1 @@ -14,6 +14,9 @@ $script:minimumHoursToEnsureDesiredDateInPacificTime = 9 filter Get-GitHubMilestone { <# + .SYNOPSIS + Get the milestones for a given GitHub repository. + .DESCRIPTION Get the milestones for a given GitHub repository. @@ -205,8 +208,11 @@ filter Get-GitHubMilestone filter New-GitHubMilestone { <# + .SYNOPSIS + Creates a new GitHub milestone for the given repository. + .DESCRIPTION - Creates a new GitHub milestone for the given repository + Creates a new GitHub milestone for the given repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub @@ -380,8 +386,11 @@ filter New-GitHubMilestone filter Set-GitHubMilestone { <# + .SYNOPSIS + Update an existing milestone for the given repository. + .DESCRIPTION - Update an existing milestone for the given repository + Update an existing milestone for the given repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub @@ -579,8 +588,11 @@ filter Set-GitHubMilestone filter Remove-GitHubMilestone { <# + .SYNOPSIS + Deletes a GitHub milestone for the given repository. + .DESCRIPTION - Deletes a GitHub milestone for the given repository + Deletes a GitHub milestone for the given repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub diff --git a/GitHubProjectCards.ps1 b/GitHubProjectCards.ps1 index 512fc9f2..1eef5118 100644 --- a/GitHubProjectCards.ps1 +++ b/GitHubProjectCards.ps1 @@ -10,6 +10,9 @@ filter Get-GitHubProjectCard { <# + .SYNOPSIS + Get the cards for a given GitHub Project Column. + .DESCRIPTION Get the cards for a given GitHub Project Column. @@ -124,6 +127,9 @@ filter Get-GitHubProjectCard filter New-GitHubProjectCard { <# + .SYNOPSIS + Creates a new card for a GitHub project. + .DESCRIPTION Creates a new card for a GitHub project. @@ -260,6 +266,9 @@ filter New-GitHubProjectCard filter Set-GitHubProjectCard { <# + .SYNOPSIS + Modify a GitHub Project Card. + .DESCRIPTION Modify a GitHub Project Card. @@ -386,6 +395,9 @@ filter Set-GitHubProjectCard filter Remove-GitHubProjectCard { <# + .SYNOPSIS + Removes a project card. + .DESCRIPTION Removes a project card. @@ -468,6 +480,9 @@ filter Remove-GitHubProjectCard filter Move-GitHubProjectCard { <# + .SYNOPSIS + Move a GitHub Project Card. + .DESCRIPTION Move a GitHub Project Card. diff --git a/GitHubProjectColumns.ps1 b/GitHubProjectColumns.ps1 index 22f7059a..49694f82 100644 --- a/GitHubProjectColumns.ps1 +++ b/GitHubProjectColumns.ps1 @@ -10,6 +10,9 @@ filter Get-GitHubProjectColumn { <# + .SYNOPSIS + Get the columns for a given GitHub Project. + .DESCRIPTION Get the columns for a given GitHub Project. @@ -101,6 +104,9 @@ filter Get-GitHubProjectColumn filter New-GitHubProjectColumn { <# + .SYNOPSIS + Creates a new column for a GitHub project. + .DESCRIPTION Creates a new column for a GitHub project. @@ -183,6 +189,9 @@ filter New-GitHubProjectColumn filter Set-GitHubProjectColumn { <# + .SYNOPSIS + Modify a GitHub Project Column. + .DESCRIPTION Modify a GitHub Project Column. @@ -271,6 +280,9 @@ filter Set-GitHubProjectColumn filter Remove-GitHubProjectColumn { <# + .SYNOPSIS + Removes the column for a project. + .DESCRIPTION Removes the column for a project. @@ -354,6 +366,9 @@ filter Remove-GitHubProjectColumn filter Move-GitHubProjectColumn { <# + .SYNOPSIS + Move a GitHub Project Column. + .DESCRIPTION Move a GitHub Project Column. diff --git a/GitHubProjects.ps1 b/GitHubProjects.ps1 index 0e5e32a9..04be78b4 100644 --- a/GitHubProjects.ps1 +++ b/GitHubProjects.ps1 @@ -10,6 +10,9 @@ filter Get-GitHubProject { <# + .SYNOPSIS + Get the projects for a given GitHub user, repository or organization. + .DESCRIPTION Get the projects for a given GitHub user, repository or organization. @@ -212,8 +215,11 @@ filter Get-GitHubProject filter New-GitHubProject { <# + .SYNOPSIS + Creates a new GitHub project for the given repository. + .DESCRIPTION - Creates a new GitHub project for the given repository + Creates a new GitHub project for the given repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub @@ -395,6 +401,9 @@ filter New-GitHubProject filter Set-GitHubProject { <# + .SYNOPSIS + Modify a GitHub Project. + .DESCRIPTION Modify a GitHub Project. @@ -543,6 +552,9 @@ filter Set-GitHubProject filter Remove-GitHubProject { <# + .SYNOPSIS + Removes the projects for a given GitHub repository. + .DESCRIPTION Removes the projects for a given GitHub repository. From c06614903e3c44a13442c6ced10a22f71684cee3 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 7 Oct 2020 14:22:16 -0700 Subject: [PATCH 10/51] Fix static-analyzer warning for Windows PowerShell The Build-* verb is new to PowerShell Core and so was considered unapproved for Windows PowerShell. Given that these are internal helper methods and it _is_ an approved verb in PS Core, keeping as-is and just marking these warning instances to be suppressed. --- build/scripts/Build-Wiki.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/scripts/Build-Wiki.ps1 b/build/scripts/Build-Wiki.ps1 index f1b48a30..4cf6e662 100644 --- a/build/scripts/Build-Wiki.ps1 +++ b/build/scripts/Build-Wiki.ps1 @@ -146,6 +146,7 @@ function Build-SideBar .EXAMPLE Build-SideBar -Path ./docs -ModuleRootPageFileName 'root.md' -ModuleName 'PowerShellForGitHub' -ModulePages @('Foo', 'Bar') #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="It's an approved verb in PS Core, just not Windows PowerShell. Plus, this is an internal helper.")] [CmdletBinding()] param( [Parameter(Mandatory)] @@ -226,6 +227,7 @@ function Build-Footer .EXAMPLE Build-Footer -Path ./docs -ModuleRootPageFileName 'root.md' -ModuleName 'PowerShellForGitHub' #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="It's an approved verb in PS Core, just not Windows PowerShell. Plus, this is an internal helper.")] [CmdletBinding()] param( [Parameter(Mandatory)] @@ -290,6 +292,7 @@ function Build-HomePage .EXAMPLE Build-HomePage -Path ./docs -ModuleRootPageFileName 'root.md' #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseApprovedVerbs", "", Justification="It's an approved verb in PS Core, just not Windows PowerShell. Plus, this is an internal helper.")] [CmdletBinding()] param( [Parameter(Mandatory)] From c92d8a64eb003fd77f18f5463ece36bf548caaf2 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Thu, 8 Oct 2020 12:56:37 -0700 Subject: [PATCH 11/51] Fix potential call depth overflow error when retrying a 202 response (#294) GitHub will return back a `202` response when the result for the query is not yet ready. GitHub requests that we "give the job a few moments to complete, and then submit the request again." We already had the configuration value `RetryDelaySeconds` which covered how many seconds we would sleep before trying the request again. We tried the request again via a recursive call to `Invoke-GHRestMethod`. It turns out that there's something going on with GitHub right now, and trying to get contributor statistics for a completely new repository never returns back a 200, even after 145 retry attempts over 72 minutes. That many recursive calls ends up causing a call depth overflow exception with PowerShell. While this scenario should be an edge-case, nonetheless it seems better to remove the possibility of this error from occurring by modifying the retry logic to be a loop rather than a recursive call. I've also added a new configuration value: `MaximumRetriesWhenResultNotReady` to help control and limit the number of retries that we'll attempt in this situation, ultimately throwing an exception if the retry limit is exceeded without a 200 response. Finally, I've disabled the `When getting Github Repository Contributors with Statistics` test until the problem is fixed on the GitHub end. I've disabled the test by commenting the test out vs using the disable keyword to avoid the Pester failure for disabled tests, and I've opened a [support issue](https://github.community/t/unable-to-retrieve-contributor-statistics-for-a-brand-new-repo/136658) on this problem. --- GitHubConfiguration.ps1 | 12 ++ GitHubCore.ps1 | 299 +++++++++++++++-------------- Tests/GitHubRepositories.tests.ps1 | 60 +++--- 3 files changed, 201 insertions(+), 170 deletions(-) diff --git a/GitHubConfiguration.ps1 b/GitHubConfiguration.ps1 index 917422ba..70e57d6d 100644 --- a/GitHubConfiguration.ps1 +++ b/GitHubConfiguration.ps1 @@ -135,6 +135,12 @@ function Set-GitHubConfiguration .PARAMETER LogTimeAsUtc If specified, all times logged will be logged as UTC instead of the local timezone. + .PARAMETER MaximumRetriesWhenResultNotReady + Some API requests may take time for GitHub to gather the results, and in the interim, + a 202 response is returned. This value indicates the maximum number of times that the + query will be retried before giving up and failing. The amount of time between each of + these requests is controlled by the RetryDelaySeconds configuration value. + .PARAMETER MultiRequestProgressThreshold Some commands may require sending multiple requests to GitHub. In some situations, getting the entirety of the request might take 70+ requests occurring over 20+ seconds. @@ -145,6 +151,8 @@ function Set-GitHubConfiguration .PARAMETER RetryDelaySeconds The number of seconds to wait before retrying a command again after receiving a 202 response. + The number of times that a retry will occur is controlled by the + MaximumRetriesWhenResultNotReady configuration value. .PARAMETER StateChangeDelaySeconds The number of seconds to wait before returning the result after executing a command that @@ -227,6 +235,8 @@ function Set-GitHubConfiguration [switch] $LogTimeAsUtc, + [int] $MaximumRetriesWhenResultNotReady, + [int] $MultiRequestProgressThreshold, [int] $RetryDelaySeconds, @@ -320,6 +330,7 @@ function Get-GitHubConfiguration 'LogProcessId', 'LogRequestBody', 'LogTimeAsUtc', + 'MaximumRetriesWhenResultNotReady', 'MultiRequestProgressThreshold', 'RetryDelaySeconds', 'StateChangeDelaySeconds', @@ -678,6 +689,7 @@ function Import-GitHubConfiguration 'logProcessId' = $false 'logRequestBody' = $false 'logTimeAsUtc' = $false + 'maximumRetriesWhenResultNotReady' = 30 'multiRequestProgressThreshold' = 10 'retryDelaySeconds' = 30 'stateChangeDelaySeconds' = 0 diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index eefbb02f..1e1cd8f7 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -196,6 +196,10 @@ function Invoke-GHRestMethod $errorBucket = $TelemetryEventName } + # Handling retries for 202 + $numRetriesAttempted = 0 + $maxiumRetriesPermitted = Get-GitHubConfiguration -Name 'MaximumRetriesWhenResultNotReady' + # Since we have retry logic, we won't create a new stopwatch every time, # we'll just always continue the existing one... $stopwatch.Start() @@ -261,182 +265,193 @@ function Invoke-GHRestMethod try { - Write-Log -Message $Description -Level Verbose - Write-Log -Message "Accessing [$Method] $url [Timeout = $(Get-GitHubConfiguration -Name WebRequestTimeoutSec))]" -Level Verbose - - $result = $null - $params = @{} - $params.Add("Uri", $url) - $params.Add("Method", $Method) - $params.Add("Headers", $headers) - $params.Add("UseDefaultCredentials", $true) - $params.Add("UseBasicParsing", $true) - $params.Add("TimeoutSec", (Get-GitHubConfiguration -Name WebRequestTimeoutSec)) - if ($PSBoundParameters.ContainsKey('InFile')) { $params.Add('InFile', $InFile) } - if (-not [String]::IsNullOrWhiteSpace($outFile)) { $params.Add('OutFile', $outFile) } - - if (($Method -in $ValidBodyContainingRequestMethods) -and (-not [String]::IsNullOrEmpty($Body))) + while ($true) # infinite loop for handling the 202 retry, but we'll either exit via a return, or throw an exception if retry limit exceeded. { - $bodyAsBytes = [System.Text.Encoding]::UTF8.GetBytes($Body) - $params.Add("Body", $bodyAsBytes) - Write-Log -Message "Request includes a body." -Level Verbose - if (Get-GitHubConfiguration -Name LogRequestBody) + Write-Log -Message $Description -Level Verbose + Write-Log -Message "Accessing [$Method] $url [Timeout = $(Get-GitHubConfiguration -Name WebRequestTimeoutSec))]" -Level Verbose + + $result = $null + $params = @{} + $params.Add("Uri", $url) + $params.Add("Method", $Method) + $params.Add("Headers", $headers) + $params.Add("UseDefaultCredentials", $true) + $params.Add("UseBasicParsing", $true) + $params.Add("TimeoutSec", (Get-GitHubConfiguration -Name WebRequestTimeoutSec)) + if ($PSBoundParameters.ContainsKey('InFile')) { $params.Add('InFile', $InFile) } + if (-not [String]::IsNullOrWhiteSpace($outFile)) { $params.Add('OutFile', $outFile) } + + if (($Method -in $ValidBodyContainingRequestMethods) -and (-not [String]::IsNullOrEmpty($Body))) { - Write-Log -Message $Body -Level Verbose + $bodyAsBytes = [System.Text.Encoding]::UTF8.GetBytes($Body) + $params.Add("Body", $bodyAsBytes) + Write-Log -Message "Request includes a body." -Level Verbose + if (Get-GitHubConfiguration -Name LogRequestBody) + { + Write-Log -Message $Body -Level Verbose + } } - } - # Disable Progress Bar in function scope during Invoke-WebRequest - $ProgressPreference = 'SilentlyContinue' + # Disable Progress Bar in function scope during Invoke-WebRequest + $ProgressPreference = 'SilentlyContinue' - [Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12 + [Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12 - $result = Invoke-WebRequest @params + $result = Invoke-WebRequest @params - if ($Method -eq 'Delete') - { - Write-Log -Message "Successfully removed." -Level Verbose - } + if ($Method -eq 'Delete') + { + Write-Log -Message "Successfully removed." -Level Verbose + } - # Record the telemetry for this event. - $stopwatch.Stop() - if (-not [String]::IsNullOrEmpty($TelemetryEventName)) - { - $telemetryMetrics = @{ 'Duration' = $stopwatch.Elapsed.TotalSeconds } - Set-TelemetryEvent -EventName $TelemetryEventName -Properties $localTelemetryProperties -Metrics $telemetryMetrics - } + # Record the telemetry for this event. + $stopwatch.Stop() + if (-not [String]::IsNullOrEmpty($TelemetryEventName)) + { + $telemetryMetrics = @{ 'Duration' = $stopwatch.Elapsed.TotalSeconds } + Set-TelemetryEvent -EventName $TelemetryEventName -Properties $localTelemetryProperties -Metrics $telemetryMetrics + } - $finalResult = $result.Content - try - { - if ($Save) + $finalResult = $result.Content + try { - $finalResult = Get-Item -Path $outFile + if ($Save) + { + $finalResult = Get-Item -Path $outFile + } + else + { + $finalResult = $finalResult | ConvertFrom-Json + } } - else + catch [InvalidOperationException] { - $finalResult = $finalResult | ConvertFrom-Json + # In some cases, the returned data might have two different keys of the same characters + # but different casing (this can happen with gists with two files named 'a.txt' and 'A.txt'). + # PowerShell 6 introduced the -AsHashtable switch to work around this issue, but this + # module wants to be compatible down to PowerShell 4, so we're unable to use that feature. + Write-Log -Message 'The returned object likely contains keys that differ only in casing. Unable to convert to an object. Returning the raw JSON as a fallback.' -Level Warning + $finalResult = $finalResult + } + catch [ArgumentException] + { + # The content must not be JSON (which is a legitimate situation). + # We'll return the raw content result instead. + # We do this unnecessary assignment to avoid PSScriptAnalyzer's PSAvoidUsingEmptyCatchBlock. + $finalResult = $finalResult } - } - catch [InvalidOperationException] - { - # In some cases, the returned data might have two different keys of the same characters - # but different casing (this can happen with gists with two files named 'a.txt' and 'A.txt'). - # PowerShell 6 introduced the -AsHashtable switch to work around this issue, but this - # module wants to be compatible down to PowerShell 4, so we're unable to use that feature. - Write-Log -Message 'The returned object likely contains keys that differ only in casing. Unable to convert to an object. Returning the raw JSON as a fallback.' -Level Warning - $finalResult = $finalResult - } - catch [ArgumentException] - { - # The content must not be JSON (which is a legitimate situation). - # We'll return the raw content result instead. - # We do this unnecessary assignment to avoid PSScriptAnalyzer's PSAvoidUsingEmptyCatchBlock. - $finalResult = $finalResult - } - if ((-not $Save) -and (-not (Get-GitHubConfiguration -Name DisableSmarterObjects))) - { - # In the case of getting raw content from the repo, we'll end up with a large object/byte - # array which isn't convertible to a smarter object, but by _trying_ we'll end up wasting - # a lot of time. Let's optimize here by not bothering to send in something that we - # know is definitely not convertible ([int32] on PS5, [long] on PS7). - if (($finalResult -isnot [Object[]]) -or - (($finalResult.Count -gt 0) -and - ($finalResult[0] -isnot [int]) -and - ($finalResult[0] -isnot [long]))) + if ((-not $Save) -and (-not (Get-GitHubConfiguration -Name DisableSmarterObjects))) + { + # In the case of getting raw content from the repo, we'll end up with a large object/byte + # array which isn't convertible to a smarter object, but by _trying_ we'll end up wasting + # a lot of time. Let's optimize here by not bothering to send in something that we + # know is definitely not convertible ([int32] on PS5, [long] on PS7). + if (($finalResult -isnot [Object[]]) -or + (($finalResult.Count -gt 0) -and + ($finalResult[0] -isnot [int]) -and + ($finalResult[0] -isnot [long]))) + { + $finalResult = ConvertTo-SmarterObject -InputObject $finalResult + } + } + + if ($result.Headers.Count -gt 0) { - $finalResult = ConvertTo-SmarterObject -InputObject $finalResult + $links = $result.Headers['Link'] -split ',' + $nextLink = $null + $nextPageNumber = 1 + $numPages = 1 + $since = 0 + foreach ($link in $links) + { + if ($link -match '<(.*page=(\d+)[^\d]*)>; rel="next"') + { + $nextLink = $Matches[1] + $nextPageNumber = [int]$Matches[2] + } + elseif ($link -match '<(.*since=(\d+)[^\d]*)>; rel="next"') + { + # Special case scenario for the users endpoint. + $nextLink = $Matches[1] + $since = [int]$Matches[2] + $numPages = 0 # Signifies an unknown number of pages. + } + elseif ($link -match '<.*page=(\d+)[^\d]+rel="last"') + { + $numPages = [int]$Matches[1] + } + } } - } - if ($result.Headers.Count -gt 0) - { - $links = $result.Headers['Link'] -split ',' - $nextLink = $null - $nextPageNumber = 1 - $numPages = 1 - $since = 0 - foreach ($link in $links) + $resultNotReadyStatusCode = 202 + if ($result.StatusCode -eq $resultNotReadyStatusCode) { - if ($link -match '<(.*page=(\d+)[^\d]*)>; rel="next"') + $retryDelaySeconds = Get-GitHubConfiguration -Name RetryDelaySeconds + + if ($Method -ne 'Get') + { + # We only want to do our retry logic for GET requests... + # We don't want to repeat PUT/PATCH/POST/DELETE. + Write-Log -Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)])." -Level Warning + } + elseif ($retryDelaySeconds -le 0) { - $nextLink = $Matches[1] - $nextPageNumber = [int]$Matches[2] + Write-Log -Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)]), however the module is currently configured to not retry in this scenario (RetryDelaySeconds is set to 0). Please try this command again later." -Level Warning } - elseif ($link -match '<(.*since=(\d+)[^\d]*)>; rel="next"') + elseif ($numRetriesAttempted -lt $maxiumRetriesPermitted) { - # Special case scenario for the users endpoint. - $nextLink = $Matches[1] - $since = [int]$Matches[2] - $numPages = 0 # Signifies an unknown number of pages. + $numRetriesAttempted++ + $localTelemetryProperties['RetryAttempt'] = $numRetriesAttempted + Write-Log -Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)]). Will retry in [$retryDelaySeconds] seconds. $($maxiumRetriesPermitted - $numRetriesAttempted) retries remaining." -Level Warning + Start-Sleep -Seconds ($retryDelaySeconds) + continue # loop back and try this again } - elseif ($link -match '<.*page=(\d+)[^\d]+rel="last"') + else { - $numPages = [int]$Matches[1] + $message = "Request still not ready after $numRetriesAttempted retries. Retry limit has been reached as per configuration value 'MaximumRetriesWhenResultNotReady'" + Write-Log -Message $message -Level Error + throw $message } } - } - - $resultNotReadyStatusCode = 202 - if ($result.StatusCode -eq $resultNotReadyStatusCode) - { - $retryDelaySeconds = Get-GitHubConfiguration -Name RetryDelaySeconds - if ($Method -ne 'Get') + # Allow for a delay after a command that may result in a state change in order to + # increase the reliability of the UT's which attempt multiple successive state change + # on the same object. + $stateChangeDelaySeconds = $(Get-GitHubConfiguration -Name 'StateChangeDelaySeconds') + $stateChangeMethods = @('Delete', 'Post', 'Patch', 'Put') + if (($stateChangeDelaySeconds -gt 0) -and ($Method -in $stateChangeMethods)) { - # We only want to do our retry logic for GET requests... - # We don't want to repeat PUT/PATCH/POST/DELETE. - Write-Log -Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)])." -Level Warning + Start-Sleep -Seconds $stateChangeDelaySeconds } - elseif ($retryDelaySeconds -le 0) + + if ($ExtendedResult) { - Write-Log -Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)]), however the module is currently configured to not retry in this scenario (RetryDelaySeconds is set to 0). Please try this command again later." -Level Warning + $finalResultEx = @{ + 'result' = $finalResult + 'statusCode' = $result.StatusCode + 'requestId' = $result.Headers['X-GitHub-Request-Id'] + 'nextLink' = $nextLink + 'nextPageNumber' = $nextPageNumber + 'numPages' = $numPages + 'since' = $since + 'link' = $result.Headers['Link'] + 'lastModified' = $result.Headers['Last-Modified'] + 'ifNoneMatch' = $result.Headers['If-None-Match'] + 'ifModifiedSince' = $result.Headers['If-Modified-Since'] + 'eTag' = $result.Headers['ETag'] + 'rateLimit' = $result.Headers['X-RateLimit-Limit'] + 'rateLimitRemaining' = $result.Headers['X-RateLimit-Remaining'] + 'rateLimitReset' = $result.Headers['X-RateLimit-Reset'] + } + + return ([PSCustomObject] $finalResultEx) } else { - Write-Log -Message "The server has indicated that the result is not yet ready (received status code of [$($result.StatusCode)]). Will retry in [$retryDelaySeconds] seconds." -Level Warning - Start-Sleep -Seconds ($retryDelaySeconds) - return (Invoke-GHRestMethod @PSBoundParameters) + return $finalResult } } - - # Allow for a delay after a command that may result in a state change in order to - #increase the reliability of the UT's which attempt multiple successive state change - # on the same object. - $stateChangeDelaySeconds = $(Get-GitHubConfiguration -Name 'StateChangeDelaySeconds') - $stateChangeMethods = @('Delete', 'Post', 'Patch', 'Put') - if (($stateChangeDelaySeconds -gt 0) -and ($Method -in $stateChangeMethods)) - { - Start-Sleep -Seconds $stateChangeDelaySeconds - } - - if ($ExtendedResult) - { - $finalResultEx = @{ - 'result' = $finalResult - 'statusCode' = $result.StatusCode - 'requestId' = $result.Headers['X-GitHub-Request-Id'] - 'nextLink' = $nextLink - 'nextPageNumber' = $nextPageNumber - 'numPages' = $numPages - 'since' = $since - 'link' = $result.Headers['Link'] - 'lastModified' = $result.Headers['Last-Modified'] - 'ifNoneMatch' = $result.Headers['If-None-Match'] - 'ifModifiedSince' = $result.Headers['If-Modified-Since'] - 'eTag' = $result.Headers['ETag'] - 'rateLimit' = $result.Headers['X-RateLimit-Limit'] - 'rateLimitRemaining' = $result.Headers['X-RateLimit-Remaining'] - 'rateLimitReset' = $result.Headers['X-RateLimit-Reset'] - } - - return ([PSCustomObject] $finalResultEx) - } - else - { - return $finalResult - } } catch { diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 2f9a06e8..40743ec7 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -1035,34 +1035,38 @@ try } } - Context 'When getting Github Repository Contributors with Statistics' { - BeforeAll { - $getGitHubRepositoryContributorParms = @{ - OwnerName = $repo.owner.login - RepositoryName = $repoName - IncludeStatistics = $true - } - - $contributors = @(Get-GitHubRepositoryContributor @getGitHubRepositoryContributorParms) - } - - It 'Should return objects of the correct type' { - $contributors[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryContributorStatistics' - $contributors[0].author.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } - - It 'Should return expected number of contributors' { - $contributors.Count | Should -Be 1 - } - - It 'Should return the correct membership' { - $repo.owner.login | Should -BeIn $contributors.author.login - } - - It 'Should return the correct properties' { - $contributors.weeks | Should -Not -BeNullOrEmpty - } - } + # TODO: This test has been disabled because GitHub isn't returning back a result after over + # one hour of retries. See here for more info: + # https://github.community/t/unable-to-retrieve-contributor-statistics-for-a-brand-new-repo/136658 + # + # Context 'When getting Github Repository Contributors with Statistics' { + # BeforeAll { + # $getGitHubRepositoryContributorParms = @{ + # OwnerName = $repo.owner.login + # RepositoryName = $repoName + # IncludeStatistics = $true + # } + + # $contributors = @(Get-GitHubRepositoryContributor @getGitHubRepositoryContributorParms) + # } + + # It 'Should return objects of the correct type' { + # $contributors[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryContributorStatistics' + # $contributors[0].author.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + # } + + # It 'Should return expected number of contributors' { + # $contributors.Count | Should -Be 1 + # } + + # It 'Should return the correct membership' { + # $repo.owner.login | Should -BeIn $contributors.author.login + # } + + # It 'Should return the correct properties' { + # $contributors.weeks | Should -Not -BeNullOrEmpty + # } + # } Context 'When getting Github Repository Contributors including Anonymous' { BeforeAll { From ec7950c02c1e52af2a6edc30331982d172f6e7ff Mon Sep 17 00:00:00 2001 From: John Date: Fri, 16 Oct 2020 23:59:10 +0200 Subject: [PATCH 12/51] Fixed the AuthorName/AuthorEmail variable check for Set-GitHubContent (#295) Fixed the variable check for Set-GitHubContent. Resolves #285. --- GitHubContents.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GitHubContents.ps1 b/GitHubContents.ps1 index 7d1bcd40..d77c21aa 100644 --- a/GitHubContents.ps1 +++ b/GitHubContents.ps1 @@ -392,8 +392,8 @@ filter Set-GitHubContent if ($PSBoundParameters.ContainsKey('AuthorName') -or $PSBoundParameters.ContainsKey('AuthorEmail')) { - if (![System.String]::IsNullOrEmpty($CommitterName) -and - ![System.String]::IsNullOrEmpty($CommitterEmail)) + if (![System.String]::IsNullOrEmpty($AuthorName) -and + ![System.String]::IsNullOrEmpty($AuthorEmail)) { $hashBody['author'] = @{ name = $AuthorName From 28e20d4a2a8079ff27bdaf3abdd7cf7e397869d5 Mon Sep 17 00:00:00 2001 From: Ted Hudek Date: Fri, 23 Oct 2020 12:10:37 -0700 Subject: [PATCH 13/51] Fix typo in example in USAGE.md (#297) Changes an opening brace to parenthesis because `Add-GitHubIssueLabel` takes an array of label strings. --- USAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/USAGE.md b/USAGE.md index 6117b1e9..e0b99e1c 100644 --- a/USAGE.md +++ b/USAGE.md @@ -457,7 +457,7 @@ Remove-GitHubLabel -OwnerName PowerShell -RepositoryName DesiredStateConfigurati #### Adding Labels to an Issue ```powershell -$labelNames = @{'bug', 'discussion') +$labelNames = @('bug', 'discussion') Add-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue 1 -LabelName $labelNames ``` From 28c433682525c3a6923fef77e7782f67244562a5 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Tue, 27 Oct 2020 15:08:09 -0700 Subject: [PATCH 14/51] Add reference to Wiki in USAGE.md (#298) Add a reference to the documentation in the Wiki to the top of USAGE.md. --- USAGE.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/USAGE.md b/USAGE.md index e0b99e1c..a71dd275 100644 --- a/USAGE.md +++ b/USAGE.md @@ -2,6 +2,7 @@ ## Usage #### Table of Contents +* [Full Module Documentation](#full-module-documentation) * [Logging](#logging) * [Telemetry](#telemetry) * [Common PowerShell API Patterns](#common-powershell-api-patterns) @@ -130,6 +131,20 @@ ---------- +## Full Module Documentation + +All commands for the module have "Comment-Based Help" available at your fingertips. +You can access that help at any time by running: + +```powershell +Get-Help -Full +``` + +In addition to accessing it from the commandline, all of that help documentation is also available +online on our [wiki](https://github.com/microsoft/PowerShellForGitHub/wiki). + +---------- + ## Logging All commands will log to the console, as well as to a log file, by default. From 8a29c7faa8c7220e3cad61b00716502e41c08d75 Mon Sep 17 00:00:00 2001 From: Jonathan Moss Date: Mon, 2 Nov 2020 22:31:57 -0500 Subject: [PATCH 15/51] Fix markdown for example in USAGE.md (#299) --- USAGE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/USAGE.md b/USAGE.md index a71dd275..60b2aef5 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1016,7 +1016,8 @@ Remove-GitHubReleaseAsset -OwnerName PowerShell -RepositoryName PowerShell -Asse or with pipelining... ```powershell -$asset | Remove-GitHubReleaseAsset -force +$asset | Remove-GitHubReleaseAsset -Force +``` ---------- @@ -1202,4 +1203,3 @@ $issue | New-GitHubIssueComment -Body $CommentBody # Close issue $issue | Set-GitHubIssue -State Closed ``` - From d4997057f8b1234ea1aabeb4fb6742148d3afaaf Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Sun, 6 Dec 2020 16:25:44 +0000 Subject: [PATCH 16/51] GitHubRepositories: Add Get/Set GitHub Repository Actions Permissions (#301) Adds the following functions to the `GitHubRepositories` module: - `Get-GitHubRepositoryActionsPermission` - `Set-GitHubRepositoryActionsPermission` #### References - [Get GitHub Actions permissions for a repository](https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#get-github-actions-permissions-for-a-repository) - [Set GitHub Actions permissions for a repository](https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#set-github-actions-permissions-for-a-repository) --- Formatters/GitHubRepositories.Format.ps1xml | 27 ++ GitHubRepositories.ps1 | 328 ++++++++++++++++++++ PowerShellForGitHub.psd1 | 2 + README.md | 1 + Tests/GitHubRepositories.tests.ps1 | 109 +++++++ USAGE.md | 14 + 6 files changed, 481 insertions(+) diff --git a/Formatters/GitHubRepositories.Format.ps1xml b/Formatters/GitHubRepositories.Format.ps1xml index 5325fd19..d128df0f 100644 --- a/Formatters/GitHubRepositories.Format.ps1xml +++ b/Formatters/GitHubRepositories.Format.ps1xml @@ -177,5 +177,32 @@ + + + GitHub.RepositoryActionsPermission + + GitHub.RepositoryActionsPermission + + + + + + + RepositoryName + + + RepositoryUrl + + + Enabled + + + AllowedActions + + + + + + diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index 9e56a2f5..c7a94513 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -2,6 +2,7 @@ # Licensed under the MIT License. @{ + GitHubRepositoryActionsPermissionTypeName = 'GitHub.RepositoryActionsPermission' GitHubRepositoryTypeName = 'GitHub.Repository' GitHubRepositoryTopicTypeName = 'GitHub.RepositoryTopic' GitHubRepositoryContributorTypeName = 'GitHub.RepositoryContributor' @@ -2692,6 +2693,257 @@ filter Disable-GitHubRepositorySecurityFix Invoke-GHRestMethod @params | Out-Null } +filter Get-GitHubRepositoryActionsPermission +{ + <# + .SYNOPSIS + Gets GitHub Actions permission for a repository on GitHub. + + .DESCRIPTION + Gets GitHub Actions permission for a repository on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.Repository + + .OUTPUTS + GitHub.RepositoryActionsPermission + + .NOTES + The authenticated user must have admin access to the repository. + + .EXAMPLE + Get-GitHubRepositoryActionsPermission -OwnerName Microsoft -RepositoryName PowerShellForGitHub + + Gets GitHub Actions permissions for the PowerShellForGithub repository. + + .EXAMPLE + Get-GitHubRepositoryActionsPermission -Uri https://github.com/PowerShell/PowerShellForGitHub + + Gets GitHub Actions permissions for the PowerShellForGithub repository. +#> + [CmdletBinding( + PositionalBinding = $false, + DefaultParameterSetName='Elements')] + param( + [Parameter( + ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + Position = 1, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $params = @{ + UriFragment = "/repos/$OwnerName/$RepositoryName/actions/permissions" + Description = "Getting GitHub Actions permissions for $RepositoryName" + Method = 'Get' + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + return (Invoke-GHRestMethod @params | + Add-GitHubRepositoryActionsPermissionAdditionalProperties -RepositoryName $RepositoryName -OwnerName $OwnerName) +} + +filter Set-GitHubRepositoryActionsPermission +{ + <# + .SYNOPSIS + Sets GitHub Actions permissions for a repository on GitHub. + + .DESCRIPTION + Sets GitHub Actions permissions for a repository on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER AllowedActions + The permissions policy that controls the actions that are allowed to run. + Can be one of: 'All', 'LocalOnly', 'Selected' or 'Disabled'. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.Repository + + .OUTPUTS + None + + .NOTES + The authenticated user must have admin access to the repository. + + If the repository belongs to an organization or enterprise that has set restrictive + permissions at the organization or enterprise levels, such as 'AllowedActions' to 'Selected' + actions, then you cannot override them for the repository. + + .EXAMPLE + Set-GitHubRepositoryActionsPermission -OwnerName Microsoft -RepositoryName PowerShellForGitHub -AllowedActions All + + Sets GitHub Actions permissions to 'All' for the PowerShellForGithub repository. + + .EXAMPLE + Set-GitHubRepositoryActionsPermission -Uri https://github.com/PowerShell/PowerShellForGitHub -AllowedActions Disabled + + Sets GitHub Actions permissions to 'Disabled' for the PowerShellForGithub repository. +#> + [CmdletBinding( + PositionalBinding = $false, + SupportsShouldProcess, + DefaultParameterSetName='Elements')] + param( + [Parameter( + ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + Position = 1, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter(Mandatory)] + [ValidateSet('All', 'LocalOnly', 'Selected', 'Disabled')] + [string] $AllowedActions, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $allowedActionsConverter = @{ + All = 'all' + LocalOnly = 'local_only' + Selected = 'selected' + Disabled = 'disabled' + } + + $hashBodyAllowedActions = $allowedActionsConverter[$AllowedActions] + + if ($AllowedActions -eq 'Disabled') + { + $hashBody = @{ + 'enabled' = $false + } + } + else + { + $hashBody = @{ + 'enabled' = $true + 'allowed_actions' = $hashBodyAllowedActions + } + } + + if (-not $PSCmdlet.ShouldProcess($RepositoryName, 'Set GitHub Repository Actions Permissions')) + { + return + } + + $params = @{ + UriFragment = "/repos/$OwnerName/$RepositoryName/actions/permissions" + Description = "Setting GitHub Actions permissions for $RepositoryName" + Method = 'Put' + Body = (ConvertTo-Json -InputObject $hashBody) + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + Invoke-GHRestMethod @params | Out-Null +} + filter Add-GitHubRepositoryAdditionalProperties { <# @@ -2967,3 +3219,79 @@ filter Add-GitHubRepositoryCollaboratorAdditionalProperties Write-Output $item } } + +filter Add-GitHubRepositoryActionsPermissionAdditionalProperties +{ + <# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Repository Actions Permissions objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .PARAMETER OwnerName + Owner of the repository. This information might be obtainable from InputObject, so this + is optional based on what InputObject contains. + + .PARAMETER RepositoryName + Name of the repository. This information might be obtainable from InputObject, so this + is optional based on what InputObject contains. + + .INPUTS + PSCustomObject + + .OUTPUTS + GitHub.RepositoryActionsPermission +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', + Justification='Internal helper that is definitely adding more than one property.')] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubRepositoryActionsPermissionTypeName, + + [Parameter(Mandatory)] + [string] $OwnerName, + + [Parameter(Mandatory)] + [string] $RepositoryName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + $repositoryUrl = (Join-GitHubUri -OwnerName $OwnerName -RepositoryName $RepositoryName) + + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'RepositoryName' -Value $RepositoryName -MemberType NoteProperty -Force + + $allowedActionsConverter = @{ + all = 'All' + local_only = 'LocalOnly' + selected = 'Selected' + } + + if ([String]::IsNullOrEmpty($item.allowed_actions)) + { + $allowedActions = 'Disabled' + } + else + { + $allowedActions = $allowedActionsConverter[$item.allowed_actions] + } + + Add-Member -InputObject $item -Name 'AllowedActions' -Value $allowedActions -MemberType NoteProperty -Force + + Write-Output $item + } +} diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 680a9dea..f72f0ab4 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -101,6 +101,7 @@ 'Get-GitHubRelease', 'Get-GitHubReleaseAsset', 'Get-GitHubRepository', + 'Get-GitHubRepositoryActionsPermission', 'Get-GitHubRepositoryBranch', 'Get-GitHubRepositoryBranchProtectionRule', 'Get-GitHubRepositoryCollaborator', @@ -188,6 +189,7 @@ 'Set-GitHubRelease', 'Set-GitHubReleaseAsset', 'Set-GitHubRepository', + 'Set-GitHubRepositoryActionsPermission', 'Set-GitHubRepositoryTopic', 'Set-GitHubTeam', 'Split-GitHubUri', diff --git a/README.md b/README.md index 88b36463..765a426c 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ At present, this module can: * Query the languages and tags in a repository, and and query/update its topics. * Change repository ownership. * Query, enable and disable security and vulnerability alerts. + * Query and set GitHub Actions permission. * Query various [traffic reports](https://developer.github.com/v3/repos/traffic/) including referral sources and paths, page views and clones. * Query, create, edit, lock/unlock [Issues](https://developer.github.com/v3/issues/) and diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 40743ec7..1ad817f6 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -1379,6 +1379,115 @@ try Remove-GitHubRepository -Uri $repo.svn_url -Force } } + + Describe 'GitHubRepositories\Get-GitHubRepositoryActionsPermission' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repoName + + $allowedActions = 'All', 'LocalOnly', 'Selected', 'Disabled' + } + + foreach ($allowedAction in $allowedActions) + { + Context "When the AllowedAction is $allowedAction" { + BeforeAll { + $setGitHubRepositoryActionsPermissionParms = @{ + Uri = $repo.svn_url + AllowedActions = $allowedAction + } + + Set-GitHubRepositoryActionsPermission @setGitHubRepositoryActionsPermissionParms + + $permissions = Get-GitHubRepositoryActionsPermission -Uri $repo.svn_url + } + + It 'Should return the correct type and properties' { + $permissions.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryActionsPermission' + + $permissions.RepositoryName | Should -Be $repoName + $permissions.RepositoryUrl | Should -Be $repo.svn_url + + if ($allowedAction -eq 'Disabled') + { + $permissions.Enabled | Should -BeFalse + } + else + { + $permissions.Enabled | Should -BeTrue + $permissions.AllowedActions | Should -Be $allowedAction + } + } + } + } + + Context "When specifiying the 'URI' Parameter from the Pipeline" { + BeforeAll { + $permissions = $repo | Get-GitHubRepositoryActionsPermission + } + + It 'Should return an object of the correct type' { + $permissions.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryActionsPermission' + } + } + + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } + } + + Describe 'GitHubRepositories\Set-GitHubRepositoryActionsPermission' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + + $allowedActions = 'All', 'LocalOnly', 'Selected', 'Disabled' + } + + foreach ($allowedAction in $allowedActions) + { + Context "When the AllowedAction Parameter is $allowedAction" { + BeforeAll { + $setGitHubRepositoryActionsPermissionParms = @{ + Uri = $repo.svn_url + AllowedActions = $allowedAction + } + + Set-GitHubRepositoryActionsPermission @setGitHubRepositoryActionsPermissionParms + } + + It 'Should have set the expected permissions' { + $permissions = Get-GitHubRepositoryActionsPermission -Uri $repo.svn_url + + if ($allowedAction -eq 'Disabled') + { + $permissions.Enabled | Should -BeFalse + } + else + { + $permissions.Enabled | Should -BeTrue + $permissions.AllowedActions | Should -Be $allowedAction + } + } + } + } + + Context "When specifiying the 'URI' Parameter from the Pipeline" { + It 'Should not throw' { + { $repo | Set-GitHubRepositoryActionsPermission -AllowedActions 'All' } | + Should -Not -Throw + } + } + + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } + } } finally { diff --git a/USAGE.md b/USAGE.md index 60b2aef5..58843423 100644 --- a/USAGE.md +++ b/USAGE.md @@ -53,6 +53,8 @@ * [Disable repository vulnerability alerts](#disable-repository-vulnerability-alerts) * [Enable repository automatic security fixes](#enable-repository-automatic-security-fixes) * [Disable repository automatic security fixes](#disable-repository-automatic-security-fixes) + * [Get repository GitHub Actions permissions](#get-repository-github-actions-permissions) + * [Set repository GitHub Actions permissions](#set-repository-github-actions-permissions) * [Branches](#branches) * [Adding a new Branch to a Repository](#adding-a-new-branch-to-a-repository) * [Removing a Branch from a Repository](#removing-a-branch-from-a-repository) @@ -646,6 +648,18 @@ Enable-GitHubRepositorySecurityFix -OwnerName microsoft -RepositoryName PowerShe Disable-GitHubRepositorySecurityFix -OwnerName microsoft -RepositoryName PowerShellForGitHub ``` +#### Get repository GitHub Actions permissions + +```powershell +Get-GitHubRepositoryActionsPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub +``` + +#### Set repository GitHub Actions permissions + +```powershell +Set-GitHubRepositoryActionsPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub -AllowedActions All +``` + ---------- ### Branches From 8fd42010209edaf10936751b8eb190655a2bdb38 Mon Sep 17 00:00:00 2001 From: Pepe Rivera Date: Mon, 21 Dec 2020 16:42:51 -0800 Subject: [PATCH 17/51] Fix labels in events being treated as full label objects (#306) `Get-GitHubEvent` is currently broken if the issue contains and event that includes the "label" or "labels" property. This is because `Add-GitHubEventAdditionalProperties` treats the labels in the event object as full fledged label objects that normally contain a URL property and other additional pieces of data. The label property in a `GitHub.Event` is a lighter-weight object that simply contains the string for the label and color that was changed, it is not the full object that you would typically receive from a call like `Get-GithubLabel`. Updated to add a new `GitHub.LabelSummary` type to describe this scenario, as well as passing in the needed `RepositoryUrl` when adding the additional label properties. --- GitHubEvents.ps1 | 5 +++-- GitHubLabels.ps1 | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/GitHubEvents.ps1 b/GitHubEvents.ps1 index f231a4ff..404838b0 100644 --- a/GitHubEvents.ps1 +++ b/GitHubEvents.ps1 @@ -3,6 +3,7 @@ @{ GitHubEventTypeName = 'GitHub.Event' + GitHubLabelSummaryTypeName = 'GitHub.LabelSummary' }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } @@ -237,12 +238,12 @@ filter Add-GitHubEventAdditionalProperties if ($null -ne $item.label) { - $null = Add-GitHubLabelAdditionalProperties -InputObject $item.label + $null = Add-GitHubLabelAdditionalProperties -InputObject $item.label -TypeName $script:GitHubLabelSummaryTypeName -RepositoryUrl $repositoryUrl } if ($null -ne $item.labels) { - $null = Add-GitHubLabelAdditionalProperties -InputObject $item.labels + $null = Add-GitHubLabelAdditionalProperties -InputObject $item.labels -TypeName $script:GitHubLabelSummaryTypeName -RepositoryUrl $repositoryUrl } if ($null -ne $item.milestone) diff --git a/GitHubLabels.ps1 b/GitHubLabels.ps1 index 7bb641a5..6d076d7d 100644 --- a/GitHubLabels.ps1 +++ b/GitHubLabels.ps1 @@ -1327,6 +1327,10 @@ filter Add-GitHubLabelAdditionalProperties .PARAMETER InputObject The GitHub object to add additional properties to. + .PARAMETER RepositoryUrl + Optionally supplied if the Label object doesn't have this value already + (as is the case for GitHub.LabelSummary). + .PARAMETER TypeName The type that should be assigned to the object. @@ -1346,6 +1350,8 @@ filter Add-GitHubLabelAdditionalProperties [AllowEmptyCollection()] [PSCustomObject[]] $InputObject, + [string] $RepositoryUrl, + [ValidateNotNullOrEmpty()] [string] $TypeName = $script:GitHubLabelTypeName ) @@ -1356,9 +1362,13 @@ filter Add-GitHubLabelAdditionalProperties if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) { - $elements = Split-GitHubUri -Uri $item.url - $repositoryUrl = Join-GitHubUri @elements - Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + if (-not [System.String]::IsNullOrEmpty($item.url)) + { + $elements = Split-GitHubUri -Uri $item.url + $RepositoryUrl = Join-GitHubUri @elements + } + + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $RepositoryUrl -MemberType NoteProperty -Force if ($null -ne $item.id) { From 22e3d7bdf6c3b33fdead74dac831e0bb43beb2c4 Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Thu, 24 Dec 2020 20:54:03 +0000 Subject: [PATCH 18/51] GitHubRepositories: Add Get/Set/Remove GitHub Repository Team Permissions (#300) Adds the following functions: * `Get-GitHubRepositoryTeamPermission` * `Set-GitHubRepositoryTeamPermission` * `Remove-GitHubRepositoryTeamPermission` References * [Check team permissions for a repository](https://docs.github.com/en/free-pro-team@latest/rest/reference/teams#check-team-permissions-for-a-repository) * [Add or update team repository permissions](https://docs.github.com/en/free-pro-team@latest/rest/reference/teams#add-or-update-team-repository-permissions) * [Remove a repository from a team](https://docs.github.com/en/free-pro-team@latest/rest/reference/teams#remove-a-repository-from-a-team) Resolves #307 --- Formatters/GitHubRepositories.Format.ps1xml | 24 + GitHubCore.ps1 | 1 + GitHubRepositories.ps1 | 652 ++++++++++++++++++++ PowerShellForGitHub.psd1 | 4 + README.md | 1 + Tests/GitHubRepositories.tests.ps1 | 438 +++++++++++++ USAGE.md | 21 + 7 files changed, 1141 insertions(+) diff --git a/Formatters/GitHubRepositories.Format.ps1xml b/Formatters/GitHubRepositories.Format.ps1xml index d128df0f..c158c2c9 100644 --- a/Formatters/GitHubRepositories.Format.ps1xml +++ b/Formatters/GitHubRepositories.Format.ps1xml @@ -204,5 +204,29 @@ + + + GitHub.RepositoryTeamPermission + + GitHub.RepositoryTeamPermission + + + + + + + RepositoryName + + + TeamName + + + Permission + + + + + + diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index 1e1cd8f7..3f37c402 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -15,6 +15,7 @@ mercyAcceptHeader = 'application/vnd.github.mercy-preview+json' mockingbirdAcceptHeader = 'application/vnd.github.mockingbird-preview' nebulaAcceptHeader = 'application/vnd.github.nebula-preview+json' + repositoryAcceptHeader = 'application/vnd.github.v3.repository+json' sailorVAcceptHeader = 'application/vnd.github.sailor-v-preview+json' scarletWitchAcceptHeader = 'application/vnd.github.scarlet-witch-preview+json' squirrelGirlAcceptHeader = 'application/vnd.github.squirrel-girl-preview' diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index c7a94513..40215d26 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -10,6 +10,7 @@ GitHubRepositoryContributorStatisticsTypeName = 'GitHub.RepositoryContributorStatistics' GitHubRepositoryLanguageTypeName = 'GitHub.RepositoryLanguage' GitHubRepositoryTagTypeName = 'GitHub.RepositoryTag' + GitHubRepositoryTeamPermissionTypeName = 'GitHub.RepositoryTeamPermission' }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } @@ -2944,6 +2945,527 @@ filter Set-GitHubRepositoryActionsPermission Invoke-GHRestMethod @params | Out-Null } +filter Get-GitHubRepositoryTeamPermission +{ +<# + .SYNOPSIS + Retrieve team permissions for a repository on GitHub. + + .DESCRIPTION + Retrieve team permissions for a repository on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER TeamName + The name of the team. + Note: This will be slower than querying by TeamSlug since it requires retrieving + all teams first. + + .PARAMETER TeamSlug + The slug (a unique key based on the team name) of the team. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.Organization + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + GitHub.Team + + .OUTPUTS + GitHub.RepositoryTeamPermission + + .EXAMPLE + Get-GitHubRepositoryTeamPermission -Uri https://github.com/microsoft/PowerShellForGitHub -TeamName Devs + + Gets permission for the Devs team on the microsoft/PowerShellForGitHub repository. + + .EXAMPLE + Get-GitHubRepositoryTeamPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub -TeamName Admins + + Gets permission for the Admin team on the microsoft/PowerShellForGitHub repository. +#> + [CmdletBinding(DefaultParameterSetName = 'TeamNameElements')] + [OutputType( + { $script:GitHubRepositoryTeamTypeName })] + param + ( + [Parameter(ParameterSetName = 'TeamNameElements')] + [Parameter(ParameterSetName = 'TeamSlugElements')] + [string] $OwnerName, + + [Parameter(ParameterSetName = 'TeamNameElements')] + [Parameter(ParameterSetName = 'TeamSlugElements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamNameUri')] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugUri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ParameterSetName = 'TeamNameElements')] + [Parameter( + Mandatory, + ParameterSetName = 'TeamNameUri')] + [ValidateNotNullOrEmpty()] + [string] $TeamName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugElements')] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugUri')] + [ValidateNotNullOrEmpty()] + [string] $TeamSlug, + + [string] $AccessToken + ) + + Write-InvocationLog + + $telemetryProperties = @{} + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + if ($PSBoundParameters.ContainsKey('TeamName')) + { + $team = Get-GitHubTeam -OrganizationName $OwnerName | + Where-Object -Property name -eq $TeamName + + if ($null -eq $team) + { + $message = "Team '$TeamName' not found" + Write-Log -Message $message -Level Error + throw $message + } + else + { + $TeamSlug = $team.slug + } + } + + $telemetryProperties['TeamSlug'] = Get-PiiSafeString -PlainText $TeamSlug + + $uriFragment = "/orgs/$OwnerName/teams/$TeamSlug/repos/$OwnerName/$RepositoryName" + $description = "Getting team $TeamSlug permissions for repository $RepositoryName" + + $params = @{ + UriFragment = $uriFragment + Description = $description + AcceptHeader = $script:repositoryAcceptHeader + Method = 'Get' + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + $result = Invoke-GHRestMethod @params + + if ($PSBoundParameters.ContainsKey('TeamSlug')) + { + $team = Get-GitHubTeam -OrganizationName $OwnerName -TeamSlug $TeamSlug + + $TeamName = $team.name + } + + return ($result | + Add-GitHubRepositoryTeamPermissionAdditionalProperties -TeamName $TeamName -TeamSlug $TeamSlug) +} + +filter Set-GitHubRepositoryTeamPermission +{ +<# + .SYNOPSIS + Sets team permission for a repository on GitHub. + + .DESCRIPTION + Sets team permission for a repository on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER TeamName + The name of the specific team to retrieve. + Note: This will be slower than querying by TeamSlug since it requires retrieving + all teams first. + + .PARAMETER TeamSlug + The slug (a unique key based on the team name) of the specific team to retrieve. + + .PARAMETER Permission + The permission to grant the team on this repository. + Can be one of: + * Pull - team members can pull, but not push to or administer this repository. + * Push - team members can pull and push, but not administer this repository. + * Admin - team members can pull, push and administer this repository. + * Maintain - team members can manage the repository without access to sensitive or + destructive actions. Recommended for project managers. Only applies to repositories owned + by organizations. + * Triage - team members can proactively manage issues and pull requests without write access. + Recommended for contributors who triage a repository. Only applies to repositories owned + by organizations. + If no permission is specified, the team's permission attribute will be used to determine + what permission to grant the team on this repository. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.Organization + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + GitHub.Team + + .EXAMPLE + Set-GitHubRepositoryTeamPermission -Uri https://github.com/microsoft/PowerShellForGitHub -TeamName Devs -Permission Push + + Sets the Push permission for the Devs team on the microsoft/PowerShellForGitHub repository. + + .EXAMPLE + Set-GitHubRepositoryTeamPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub -TeamName Admins -Permission Admin + + Sets the Admin permission for the Admin team on the microsoft/PowerShellForGitHub repository. +#> + [CmdletBinding( + SupportsShouldProcess, + DefaultParameterSetName = 'TeamNameElements')] + param( + [Parameter(ParameterSetName = 'TeamNameElements')] + [Parameter(ParameterSetName = 'TeamSlugElements')] + [string] $OwnerName, + + [Parameter(ParameterSetName = 'TeamNameElements')] + [Parameter(ParameterSetName = 'TeamSlugElements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamNameUri')] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugUri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ParameterSetName = 'TeamNameElements')] + [Parameter( + Mandatory, + ParameterSetName = 'TeamNameUri')] + [ValidateNotNullOrEmpty()] + [string] $TeamName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugElements')] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugUri')] + [ValidateNotNullOrEmpty()] + [string] $TeamSlug, + + [Parameter()] + [ValidateSet('Pull', 'Push', 'Admin', 'Maintain', 'Triage')] + [string]$Permission, + + [string] $AccessToken + ) + + Write-InvocationLog + + $telemetryProperties = @{} + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + if ($PSBoundParameters.ContainsKey('TeamName')) + { + $team = Get-GitHubTeam -OrganizationName $OwnerName | + Where-Object -Property name -eq $TeamName + + if ($null -eq $team) + { + $message = "Team '$TeamName' not found" + Write-Log -Message $message -Level Error + throw $message + } + else + { + $TeamSlug = $team.slug + } + } + + $telemetryProperties['TeamSlug'] = Get-PiiSafeString -PlainText $TeamSlug + + $hashBody = @{} + if ($PSBoundParameters.ContainsKey('Permission')) + { + $hashBody = @{ + permission = $Permission.ToLower() + } + } + + if (-not $PSCmdlet.ShouldProcess( + $RepositoryName, "Set GitHub $Permission Repository Permissions for Team $TeamSlug")) + { + return + } + + $params = @{ + UriFragment = "/orgs/$OwnerName/teams/$TeamSlug/repos/$OwnerName/$RepositoryName" + Description = "Setting team $TeamSlug $Permission permissions for repository $RepositoryName" + Body = (ConvertTo-Json -InputObject $hashBody) + Method = 'Put' + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + Invoke-GHRestMethod @params | Out-Null +} + +filter Remove-GitHubRepositoryTeamPermission +{ +<# + .SYNOPSIS + Removes team permission for a repository on GitHub. + + .DESCRIPTION + Removes team permission for a repository on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER TeamName + The name of the specific team to remove. + Note: This will be slower than querying by TeamSlug since it requires retrieving + all teams first. + + .PARAMETER TeamSlug + The slug (a unique key based on the team name) of the specific team to remove. + + .PARAMETER Force + If this switch is specified, you will not be prompted for confirmation of command execution. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.Organization + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + GitHub.Team + + .EXAMPLE + Remove-GitHubRepositoryTeamPermission -Uri https://github.com/microsoft/PowerShellForGitHub -TeamName Devs + + Removes the permission for the Devs team on the microsoft/PowerShellForGitHub repository. + + .EXAMPLE + Remove-GitHubRepositoryTeamPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub -TeamName Admins + + Removes the permission for the Admin team on the microsoft/PowerShellForGitHub repository. + +#> +[CmdletBinding( + SupportsShouldProcess, + DefaultParameterSetName = 'TeamNameElements', + ConfirmImpact='High')] + [Alias('Delete-GitHubRepositoryTeamPermission')] + param( + [Parameter(ParameterSetName = 'TeamNameElements')] + [Parameter(ParameterSetName = 'TeamSlugElements')] + [string] $OwnerName, + + [Parameter(ParameterSetName = 'TeamNameElements')] + [Parameter(ParameterSetName = 'TeamSlugElements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamNameUri')] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugUri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ParameterSetName = 'TeamNameElements')] + [Parameter( + Mandatory, + ParameterSetName = 'TeamNameUri')] + [ValidateNotNullOrEmpty()] + [string] $TeamName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugElements')] + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'TeamSlugUri')] + [ValidateNotNullOrEmpty()] + [string] $TeamSlug, + + [switch] $Force, + + [string] $AccessToken + ) + + Write-InvocationLog + + $telemetryProperties = @{} + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + if ($PSBoundParameters.ContainsKey('TeamName')) + { + $team = Get-GitHubTeam -OrganizationName $OwnerName | + Where-Object -Property name -eq $TeamName + + if ($null -eq $team) + { + $message = "Team '$TeamName' not found" + Write-Log -Message $message -Level Error + throw $message + } + else + { + $TeamSlug = $team.slug + } + } + + $telemetryProperties['TeamSlug'] = Get-PiiSafeString -PlainText $TeamSlug + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + if (-not $PSCmdlet.ShouldProcess( + $RepositoryName, "Remove GitHub Repository Permissions for Team $TeamSlug")) + { + return + } + + $params = @{ + UriFragment = "/orgs/$OwnerName/teams/$TeamSlug/repos/$OwnerName/$RepositoryName" + Description = "Removing team $TeamSlug permissions from repository $RepositoryName" + Method = 'Delete' + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + Invoke-GHRestMethod @params | Out-Null +} + filter Add-GitHubRepositoryAdditionalProperties { <# @@ -3295,3 +3817,133 @@ filter Add-GitHubRepositoryActionsPermissionAdditionalProperties Write-Output $item } } + +filter Add-GitHubRepositoryTeamPermissionAdditionalProperties +{ +<# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Repository Team Permission objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER OwnerName + Owner of the repository. This information might be obtainable from InputObject, so this + is optional based on what InputObject contains. + + .PARAMETER RepositoryName + Name of the repository. This information might be obtainable from InputObject, so this + is optional based on what InputObject contains. + + .PARAMETER TeamName + The name of the team. + + .PARAMETER TeamSlug + The slug (a unique key based on the team name) of the team. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + PSCustomObject + + .OUTPUTS + GitHub.RepositoryTeamPermission +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", + Justification="Internal helper that is definitely adding more than one property.")] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [string] $OwnerName, + + [string] $RepositoryName, + + [Parameter(Mandatory)] + [string] $TeamName, + + [Parameter(Mandatory)] + [string] $TeamSlug, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubRepositoryTeamPermissionTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + $repositoryUrl = [String]::Empty + if ([String]::IsNullOrEmpty($item.html_url)) + { + if ($PSBoundParameters.ContainsKey('OwnerName') -and + $PSBoundParameters.ContainsKey('RepositoryName')) + { + $repositoryUrl = (Join-GitHubUri -OwnerName $OwnerName -RepositoryName $RepositoryName) + } + } + else + { + $elements = Split-GitHubUri -Uri $item.html_url + $repositoryUrl = Join-GitHubUri @elements + } + + if (-not [String]::IsNullOrEmpty($repositoryUrl)) + { + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + } + + if ($item.id -gt 0) + { + Add-Member -InputObject $item -Name 'RepositoryId' -Value $item.id -MemberType NoteProperty -Force + } + + if ($null -ne $item.owner) + { + $null = Add-GitHubUserAdditionalProperties -InputObject $item.owner + } + + if ($null -ne $item.organization) + { + $null = Add-GitHubOrganizationAdditionalProperties -InputObject $item.organization + } + + Add-Member -InputObject $item -Name 'RepositoryName' -Value $item.full_name -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'TeamName' -Value $TeamName -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'TeamSlug' -Value $TeamSlug -MemberType NoteProperty -Force + } + + if ($result.permissions.admin) + { + $permission = 'admin' + } + elseif ($result.permissions.push) + { + $permission = 'push' + } + elseif ($result.permissions.maintain) + { + $permission = 'maintain' + } + elseif ($result.permissions.triage) + { + $permission = 'triage' + } + elseif ($result.permissions.pull) + { + $permission = 'pull' + } + + Add-Member -InputObject $item -Name 'Permission' -Value $permission -MemberType NoteProperty -Force + + Write-Output $item + } +} diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index f72f0ab4..f557729d 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -109,6 +109,7 @@ 'Get-GitHubRepositoryFork', 'Get-GitHubRepositoryLanguage', 'Get-GitHubRepositoryTag', + 'Get-GitHubRepositoryTeamPermission', 'Get-GitHubRepositoryTopic', 'Get-GitHubRepositoryUniqueContributor', 'Get-GitHubTeam', @@ -163,6 +164,7 @@ 'Remove-GitHubRepository', 'Remove-GitHubRepositoryBranch' 'Remove-GitHubRepositoryBranchProtectionRule', + 'Remove-GitHubRepositoryTeamPermission', 'Remove-GitHubTeam', 'Rename-GitHubGistFile', 'Rename-GitHubRepository', @@ -190,6 +192,7 @@ 'Set-GitHubReleaseAsset', 'Set-GitHubRepository', 'Set-GitHubRepositoryActionsPermission', + 'Set-GitHubRepositoryTeamPermission', 'Set-GitHubRepositoryTopic', 'Set-GitHubTeam', 'Split-GitHubUri', @@ -221,6 +224,7 @@ 'Delete-GitHubRepository', 'Delete-GitHubRepositoryBranch', 'Delete-GitHubRepositoryBranchProtectionRule', + 'Delete-GitHubRepositoryTeamPermission', 'Delete-GitHubTeam', 'Fork-GitHubGist', 'Get-GitHubAsset', diff --git a/README.md b/README.md index 765a426c..0d06c3b2 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ At present, this module can: * Change repository ownership. * Query, enable and disable security and vulnerability alerts. * Query and set GitHub Actions permission. + * Query, set and remove team permissions. * Query various [traffic reports](https://developer.github.com/v3/repos/traffic/) including referral sources and paths, page views and clones. * Query, create, edit, lock/unlock [Issues](https://developer.github.com/v3/issues/) and diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 1ad817f6..f63d8f3e 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -1488,6 +1488,444 @@ try } } } + + Describe 'GitHubRepositories\Get-GitHubRepositoryTeamPermission' { + BeforeAll { + $repositoryTeamPermissionTypeName = 'GitHub.RepositoryTeamPermission' + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName + + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName + + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } + + $team = New-GitHubTeam @newGithubTeamParms + + $permissions = 'Push', 'Pull', 'Maintain', 'Triage', 'Admin' + } + + Foreach ($permission in $permissions) { + Context "When the Team Permission is $permission" { + BeforeAll { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = $permission + } + + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + } + + $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + } + + It 'Should have the expected type and additional properties' { + $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName + $repoPermission.RepositoryName | Should -Be $repo.full_name + $repoPermission.RepositoryUrl | Should -Be $repo.svn_url + $repoPermission.RepositoryId | Should -Be $repo.RepositoryId + $repoPermission.TeamName | Should -Be $team.TeamName + $repoPermission.TeamSlug | Should -Be $team.TeamSlug + $repoPermission.Permission | Should -Be $permission + } + } + } + + Context "When specifying the 'TeamName' parameter" { + BeforeAll { + $permission = 'Pull' + + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = $permission + } + + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $teamName + } + + $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + } + + It 'Should have the expected type and additional properties' { + $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName + $repoPermission.RepositoryName | Should -Be $repo.full_name + $repoPermission.RepositoryUrl | Should -Be $repo.svn_url + $repoPermission.RepositoryId | Should -Be $repo.RepositoryId + $repoPermission.TeamName | Should -Be $team.TeamName + $repoPermission.TeamSlug | Should -Be $team.TeamSlug + $repoPermission.Permission | Should -Be $permission + } + + Context 'When the specified TeamName does not exist' { + BeforeAll { + $nonExistingTeamName = [Guid]::NewGuid().Guid + + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $nonExistingTeamName + } + } + + It 'Should throw the correct exception' { + { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | + Should -Throw "Team '$nonExistingTeamName' not found" + } + } + } + + Context "When specifying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $getGitHubRepositoryTeamPermissionParms = @{ + TeamName = $teamName + } + $repoPermission = $repo | + Get-GitHubRepositoryTeamPermission @getGitHubRepositoryTeamPermissionParms + } + + It 'Should have the expected type and additional properties' { + $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName + $repoPermission.RepositoryName | Should -Be $repo.full_name + $repoPermission.TeamName | Should -Be $teamName + } + } + + Context "When specifying the 'TeamSlug' and 'OrganizationName' Parameters from the Pipeline" { + BeforeAll -ScriptBlock { + $getGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + } + $repoPermission = $team | + Get-GitHubRepositoryTeamPermission @getGitHubRepositoryTeamPermissionParms + } + + It 'Should have the expected type and additional properties' { + $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName + $repoPermission.RepositoryName | Should -Be $repo.full_name + $repoPermission.TeamName | Should -Be $teamName + $repoPermission.TeamSlug | Should -Be $team.TeamSlug + } + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } + } + + Describe 'GitHubRepositories\Set-GitHubRepositoryTeamPermission' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName + + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName + + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } + + $team = New-GitHubTeam @newGithubTeamParms + + $permissions = 'Push', 'Pull', 'Maintain', 'Triage', 'Admin' + } + + Foreach ($permission in $permissions) { + Context "When the Team Permission is specified as $permission" { + BeforeAll { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = $permission + } + + } + + It 'Should not throw' { + { Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + + } + + It 'Should have set the correct Team permission' { + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + } + + $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + + $repoPermission.Permission | Should -Be $permission + } + } + } + + Context "When specifying the 'TeamName' parameter" { + BeforeAll { + $permission = 'Pull' + + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $teamName + Permission = $permission + } + } + + It 'Should not throw' { + { Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } + + It 'Should have set the correct Team permission' { + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + } + + $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + + $repoPermission.Permission | Should -Be $permission + } + + Context 'When the specified TeamName does not exist' { + BeforeAll { + $nonExistingTeamName = [Guid]::NewGuid().Guid + + $setGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $nonExistingTeamName + } + } + + It 'Should throw the correct exception' { + { Set-GitHubRepositoryTeamPermission @setGithubRepositoryTeamPermissionParms } | + Should -Throw "Team '$nonExistingTeamName' not found" + } + } + } + + Context "When specifying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $setGitHubRepositoryTeamPermissionParms = @{ + TeamName = $teamName + } + } + + It 'Should not throw' { + { $repo | Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } + } + + Context "When specifying the 'TeamSlug' and 'OrganizationName' Parameters from the Pipeline" { + BeforeAll -ScriptBlock { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + } + } + + It 'Should not throw' { + { $team | Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } + } + + Describe 'GitHubRepositories\Remove-GitHubRepositoryTeamPermission' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName + + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName + + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } + + $team = New-GitHubTeam @newGithubTeamParms + + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = 'Pull' + } + + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + } + + Context "When specifying the 'TeamSlug' parameter" { + BeforeAll { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = 'Pull' + } + + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + } + + It 'Should not throw' { + $removeGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Force = $true + } + + { Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + + } + + It 'Should have removed the Team permission' { + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + } + + { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | + Should -Throw 'Not Found' + } + } + + Context "When specifying the 'TeamName' parameter" { + BeforeAll { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = 'Pull' + } + + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + } + + It 'Should not throw' { + $removeGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $teamName + Force = $true + } + + { Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } + + It 'Should have removed the Team permission' { + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + } + + { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | + Should -Throw 'Not Found' + } + + Context 'When the specified TeamName does not exist' { + BeforeAll { + $nonExistingTeamName = [Guid]::NewGuid().Guid + + $removeGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $nonExistingTeamName + Force = $true + } + } + + It 'Should throw the correct exception' { + { Remove-GitHubRepositoryTeamPermission @removeGithubRepositoryTeamPermissionParms } | + Should -Throw "Team '$nonExistingTeamName' not found" + } + } + } + + Context "When specifying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $removeGitHubRepositoryTeamPermissionParms = @{ + TeamName = $teamName + Force = $true + } + } + + It 'Should not throw' { + { $repo | Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } + } + + Context "When specifying the 'TeamSlug' and 'Organization' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $removeGitHubRepositoryTeamPermissionParms = @{ + RepositoryUrl = $repo.svn_url + Force = $true + } + } + + It 'Should not throw' { + { $team | Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } + } } finally { diff --git a/USAGE.md b/USAGE.md index 58843423..e783ec8d 100644 --- a/USAGE.md +++ b/USAGE.md @@ -55,6 +55,9 @@ * [Disable repository automatic security fixes](#disable-repository-automatic-security-fixes) * [Get repository GitHub Actions permissions](#get-repository-github-actions-permissions) * [Set repository GitHub Actions permissions](#set-repository-github-actions-permissions) + * [Get a repository team permission](#get-a-repository-team-permission) + * [Set a repository team permission](#set-a-repository-team-permission) + * [Remove a repository team permission](#remove-a-repository-team-permission) * [Branches](#branches) * [Adding a new Branch to a Repository](#adding-a-new-branch-to-a-repository) * [Removing a Branch from a Repository](#removing-a-branch-from-a-repository) @@ -660,6 +663,24 @@ Get-GitHubRepositoryActionsPermission -OwnerName microsoft -RepositoryName Power Set-GitHubRepositoryActionsPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub -AllowedActions All ``` +#### Get a repository team permission + +```powershell +Get-GitHubRepositoryTeamPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub -TeamName Admins +``` + +#### Set a repository team permission + +```powershell +Set-GitHubRepositoryTeamPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub -TeamName Admins -Permission Admin +``` + +#### Remove a repository team permission + +```powershell +Remove-GitHubRepositoryTeamPermission -OwnerName microsoft -RepositoryName PowerShellForGitHub -TeamName Admins +``` + ---------- ### Branches From 7f1dbf2510534001f403811210d84a38c04747f7 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Thu, 31 Dec 2020 15:10:30 -0800 Subject: [PATCH 19/51] Fix the USAGE.md example for New-GitHubRepositoryFromTemplate (#309) Resolves #308 --- USAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/USAGE.md b/USAGE.md index e783ec8d..e3b9ad51 100644 --- a/USAGE.md +++ b/USAGE.md @@ -618,7 +618,7 @@ New-GitHubRepository -RepositoryName TestRepo -OrganizationName MyOrg -TeamId $m #### Create a repository from a template repository ```powershell -New-GitHubRepositoryFromTemplate -OwnerName MyOrg -RepositoryName MyNewRepo-TemplateOwnerName MyOrg -TemplateRepositoryName MyTemplateRepo +New-GitHubRepositoryFromTemplate -OwnerName MyOrg -RepositoryName TemplateRepoName -TargetRepositoryName MyNewRepo -TargetOwnerName MyUserName ``` #### Get repository vulnerability alert status From a1640a27b43487ea5714a0be84a9cb4ede3e7f99 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Tue, 5 Jan 2021 11:46:46 -0800 Subject: [PATCH 20/51] Update module to 0.16.0 (#310) --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ PowerShellForGitHub.psd1 | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 497e8f72..601503e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,40 @@ # PowerShellForGitHub PowerShell Module # Changelog +## [0.16.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.16.0) - (2021/01/06) + +### Features: + ++ Added the ability to retrieve and modify team permissions on a repository with + `Get-GitHubRepositoryTeamPermission`, `Set-GitHubRepositoryTeamPermission` and + `Remove-GitHubRepositoryTeamPermission` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/300) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/22e3d7bdf6c3b33fdead74dac831e0bb43beb2c4) + ++ Added the ability to retrieve and modify the GitHub Actions permissions policy for repositories + with `Get-GitHubRepositoryActionsPermission` and `Set-GitHubRepositoryActionsPermission` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/301) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/d4997057f8b1234ea1aabeb4fb6742148d3afaaf) + +### Fixes: + +- Added missing `.SYNOPSIS` to a number of functions throughout the module. + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/293) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/ab536c772a7656f92166d13f5df9ef7bf6627a3f) + +- Fixed an error in `Set-GitHubContent` which caused it to ignore requested changes to + `AuthorName`/`AuthorEmail`. + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/295) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/ec7950c02c1e52af2a6edc30331982d172f6e7ff) + +- Fixed `Get-GitHubEvent`, which was erroring out when its result contained any labels. (The labels + were being post-processed incorrectly when adding support for pipelining). + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/306) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/8fd42010209edaf10936751b8eb190655a2bdb38) + +Authors: + * [**@HowardWolosky**](https://github.com/HowardWolosky) + * [**@@X-Guardian**](https://github.com/X-Guardian) + * [**@johnlokerse**](https://github.com/johnlokerse) + * [**@joseartrivera**](https://github.com/joseartrivera) + +------ + ## [0.15.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.15.1) - (2020/09/09) ### Fixes: diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index f557729d..be840033 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -7,7 +7,7 @@ CompanyName = 'Microsoft Corporation' Copyright = 'Copyright (C) Microsoft Corporation. All rights reserved.' - ModuleVersion = '0.15.1' + ModuleVersion = '0.16.0' Description = 'PowerShell wrapper for GitHub API' # Script module or binary module file associated with this manifest. From 007deb7e53d6a1a016f864835e9ca28fdf2b08f9 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 6 Jan 2021 14:16:21 -0800 Subject: [PATCH 21/51] Fix issues with Build-Wiki and add Wiki documentation to CONTRIBUTING.md's Release section (#311) Fixed some issues with `Build-Wiki`: * Ensured that `Home.md` is not incorrectly categorized as deprecated. * Fixed how we check for `platyPS` being installed. * Fixed how we reference files in `Move-Item` to solve the issue when the file being moved is new. * Added warning/reminder to run this under `PS7+` to avoid issue with how multi-line examples get formatted. Also added Wiki updating instructions to the release section of `CONTRIBUTING.md`. --- CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++++ build/scripts/Build-Wiki.ps1 | 12 +++++++++--- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b547f708..6b335618 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,6 +37,7 @@ Looking for information on how to use this module? Head on over to [README.md]( * [Updating the CHANGELOG](#updating-the-changelog) * [Adding a New Tag](#adding-a-new-tag) * [Running the Release Build](#running-the-release-build) + * [Updating the Wiki documentation](#updating-the-wiki-documentation) * [Contributors](#contributors) * [Legal and Licensing](#legal-and-licensing) @@ -551,6 +552,41 @@ maintainer because it accesses internal services to sign the module files with M > Instructions for updating the `PowerShellGalleryApiKey` secret in the pipeline can be found in the > [internal Microsoft repo for this project](https://microsoft.visualstudio.com/Apps/_git/eng.powershellforgithub). +#### Updating the Wiki Documentation + +The [Wiki](https://github.com/microsoft/PowerShellForGitHub/wiki) contains the full documentation +for all exported commands from the module, thanks to [platyPS](https://github.com/PowerShell/platyPS). + +Every time a new release occurs, the Wiki should be updated to reflect any changes that occurred +within the module. + +1. Ensure that you have cloned the Wiki: + + ``` + git clone https://github.com/microsoft/PowerShellForGitHub.wiki.git + ``` + +2. Open a PowerShell 7+ console window (don't use Windows PowerShell as there's a platyPS bug + with that version regarding multi-line examples) and navigate to your Wiki clone. + +3. Run this command (assuming that you have a `PowerShellForGitHub` clone at the same level as your + Wiki clone): + + ```powershell + ..\PowerShellForGitHub\build\scripts\Build-Wiki.ps1 -Path .\ -RemoveDeprecated -Verbose -Force + ``` + +4. Verify the changes all make sense. You will also need to manually copy the core content of + `PowerShellForGitHub.md` into `Home.md`. For the time being, we are duplicating that content + in Home until such time as we have better content to put there. + +5. Commit the change and directly push it to the Wiki's `master` branch...no need to go through + a pull request for the Wiki changes. + +> This is not currently automated as part of the [Release pipeline](#running-the-release-build) +> because I don't currently want to store any credentials/tokens with write access to the repo +> in the pipeline. + ---------- ### Contributors diff --git a/build/scripts/Build-Wiki.ps1 b/build/scripts/Build-Wiki.ps1 index 4cf6e662..f445dd94 100644 --- a/build/scripts/Build-Wiki.ps1 +++ b/build/scripts/Build-Wiki.ps1 @@ -344,6 +344,11 @@ Set-StrictMode -Version 1.0 $Path = Resolve-Path -Path $Path +if ($PSVersionTable.PSVersion.Major -lt 7) +{ + Write-Warning 'It is recommended to run this with PowerShell 7+, as platyPS has a bug which doesn''t properly handle multi-line examples when run on older vesrions of PowerShell.' +} + $numSteps = 11 $currentStep = 0 $progressParams = @{ @@ -354,7 +359,7 @@ $progressParams = @{ ####### $currentStep++ Write-Progress @progressParams -Status 'Ensuring PlatyPS installed' -PercentComplete (($currentStep / $numSteps) * 100) -if ($null -eq (Get-Module -Name 'PlatyPS')) +if ($null -eq (Get-Module -Name 'PlatyPS' -ListAvailable)) { Write-Verbose -Message 'Installing PlatyPS Module' Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force -Verbose:$false | Out-Null @@ -377,6 +382,7 @@ $moduleRootPageFileName = "$ModuleName.md" # files that should be _removed_ from the Wiki due to rename/removal of exports. $tempFolder = Join-Path -Path $env:TEMP -ChildPath ([Guid]::NewGuid().Guid) New-Item -Path $tempFolder -ItemType Directory | Out-Null +Write-Verbose -Message "Working from temp location: $tempFolder" ####### $currentStep++ @@ -475,7 +481,7 @@ foreach ($file in $currentFiles) $content = Get-Content -Path $file -Raw -Encoding utf8 if (($content -match $generatedMarker) -and ($file.BaseName -notin $modulePages) -and - ($file.Name -ne $moduleRootPageFileName)) + ($file.Name -notin ($moduleRootPageFileName, 'Home.md'))) { $deprecatedFiles += $file } @@ -508,7 +514,7 @@ Write-Progress @progressParams -Status "Moving generated content to final destin $files = Get-ChildItem -Path $tempFolder foreach ($file in $files) { - Move-Item -Path $file -Destination $Path -Force:$Force.IsPresent + Move-Item -Path $file.FullName -Destination $Path -Force:$Force.IsPresent } Remove-Item -Path $tempFolder -Recurse -Force From f7a60c75e2cf31087f61b08d26a903a8573d740b Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 27 Jan 2021 14:02:21 -0800 Subject: [PATCH 22/51] Disable DFS for release builds (#316) The functionality is not currently being used, and keeping it enabled will cause this pipeline to stop being supported. --- build/pipelines/templates/prepare-release-internalOnly.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pipelines/templates/prepare-release-internalOnly.yaml b/build/pipelines/templates/prepare-release-internalOnly.yaml index 984f1b8f..6c883677 100644 --- a/build/pipelines/templates/prepare-release-internalOnly.yaml +++ b/build/pipelines/templates/prepare-release-internalOnly.yaml @@ -32,6 +32,7 @@ steps: displayName: Initialize Package ES inputs: productName: $(ModuleName) + useDfs: false disableWorkspace: true env: XES_DISABLEPROV: true From a2329d67302c55c42bae7fab2c78e63e1abdb656 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Sat, 20 Mar 2021 15:52:37 -0700 Subject: [PATCH 23/51] Allow callers of Invoke-GHRestMethod[MultipleResult] to specify additional headers (#319) When experimenting with the the notifications API, it was necessary to be able to specify an additional header (If-Modified-Since). Making this support generic by allowing callers to specify any number of additional headers to be included with the REST request. --- GitHubCore.ps1 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index 3f37c402..f5cc17ac 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -68,6 +68,10 @@ function Invoke-GHRestMethod be configured correctly automatically. You should only specify this under advanced situations (like if the extension of InFile is of a type unknown to this module). + .PARAMETER AdditionalHeader + Allows the caller to specify any number of additional headers that should be added to + the request. + .PARAMETER ExtendedResult If specified, the result will be a PSObject that contains the normal result, along with the response code and other relevant header detail content. @@ -135,6 +139,8 @@ function Invoke-GHRestMethod [string] $ContentType = $script:defaultJsonBodyContentType, + [HashTable] $AdditionalHeader = @{}, + [switch] $ExtendedResult, [switch] $Save, @@ -228,6 +234,12 @@ function Invoke-GHRestMethod 'User-Agent' = 'PowerShellForGitHub' } + # Add any additional headers + foreach ($header in $AdditionalHeader.Keys.GetEnumerator()) + { + $headers.Add($header, $AdditionalHeader.$header) + } + $AccessToken = Get-AccessToken -AccessToken $AccessToken if (-not [String]::IsNullOrEmpty($AccessToken)) { @@ -588,6 +600,10 @@ function Invoke-GHRestMethodMultipleResult Specify the media type in the Accept header. Different types of commands may require different media types. + .PARAMETER AdditionalHeader + Allows the caller to specify any number of additional headers that should be added to + all of the requests made. + .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api as opposed to requesting a new one. @@ -637,6 +653,8 @@ function Invoke-GHRestMethodMultipleResult [string] $AcceptHeader = $script:defaultAcceptHeader, + [hashtable] $AdditionalHeader = @{}, + [string] $AccessToken, [string] $TelemetryEventName = $null, @@ -675,6 +693,7 @@ function Invoke-GHRestMethodMultipleResult 'Method' = 'Get' 'Description' = $currentDescription 'AcceptHeader' = $AcceptHeader + 'AdditionalHeader' = $AdditionalHeader 'ExtendedResult' = $true 'AccessToken' = $AccessToken 'TelemetryProperties' = $telemetryProperties From 002363505f5738209f4b25d4d31c3d0434bc015e Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Thu, 25 Mar 2021 00:52:07 -0700 Subject: [PATCH 24/51] Fix gist test validating the since parameter (#321) octocat recently updated all of its gists, starting on 2/24/2021. The test previously would query for gists that were updated since 2016, but as of 2/24/2021, that included all of them. The test has been made more robust by choosing the most recent date of all the gists and then requerying, which should hopefully now always guarantee that we'll get a reduced set of gists, unless all of the gists are suddenly updated in the future at the exact same second. --- Tests/GitHubGists.tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/GitHubGists.tests.ps1 b/Tests/GitHubGists.tests.ps1 index d26e483b..61c1053b 100644 --- a/Tests/GitHubGists.tests.ps1 +++ b/Tests/GitHubGists.tests.ps1 @@ -238,7 +238,7 @@ try } } - $since = (Get-Date -Date '01/01/2016') + $since = $gists.updated_At | Sort-Object | Select-Object -Last 1 $sinceGists = Get-GitHubGist -UserName $username -Since $since It 'Should have fewer results with using the since parameter' { $sinceGists.Count | Should -BeGreaterThan 0 From 1200b5b36aa94d96906802ddc04f8604ab83d83c Mon Sep 17 00:00:00 2001 From: jing8956 Date: Tue, 11 May 2021 12:12:43 +0800 Subject: [PATCH 25/51] Fix Encode Issues (#328) `Set-GitHubContent` needed to use the `UTF8` encoder, just like `Get-GitHubContent`, as opposed to the `Unicode` encoder. --- GitHubContents.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GitHubContents.ps1 b/GitHubContents.ps1 index d77c21aa..9962e91e 100644 --- a/GitHubContents.ps1 +++ b/GitHubContents.ps1 @@ -358,7 +358,7 @@ filter Set-GitHubContent $uriFragment = "/repos/$OwnerName/$RepositoryName/contents/$Path" - $encodedContent = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Content)) + $encodedContent = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Content)) $hashBody = @{ message = $CommitMessage From 0ebf9e8b8d0f4fa361996674dbca804da36bace7 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 26 May 2021 08:24:11 -0700 Subject: [PATCH 26/51] Update module to 0.16.1 (#330) --- CHANGELOG.md | 170 +++++++++++++++++++++++++-------------- PowerShellForGitHub.psd1 | 2 +- 2 files changed, 112 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 601503e6..b3688003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,29 @@ # PowerShellForGitHub PowerShell Module # Changelog +## [0.16.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.16.1) - (2021/05/26) + +### Features + ++ `Invoke-GHRestMethodMultipleResult` now allows callers to specify `AdditionalHeader`, just like + `Invoke-GHRestMethod`. + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/319) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/a2329d67302c55c42bae7fab2c78e63e1abdb656) + +### Fixes + +- Fixes encoding issues when calling `Set-GitHubContent` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/328) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/1200b5b36aa94d96906802ddc04f8604ab83d83c) + +### Authors + + * [**@HowardWolosky**](https://github.com/HowardWolosky) + * [**@jing8956**](https://github.com/jing8956) + +------ + ## [0.16.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.16.0) - (2021/01/06) -### Features: +### Features + Added the ability to retrieve and modify team permissions on a repository with `Get-GitHubRepositoryTeamPermission`, `Set-GitHubRepositoryTeamPermission` and @@ -14,7 +34,7 @@ with `Get-GitHubRepositoryActionsPermission` and `Set-GitHubRepositoryActionsPermission` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/301) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/d4997057f8b1234ea1aabeb4fb6742148d3afaaf) -### Fixes: +### Fixes - Added missing `.SYNOPSIS` to a number of functions throughout the module. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/293) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/ab536c772a7656f92166d13f5df9ef7bf6627a3f) @@ -27,9 +47,10 @@ were being post-processed incorrectly when adding support for pipelining). [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/306) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/8fd42010209edaf10936751b8eb190655a2bdb38) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) - * [**@@X-Guardian**](https://github.com/X-Guardian) + * [**@X-Guardian**](https://github.com/X-Guardian) * [**@johnlokerse**](https://github.com/johnlokerse) * [**@joseartrivera**](https://github.com/joseartrivera) @@ -37,14 +58,15 @@ Authors: ## [0.15.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.15.1) - (2020/09/09) -### Fixes: +### Fixes - Fixed the default `LogPath` when no user profile is available (like in the situation of running within the context of an Azure Function App). The alternate default log path in this scenario will now be the `LocalApplicationDataFolder`. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/283) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/e9a6810b3c1a3c6b2ec798bc06f4fa50be154e87) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) ------ @@ -191,7 +213,7 @@ existing users need to be made aware of. * `Get-GitHubTeam` and `Get-GitHubTeamMember` no longer support the `TeamId` parameter, as that functionality has been deprecated by GitHub. You can use `TeamSlug` instead. -### Features: +### Features + Complete pipeline support has been added to the module. You can now pipe the output of almost any command as input to almost any command. Every command output now has a specific `GitHub.*` @@ -294,7 +316,7 @@ existing users need to be made aware of. `DefaultPassThru`. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/276) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/9600fc21120e17241e60606c5de3459d973026bb) -### Fixes: +### Fixes - Module update check needs to be able to handle when the module in use is newer than the published version (since publication to PowerShellGallery happens a few hours after the version is updated @@ -353,7 +375,8 @@ existing users need to be made aware of. status is handled in the module. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/274) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/db111559f9844e9a30b666ec069a5dc462643c63) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) * [**@X-Guardian**](https://github.com/X-Guardian) * [**@themilfan**](https://github.com/themilfan) @@ -363,7 +386,7 @@ Authors: ## [0.14.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.14.0) - (2020/05/30) -### Features: +### Features + The module will now asynchronously check for updates up to once per day. This can be disabled if desired with the `Set-GitHubConfiguration -DisableUpdateCheck`. @@ -372,7 +395,7 @@ Authors: exported. Now it is. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/180) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/b7e1ea1cb912493e110b9854b0ec7700462254a0) -### Fixes: +### Fixes - Fixes the behavior of `Get-GitHubRepository`. It actually had a number of issues: [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/179) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/c4c1ec344a357489d248b9cf1bc2837484d4915f) @@ -404,19 +427,21 @@ Authors: - Documentation updates around configuring unattended authentication. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/173) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/3440909f5f1264865ccfca85ce2364af3ce85425) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.13.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.13.1) - (2020/05/12) -### Fixes: +### Fixes - Ensure progress bar for Wait-JobWithAnimation gets marked as Completed [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/169) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/bb2ad45f61f4e55ba763d5eb402c80de5991bb6b) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) ------ @@ -428,14 +453,15 @@ Authors: - Migrate REST API progress status to use Write-Progress [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/167) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/992f67871cd659dac20833487b326bdad7b85bd8) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.12.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.12.0) - (2020/05/12) -### Features: +### Features + Added core support for Projects [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/160) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/1cdaac1a5af873589458bd0b40b3651187ec7e19) @@ -446,14 +472,15 @@ Authors: + Added sample usage documentation for the new Project API's [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/164) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/1556b8b39cd61735aad14be0fb237c14e763f696) -### Fixes: +### Fixes - Minor spelling fixes in documentation throughout module [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/165) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/6735ba57a5a43b61a37ef09d4021296dcd417dba) - Fixed confirmation message for `Rename-GitHubRepository` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/161) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/3fab72464e38cb573408add7e99d5a6bb0db2ea1) -Authors: +### Authors + * [**@jpomfret**](https://github.com/jpomfret) * [**@HowardWolosky**](https://github.com/HowardWolosky) @@ -461,18 +488,20 @@ Authors: ## [0.11.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.11.0) - (2020/04/03) -### Features: +### Features + Added `Get-GitHubContents` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/146) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/9a45908dc65b3e8dd0227083fab281099cf07b1b) -Author: [**@Shazwazza**](https://github.com/Shazwazza) +### Authors + +[**@Shazwazza**](https://github.com/Shazwazza) ------ ## [0.10.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.10.0) - (2020/03/02) -### Features: +### Features + Added `Rename-GitHubRepository` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/145) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/536b762425d51a181166c2c47ad2b00014911d1d) @@ -483,18 +512,20 @@ Author: [**@mtboren**](https://github.com/mtboren) ## [0.9.2](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.2) - (2019/11/11) -### Fixes: +### Fixes - Reduces the warning noise seen during execution of the unit tests. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/130) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/89f69f1132505f04e6b2ac38b6f5a93aef6ac947) -Author: [**@smaglio81**](https://github.com/smaglio81) +### Authors + +[**@smaglio81**](https://github.com/smaglio81) ------ ## [0.9.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.1) - (2019/09/24) -### Fixes: +### Fixes - Ensure Milestone `due_on` always gets set to the desired date. (Attempts to work around odd GitHub behavior which uses PST/PDT's midnight to determine the date instead of UTC.) @@ -505,27 +536,30 @@ Author: [**@smaglio81**](https://github.com/smaglio81) - The `Archived` switch's value was being incorrectly inverted [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/135) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/9bdb37c053f98f108d346050622b609d8488fd45) -Author: [**@HowardWolosky**](https://github.com/HowardWolosky) +### Authors + +[**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.9.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.9.0) - (2019/09/19) -### Features: +### Features + Added `Get-GitHubRelease` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/125) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/7ea773c715525273dddd451d2a05f429e7fe69e1) + Added `New-GitHubPullRequest` [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/111) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/788465faec1b6d6331537aa87c2d94039682e373) -### Fixes: +### Fixes - Updates the GitHub Enterprise support to use the `http(s)://[hostname]/api/v3` syntax instead of the non-standard `http(s)://api.[hostname]/` syntax. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/118) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/f7b956da4ae169ec6ec1bb6582ce742372677f5c) - Minor Comment Based Help (CBH) update for Get-GitHubRepository [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/120) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/220333a71214fb88a33093b5e907d431dcfdb4c8) -Authors: +### Authors + * [**@smaglio81**](https://github.com/smaglio81) * [**@rjmholt**](https://github.com/rjmholt) * [**@v2kiran**](https://github.com/v2kiran) @@ -535,19 +569,20 @@ Authors: ## [0.8.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.8.0) - (2019/04/12) -### Features: +### Features + Added support for GitHub Enterprise users by adding a new `ApiHostName` configuration value. ([more info](https://github.com/Microsoft/PowerShellForGitHub/blob/master/README.md#github-enterprise)) [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/101) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/d5acd0f73d97f6692914976ce9366456a59cbf70) -### Fixes: +### Fixes - Renamed `ConvertFrom-Markdown` to `ConvertFrom-GitHubMarkdown` to avoid a conflict with PSCore's new `ConvertFrom-Markdown` command. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/100) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/088f95b5a1340c7ce570e6e68a41967fd5760c46) -Authors: +### Authors + * [**@Cellivar**](https://github.com/Cellivar) * [**@HowardWolosky**](https://github.com/HowardWolosky) @@ -555,14 +590,14 @@ Authors: ## [0.7.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.7.0) - (2019/03/15) -### Features: +### Features + Added `Test-GitHubOrganizationMember` to test if a user is in an organization. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/90) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/c60bb29ac02e7ab9fcd2e29db865b63876cb0125) + Updated `Get-GitHubTeamMember` to optionally work directly with a TeamId. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/90) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/c60bb29ac02e7ab9fcd2e29db865b63876cb0125) -### Fixes: +### Fixes - Modified all [int] parameters to be [int64] to avoid out of bounds issues with large ID's. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/94) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/a22739e7f535faf4c5f486694bd213782437e82a) @@ -570,44 +605,51 @@ Authors: the REST responses. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/88) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/592167de9b3f07635c49365e291082fd3f712586) -Author: [**@HowardWolosky**](https://github.com/HowardWolosky) +### Authors + +[**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.6.4](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.4) - (2019/01/16) -### Fixes: +### Fixes - Updated the `*-GitHubIssue` functions to support specifying the `MediaType` that should be used for the returned result. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/83) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/e3b6c53017abd36fc70253e1a49c31046c885ad1) -Author: [**@joseartrivera**](https://github.com/joseartrivera) +### Authors + +[**@joseartrivera**](https://github.com/joseartrivera) ------ ## [0.6.3](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.3) - (2019/01/07) -### Fixes: +### Fixes - Updated all parameter sets to use `CamelCase` for the permitted options, and stopped any use of abbreviation, to be more consistent with the rest of PowerShell. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/81) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/185441078efeb0e6693eafeb023785388a1a5a69) -Author: [**@HowardWolosky**](https://github.com/HowardWolosky) +### Authors + +[**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.6.2](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.2) - (2018/12/13) -### Fixes: +### Fixes - Fixes a bug preventing Labels from being correctly added at the time of new Issue creation or modified when updating an issue. {[[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/76) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/3b6e84cbafaf044e2154a06612b1c43a873cd002) and [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/78) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/577f07bd219e9b5c03d481e562fd7f2fc3586474)} -Authors: +### Authors + * [**@lazywinadmin**](https://github.com/lazywinadmin) * [**@HowardWolosky**](https://github.com/HowardWolosky) @@ -615,20 +657,21 @@ Authors: ## [0.6.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.1) - (2018/12/13) -### Fixes: +### Fixes - Fixes a bug with checking Issues. When trying to list all issues, it tried to speficially look for Issue 0. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/73) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/bf6764080ce1291cfe2530a39ffd292f38b37440) -Authors: +### Authors + * [**@joseartrivera**](https://github.com/joseartrivera) ------ ## [0.6.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.6.0) - (2018/12/13) -### Features: +### Features + Completes all support for GitHub Issue API's: + Added support for the [Issue Event](https://developer.github.com/v3/issues/events/) API's. @@ -641,7 +684,8 @@ Authors: exact body of the REST request being sent before it is sent over the wire. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/60) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/98aec29d61bf013a153705079703ae027cc25c9f) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) * [**@joseartrivera**](https://github.com/joseartrivera) * [**@etgottli**](https://github.com/etgottli) @@ -650,20 +694,21 @@ Authors: ## [0.5.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.5.0) - (2018/11/30) -### Features: +### Features + Added support for the [Issue Comment](https://developer.github.com/v3/issues/comments/) API's. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/53) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/28b314bd7c0a810848e1acb3df43a1d83291be7b) + Added support for the [Issue Assignee](https://developer.github.com/v3/issues/assignees/) API's. [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/54) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/680696a833b3cc753e961fc8c723b0be9b39ecc2) -### Fixes: +### Fixes - Fixed bug that caused single or empty arrays returned within objects to be flattened (instead of remaining as arrays) [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/56) | [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/6cf344fb38485275f94b1e85c1a5f932e1b519c3) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) * [**@joseartrivera**](https://github.com/joseartrivera) @@ -671,12 +716,12 @@ Authors: ## [0.4.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.4.0) - (2018/11/16) -### Features: +### Features + Added support for the [Repository Traffic API's](https://developer.github.com/v3/repos/traffic/). [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/49) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/8d2e76f9059f0939b892d08386fe43f0e2722bb0) -### Fixes: +### Fixes - Made NuGet dll retrieval more robust by preventing potential file access problems from being written to the error stream. @@ -685,7 +730,8 @@ Authors: if explicitly passed-in [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/50) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/c6835f4cb1ef0e78e23a8195949eb9ad2555fd4a) -Authors: +### Authors + * [**@HowardWolosky**](https://github.com/HowardWolosky) * [**@joseartrivera**](https://github.com/joseartrivera) @@ -693,7 +739,7 @@ Authors: ## [0.3.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.3.1) - (2018/11/13) -### Fixes: +### Fixes - Minor static analysis issues fixed. - Corrected name of the test file for `GitHubRepositoryForks` @@ -707,24 +753,26 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) ## [0.3.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.3.0) - (2018/11/13) -### Features: +### Features + Added support for querying forks and creating new ones. -### Fixes: +### Fixes - Will only perform a retry when receiving a `202` response on a `GET` request. Previously, it would retry regardless of the method of the request. More Info: [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/41) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/1076239d7639497984a6e0b04df1e69019c4ec28) -Author: [**@HowardWolosky**](https://github.com/HowardWolosky) +### Authors + +[**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.2.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.2.0) - (2018/11/13) -### Features: +### Features + Significant restructing and refactoring of entire module to make future expansion easier. + Significant documentation updates ([CHANGELOG](./CHANGELOG.md), [CONTRIBUTING.md](./CONTRIBUTING.md), @@ -744,7 +792,7 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) get tags, get/set topic and current used programming languages. + Enhanced user query support as well as being able update information for the current user. -### Fixes: +### Fixes - Made parameter ordering consistent across all functions (OwnerName is now first, then RepositoryName) - Normalized all parameters to use SentenceCase @@ -789,16 +837,20 @@ Author: [**@HowardWolosky**](https://github.com/HowardWolosky) More Info: [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/39) | [[cl]](https://github.com/PowerShell/PowerHellForGitHub/commit/eb33688e5b8d688d28e8582b76b526da3c4428be) -Author: [**@HowardWolosky**](https://github.com/HowardWolosky) +### Authors + +[**@HowardWolosky**](https://github.com/HowardWolosky) ------ ## [0.1.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.1.0) - (2016/11/29) -### Features: +### Features + Initial public release More Info: [[cl]](https://github.com/PowerShell/PowerShellForGitHub/commit/6a3b400019d6a97ccc2f08a951fd4b2d09282eb5) -Author: [**@KarolKaczmarek**](https://github.com/KarolKaczmarek) +### Authors + +[**@KarolKaczmarek**](https://github.com/KarolKaczmarek) diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index be840033..73f2bd10 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -7,7 +7,7 @@ CompanyName = 'Microsoft Corporation' Copyright = 'Copyright (C) Microsoft Corporation. All rights reserved.' - ModuleVersion = '0.16.0' + ModuleVersion = '0.16.1' Description = 'PowerShell wrapper for GitHub API' # Script module or binary module file associated with this manifest. From f7efc4a03640cf292b0e6a256d6713a6f15145b2 Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Thu, 15 Jul 2021 16:43:15 +0100 Subject: [PATCH 27/51] GitHubBranches: Add Get/New/Remove GitHub Repository Branch Pattern Protection Rule (#313) Adds the following functions to the `GitHubBranches` module: * `Invoke-GHGraphQl` * `Get-GitHubRepositoryBranchPatternProtectionRule` * `New-GitHubRepositoryBranchPatternProtectionRule` * `Remove-GitHubRepositoryBranchPatternProtectionRule` `Invoke-GHGraphQl` is based on `Invoke-GHRestMethod` but modified with the following features: * Use of the GitHub GraphQL API Endpoint. * PowerShell 5 and 6+ `Invoke-WebRequest` error handling support. * Use of `ThrowTerminatingError` instead of `Throw` for enhanced exceptions and hiding the internal details of the function. Reference: [Everything you wanted to know about exceptions](https://docs.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-exceptions) * GraphQl specific error handling. * Extensive debug logging. Fixes #312 References * [createbranchprotectionrule](https://docs.github.com/en/graphql/reference/mutations#createbranchprotectionrule) * [deletebranchprotectionrule](https://docs.github.com/en/graphql/reference/mutations#deletebranchprotectionrule) * [branchprotectionrule](https://docs.github.com/en/graphql/reference/objects#branchprotectionrule) --- Formatters/GitHubBranches.Format.ps1xml | 74 ++ GitHubBranches.ps1 | 1170 +++++++++++++++++++++-- GitHubGraphQl.ps1 | 365 +++++++ Helpers.ps1 | 52 + PowerShellForGitHub.psd1 | 7 + Tests/Common.ps1 | 1 + Tests/GitHubBranches.tests.ps1 | 580 ++++++++++- Tests/GitHubGraphQl.Tests.ps1 | 237 +++++ USAGE.md | 21 + 9 files changed, 2422 insertions(+), 85 deletions(-) create mode 100644 Formatters/GitHubBranches.Format.ps1xml create mode 100644 GitHubGraphQl.ps1 create mode 100644 Tests/GitHubGraphQl.Tests.ps1 diff --git a/Formatters/GitHubBranches.Format.ps1xml b/Formatters/GitHubBranches.Format.ps1xml new file mode 100644 index 00000000..509427b9 --- /dev/null +++ b/Formatters/GitHubBranches.Format.ps1xml @@ -0,0 +1,74 @@ + + + + + + GitHub.BranchPatternProtectionRule + + GitHub.BranchPatternProtectionRule + + + + + + + RepositoryUrl + + + pattern + + + requiredApprovingReviewCount + + + dismissesStaleReviews + + + requiresCodeOwnerReviews + + + DismissalTeams + + + DismissalUsers + + + requiresStatusChecks + + + requiresStrictStatusChecks + + + requiredStatusCheckContexts + + + requiresCommitSignatures + + + requiresLinearHistory + + + isAdminEnforced + + + RestrictPushApps + + + RestrictPushTeams + + + RestrictPushUsers + + + allowsForcePushes + + + allowsDeletions + + + + + + + + diff --git a/GitHubBranches.ps1 b/GitHubBranches.ps1 index 969f7264..dfd04c27 100644 --- a/GitHubBranches.ps1 +++ b/GitHubBranches.ps1 @@ -4,6 +4,10 @@ @{ GitHubBranchTypeName = 'GitHub.Branch' GitHubBranchProtectionRuleTypeName = 'GitHub.BranchProtectionRule' + GitHubBranchPatternProtectionRuleTypeName = 'GitHub.BranchPatternProtectionRule' + MaxProtectionRules = 100 + MaxPushAllowances = 100 + MaxReviewDismissalAllowances = 100 }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } @@ -485,6 +489,7 @@ filter Remove-GitHubRepositoryBranch Invoke-GHRestMethod @params | Out-Null } + filter Get-GitHubRepositoryBranchProtectionRule { <# @@ -1072,128 +1077,1125 @@ filter Remove-GitHubRepositoryBranchProtectionRule return Invoke-GHRestMethod @params | Out-Null } -filter Add-GitHubBranchAdditionalProperties +filter New-GitHubRepositoryBranchPatternProtectionRule { -<# + <# .SYNOPSIS - Adds type name and additional properties to ease pipelining to GitHub Branch objects. + Creates a branch protection rule for a branch on a given GitHub repository. - .PARAMETER InputObject - The GitHub object to add additional properties to. + .DESCRIPTION + Creates a branch protection rules for a branch on a given GitHub repository. - .PARAMETER TypeName - The type that should be assigned to the object. + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER OrganizationName + Name of the Organization. + + .PARAMETER BranchPatternName + The branch name pattern to create the protection rule on. + + .PARAMETER StatusCheck + The list of status checks to require in order to merge into the branch. + + .PARAMETER RequireStrictStatusChecks + Require branches to be up to date before merging. This setting will not take effect unless + at least one status check is defined. + + .PARAMETER IsAdminEnforced + Enforce all configured restrictions for administrators. + + .PARAMETER DismissalUser + Specify the user names of users who can dismiss pull request reviews. + + .PARAMETER DismissalTeam + Specify which teams can dismiss pull request reviews. This can only be + specified for organization-owned repositories. + + .PARAMETER DismissStaleReviews + If specified, approving reviews when someone pushes a new commit are automatically + dismissed. + + .PARAMETER RequireCodeOwnerReviews + Blocks merging pull requests until code owners review them. + + .PARAMETER RequiredApprovingReviewCount + Specify the number of reviewers required to approve pull requests. Use a number between 1 + and 6. + + .PARAMETER RestrictPushUser + Specify which users have push access. + + .PARAMETER RestrictPushTeam + Specify which teams have push access. + + .PARAMETER RestrictPushApp + Specify which apps have push access. + + .PARAMETER RequireLinearHistory + Enforces a linear commit Git history, which prevents anyone from pushing merge commits to a + branch. Your repository must allow squash merging or rebase merging before you can enable a + linear commit history. + + .PARAMETER RequireCommitSignatures + Specifies whether commits are required to be signed. + + .PARAMETER AllowForcePushes + Permits force pushes to the protected branch by anyone with write access to the repository. + + .PARAMETER AllowDeletions + Allows deletion of the protected branch by anyone with write access to the repository. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. .INPUTS - [PSCustomObject] + GitHub.Repository + GitHub.Branch .OUTPUTS - GitHub.Branch + GitHub.BranchPatternProtectionRule + + .NOTES + Protecting a branch requires admin or owner permissions to the repository. + + .EXAMPLE + New-GitHubRepositoryBranchPatternProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchName release/**/* -EnforceAdmins + + Creates a branch protection rule for the 'release/**/*' branch pattern of the PowerShellForGithub repository + enforcing all configuration restrictions for administrators. + + .EXAMPLE + New-GitHubRepositoryBranchPatternProtectionRule -Uri 'https://github.com/microsoft/PowerShellForGitHub' -BranchName master -RequiredApprovingReviewCount 1 + + Creates a branch protection rule for the master branch of the PowerShellForGithub repository + requiring one approving review. #> - [CmdletBinding()] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Internal helper that is definitely adding more than one property.")] + [CmdletBinding( + PositionalBinding = $false, + SupportsShouldProcess, + DefaultParameterSetName = 'Elements')] + [OutputType( { $script:GitHubBranchPatternProtectionRuleTypeName })] param( + [Parameter(ParameterSetName = 'Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName = 'Elements')] + [string] $RepositoryName, + [Parameter( Mandatory, - ValueFromPipeline)] - [AllowNull()] - [AllowEmptyCollection()] - [PSCustomObject[]] $InputObject, + ValueFromPipelineByPropertyName, + Position = 1, + ParameterSetName = 'Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [string] $OrganizationName, + + [Parameter( + Mandatory, + Position = 2)] + [string] $BranchPatternName, [ValidateNotNullOrEmpty()] - [string] $TypeName = $script:GitHubBranchTypeName - ) + [string[]] $StatusCheck, - foreach ($item in $InputObject) - { - $item.PSObject.TypeNames.Insert(0, $TypeName) + [switch] $RequireStrictStatusChecks, - if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) - { - if ($null -ne $item.url) - { - $elements = Split-GitHubUri -Uri $item.url - } - else - { - $elements = Split-GitHubUri -Uri $item.commit.url - } - $repositoryUrl = Join-GitHubUri @elements + [switch] $IsAdminEnforced, - Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + [ValidateNotNullOrEmpty()] + [string[]] $DismissalUser, - $branchName = $item.name - if ($null -eq $branchName) - { - $branchName = $item.ref -replace ('refs/heads/', '') - } + [ValidateNotNullOrEmpty()] + [string[]] $DismissalTeam, - Add-Member -InputObject $item -Name 'BranchName' -Value $branchName -MemberType NoteProperty -Force + [switch] $DismissStaleReviews, - if ($null -ne $item.commit) - { - Add-Member -InputObject $item -Name 'Sha' -Value $item.commit.sha -MemberType NoteProperty -Force - } - elseif ($null -ne $item.object) - { - Add-Member -InputObject $item -Name 'Sha' -Value $item.object.sha -MemberType NoteProperty -Force - } - } + [switch] $RequireCodeOwnerReviews, - Write-Output $item + [ValidateRange(1, 6)] + [int] $RequiredApprovingReviewCount, + + [ValidateNotNullOrEmpty()] + [string[]] $RestrictPushUser, + + [ValidateNotNullOrEmpty()] + [string[]] $RestrictPushTeam, + + [ValidateNotNullOrEmpty()] + [string[]] $RestrictPushApp, + + [switch] $RequireLinearHistory, + + [switch] $AllowForcePushes, + + [switch] $AllowDeletions, + + [switch] $RequireCommitSignatures, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + if ([System.String]::IsNullOrEmpty($OrganizationName)) + { + $OrganizationName = $OwnerName } -} -filter Add-GitHubBranchProtectionRuleAdditionalProperties -{ - <# - .SYNOPSIS - Adds type name and additional properties to ease pipelining to GitHub Branch Protection Rule objects. + $telemetryProperties = @{ + OwnerName = (Get-PiiSafeString -PlainText $OwnerName) + RepositoryName = (Get-PiiSafeString -PlainText $RepositoryName) + } - .PARAMETER InputObject - The GitHub object to add additional properties to. + $hashbody = @{query = "query repo { repository(name: ""$RepositoryName"", owner: ""$OwnerName"") { id } }" } - .PARAMETER TypeName - The type that should be assigned to the object. + $params = @{ + Body = ConvertTo-Json -InputObject $hashBody + Description = "Querying Repository $RepositoryName, Owner $OwnerName" + AccessToken = $AccessToken + TelemetryEventName = 'Get-GitHubRepositoryQ1' + TelemetryProperties = $telemetryProperties + } - .INPUTS - PSCustomObject + try + { + $result = Invoke-GHGraphQl @params + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } - .OUTPUTS - GitHub.Branch -#> - [CmdletBinding()] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', - Justification = 'Internal helper that is definitely adding more than one property.')] - param( - [Parameter( - Mandatory, - ValueFromPipeline)] - [AllowNull()] - [AllowEmptyCollection()] - [PSCustomObject[]] $InputObject, + $repoId = $result.data.repository.id - [ValidateNotNullOrEmpty()] - [string] $TypeName = $script:GitHubBranchProtectionRuleTypeName + $mutationList = @( + "repositoryId: ""$repoId"", pattern: ""$BranchPatternName""" ) - foreach ($item in $InputObject) + if ($PSBoundParameters.ContainsKey('DismissalTeam') -or + $PSBoundParameters.ContainsKey('RestrictPushTeam')) { - $item.PSObject.TypeNames.Insert(0, $TypeName) + Write-Debug -Message "Getting details for all GitHub Teams in Organization '$OrganizationName'" - if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + try { - $elements = Split-GitHubUri -Uri $item.url - $repositoryUrl = Join-GitHubUri @elements - Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + $orgTeams = Get-GitHubTeam -OrganizationName $OrganizationName -Verbose:$false + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } + } - $hostName = $(Get-GitHubConfiguration -Name 'ApiHostName') + # Process 'Require pull request reviews before merging' properties + if ($PSBoundParameters.ContainsKey('RequiredApprovingReviewCount') -or + $PSBoundParameters.ContainsKey('DismissStaleReviews') -or + $PSBoundParameters.ContainsKey('RequireCodeOwnerReviews') -or + $PSBoundParameters.ContainsKey('DismissalUser') -or + $PSBoundParameters.ContainsKey('DismissalTeam')) + { + $mutationList += 'requiresApprovingReviews: true' - if ($item.url -match "^https?://(?:www\.|api\.|)$hostName/repos/(?:[^/]+)/(?:[^/]+)/branches/([^/]+)/.*$") + if ($PSBoundParameters.ContainsKey('RequiredApprovingReviewCount')) + { + $mutationList += 'requiredApprovingReviewCount: ' + $RequiredApprovingReviewCount + } + + if ($PSBoundParameters.ContainsKey('DismissStaleReviews')) + { + $mutationList += 'dismissesStaleReviews: ' + $DismissStaleReviews.ToBool().ToString().ToLower() + } + + if ($PSBoundParameters.ContainsKey('RequireCodeOwnerReviews')) + { + $mutationList += 'requiresCodeOwnerReviews: ' + $RequireCodeOwnerReviews.ToBool().ToString().ToLower() + } + + if ($PSBoundParameters.ContainsKey('DismissalUser') -or + $PSBoundParameters.ContainsKey('DismissalTeam')) + { + $reviewDismissalActorIds = @() + + if ($PSBoundParameters.ContainsKey('DismissalUser')) { - Add-Member -InputObject $item -Name 'BranchName' -Value $Matches[1] -MemberType NoteProperty -Force + foreach ($user in $DismissalUser) + { + $hashbody = @{query = "query user { user(login: ""$user"") { id } }"} + + $params = @{ + Body = ConvertTo-Json -InputObject $hashBody + Description = "Querying for user $user" + AccessToken = $AccessToken + TelemetryEventName = 'Get-GitHubUserQ1' + TelemetryProperties = $telemetryProperties + } + + try + { + $result = Invoke-GHGraphQl @params + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } + + $reviewDismissalActorIds += $result.data.user.id + } + } + + if ($PSBoundParameters.ContainsKey('DismissalTeam')) + { + foreach ($team in $DismissalTeam) + { + $teamDetail = $orgTeams | Where-Object -Property Name -eq $team + + if ($teamDetail.Count -eq 0) + { + $newErrorRecordParms = @{ + ErrorMessage = "Team '$team' not found in organization '$OrganizationName'" + ErrorId = 'DismissalTeamNotFound' + ErrorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound + TargetObject = $team + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + + $getGitHubRepositoryTeamPermissionParms = @{ + TeamSlug = $teamDetail.TeamSlug + OwnerName = $ownerName + RepositoryName = $repositoryName + Verbose = $false + } + + Write-Debug -Message "Getting GitHub Permissions for Team '$team' on Repository '$OwnerName/$RepositoryName'" + + try + { + $teamPermission = Get-GitHubRepositoryTeamPermission @getGitHubRepositoryTeamPermissionParms + } + catch + { + Write-Debug -Message "Team '$team' has no permissions on Repository '$OwnerName/$RepositoryName'" + } + + if (($teamPermission.permissions.push -eq $true) -or ($teamPermission.permissions.maintain -eq $true)) + { + $reviewDismissalActorIds += $teamDetail.node_id + } + else + { + $newErrorRecordParms = @{ + ErrorMessage = "Team '$team' does not have push or maintain permissions on repository '$OwnerName/$RepositoryName'" + ErrorId = 'DismissalTeamNoPermissions' + ErrorCategory = [System.Management.Automation.ErrorCategory]::PermissionDenied + TargetObject = $team + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } } + + $mutationList += 'restrictsReviewDismissals: true' + $mutationList += 'reviewDismissalActorIds: [ "' + ($reviewDismissalActorIds -join ('","')) + '" ]' } + } + + # Process 'Require status checks to pass before merging' properties + if ($PSBoundParameters.ContainsKey('StatusCheck') -or + $PSBoundParameters.ContainsKey('RequireStrictStatusChecks')) + { + $mutationList += 'requiresStatusChecks: true' + + if ($PSBoundParameters.ContainsKey('RequireStrictStatusChecks')) + { + $mutationList += 'requiresStrictStatusChecks: ' + $RequireStrictStatusChecks.ToBool().ToString().ToLower() + } + + if ($PSBoundParameters.ContainsKey('StatusCheck')) + { + $mutationList += 'requiredStatusCheckContexts: [ "' + ($StatusCheck -join ('","')) + '" ]' + } + } + + if ($PSBoundParameters.ContainsKey('RequireCommitSignatures')) + { + $mutationList += 'requiresCommitSignatures: ' + $RequireCommitSignatures.ToBool().ToString().ToLower() + } + + if ($PSBoundParameters.ContainsKey('RequireLinearHistory')) + { + $mutationList += 'requiresLinearHistory: ' + $RequireLinearHistory.ToBool().ToString().ToLower() + } + + if ($PSBoundParameters.ContainsKey('IsAdminEnforced')) + { + $mutationList += 'isAdminEnforced: ' + $IsAdminEnforced.ToBool().ToString().ToLower() + } + + # Process 'Restrict who can push to matching branches' properties + if ($PSBoundParameters.ContainsKey('RestrictPushUser') -or + $PSBoundParameters.ContainsKey('RestrictPushTeam') -or + $PSBoundParameters.ContainsKey('RestrictPushApp')) + { + $restrictPushActorIds = @() + + if ($PSBoundParameters.ContainsKey('RestrictPushUser')) + { + foreach ($user in $RestrictPushUser) + { + $hashbody = @{query = "query user { user(login: ""$user"") { id } }" } + + $params = @{ + Body = ConvertTo-Json -InputObject $hashBody + Description = "Querying for User $user" + AccessToken = $AccessToken + TelemetryEventName = 'GetGitHubUserQ1' + TelemetryProperties = $telemetryProperties + } + + try + { + $result = Invoke-GHGraphQl @params + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } + + $restrictPushActorIds += $result.data.user.id + } + } + + if ($PSBoundParameters.ContainsKey('RestrictPushTeam')) + { + foreach ($team in $RestrictPushTeam) + { + $teamDetail = $orgTeams | Where-Object -Property Name -eq $team + + if ($teamDetail.Count -eq 0) + { + $newErrorRecordParms = @{ + ErrorMessage = "Team '$team' not found in organization '$OrganizationName'" + ErrorId = 'RestrictPushTeamNotFound' + ErrorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound + TargetObject = $team + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + + $getGitHubRepositoryTeamPermissionParms = @{ + TeamSlug = $teamDetail.TeamSlug + OwnerName = $ownerName + RepositoryName = $repositoryName + Verbose = $false + } + + Write-Debug -Message "Getting GitHub Permissions for Team '$team' on Repository '$OwnerName/$RepositoryName'" + try + { + $teamPermission = Get-GitHubRepositoryTeamPermission @getGitHubRepositoryTeamPermissionParms + } + catch + { + Write-Debug -Message "Team '$team' has no permissions on Repository '$OwnerName/$RepositoryName'" + } + + if ($teamPermission.permissions.push -eq $true -or $teamPermission.permissions.maintain -eq $true) + { + $restrictPushActorIds += $teamDetail.node_id + } + else + { + $newErrorRecordParms = @{ + ErrorMessage = "Team '$team' does not have push or maintain permissions on repository '$OwnerName/$RepositoryName'" + ErrorId = 'RestrictPushTeamNoPermissions' + ErrorCategory = [System.Management.Automation.ErrorCategory]::PermissionDenied + TargetObject = $team + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + } + + if ($PSBoundParameters.ContainsKey('RestrictPushApp')) + { + foreach ($app in $RestrictPushApp) + { + $hashbody = @{query = "query app { marketplaceListing(slug: ""$app"") { app { id } } }" } + + $params = @{ + Body = ConvertTo-Json -InputObject $hashBody + Description = "Querying for app $app" + AccessToken = $AccessToken + TelemetryEventName = 'Get-GitHubAppQ1' + TelemetryProperties = $telemetryProperties + } + + try + { + $result = Invoke-GHGraphQl @params + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } + + if ($result.data.marketplaceListing) + { + $restrictPushActorIds += $result.data.marketplaceListing.app.id + } + else + { + $newErrorRecordParms = @{ + ErrorMessage = "App '$app' not found in GitHub Marketplace" + ErrorId = 'RestictPushAppNotFound' + ErrorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound + TargetObject = $app + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + } + + $mutationList += 'restrictsPushes: true' + $mutationList += 'pushActorIds: [ "' + ($restrictPushActorIds -join ('","')) + '" ]' + } + + if ($PSBoundParameters.ContainsKey('AllowForcePushes')) + { + $mutationList += 'allowsForcePushes: ' + $AllowForcePushes.ToBool().ToString().ToLower() + } + + if ($PSBoundParameters.ContainsKey('AllowDeletions')) + { + $mutationList += 'allowsDeletions: ' + $AllowDeletions.ToBool().ToString().ToLower() + } + + $mutationInput = $mutationList -join (',') + $hashbody = @{query = "mutation ProtectionRule { createBranchProtectionRule(input: { $mutationInput }) " + + "{ clientMutationId } } " + } + + $body = ConvertTo-Json -InputObject $hashBody + + if (-not $PSCmdlet.ShouldProcess( + "$OwnerName/$RepositoryName", + "Create GitHub Repository Branch Pattern Protection Rule '$BranchPatternName'")) + { + return + } + + $params = @{ + Body = $body + Description = "Creating GitHub Repository Branch Pattern Protection Rule '$BranchPatternName' on $OwnerName/$RepositoryName" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + try + { + $result = Invoke-GHGraphQl @params + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } +} + +filter Get-GitHubRepositoryBranchPatternProtectionRule +{ + <# + .SYNOPSIS + Retrieve a branch pattern protection rule for a given GitHub repository. + + .DESCRIPTION + Retrieve a branch pattern protection rule for a given GitHub repository. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER BranchPatternName + Name of the specific branch Pattern to be retrieved. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.Repository + + .OUTPUTS + GitHub.BranchPatternProtectionRule + + .EXAMPLE + Get-GitHubRepositoryBranchPatternProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchPatternName release/**/* + + Retrieves branch protection rules for the release/**/* branch pattern of the PowerShellForGithub repository. + + .EXAMPLE + Get-GitHubQlRepositoryBranchPatternProtectionRule -Uri 'https://github.com/microsoft/PowerShellForGitHub' -BranchPatternName master + + Retrieves branch protection rules for the master branch pattern of the PowerShellForGithub repository. +#> + [CmdletBinding( + PositionalBinding = $false, + DefaultParameterSetName = 'Elements')] + [OutputType( { $script:GitHubBranchProtectionRuleTypeName })] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", + Justification = "The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter(ParameterSetName = 'Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName = 'Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + Position = 1, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter(Position = 2)] + [string] $BranchPatternName, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $branchProtectionRuleFields = ('allowsDeletions allowsForcePushes dismissesStaleReviews id ' + + 'isAdminEnforced pattern requiredApprovingReviewCount requiredStatusCheckContexts ' + + 'requiresApprovingReviews requiresCodeOwnerReviews requiresCommitSignatures requiresLinearHistory ' + + 'requiresStatusChecks requiresStrictStatusChecks restrictsPushes restrictsReviewDismissals ' + + "pushAllowances(first: $script:MaxPushAllowances) { nodes { actor { ... on App { __typename name } " + + '... on Team { __typename name } ... on User { __typename login } } } }' + + "reviewDismissalAllowances(first: $script:MaxReviewDismissalAllowances)" + + '{ nodes { actor { ... on Team { __typename name } ... on User { __typename login } } } } ' + + 'repository { url }') + + $hashbody = @{query = "query branchProtectionRule { repository(name: ""$RepositoryName"", " + + "owner: ""$OwnerName"") { branchProtectionRules(first: $script:MaxProtectionRules) { nodes { " + + "$branchProtectionRuleFields } } } }"} + + $params = @{ + Body = ConvertTo-Json -InputObject $hashBody + Description = "Querying $OwnerName/$RepositoryName repository for branch protection rules" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + try + { + $result = Invoke-GHGraphQl @params + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } + + if ($result.data.repository.branchProtectionRules) + { + if ($PSBoundParameters.ContainsKey('BranchPatternName')) + { + $rule = ($result.data.repository.branchProtectionRules.nodes | + Where-Object -Property pattern -eq $BranchPatternName) + } + else + { + $rule = $result.data.repository.branchProtectionRules.nodes + } + } + + if (!$rule -and $PSBoundParameters.ContainsKey('BranchPatternName')) + { + $newErrorRecordParms = @{ + ErrorMessage = "Branch Protection Rule '$BranchPatternName' not found on repository '$OwnerName/$RepositoryName'" + ErrorId = 'BranchProtectionRuleNotFound' + ErrorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound + TargetObject = $BranchPatternName + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + + return ($rule | Add-GitHubBranchPatternProtectionRuleAdditionalProperties) +} + +filter Remove-GitHubRepositoryBranchPatternProtectionRule +{ + <# + .SYNOPSIS + Remove a branch pattern protection rule from a given GitHub repository. + + .DESCRIPTION + Remove a branch pattern protection rule from a given GitHub repository. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER BranchPatternName + Name of the specific branch protection rule pattern to remove. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Repository + + .OUTPUTS + None + + .EXAMPLE + Remove-GitHubRepositoryBranchPatternProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchPatternName release/**/* + + Removes branch pattern 'release/**/*' protection rules from the PowerShellForGithub repository. + + .EXAMPLE + Remove-GitHubRepositoryBranchPatternProtectionRule -Uri 'https://github.com/microsoft/PowerShellForGitHub' -BranchPatternName release/**/* + + Removes branch pattern 'release/**/*' protection rules from the PowerShellForGithub repository. + + .EXAMPLE + Remove-GitHubRepositoryBranchPatternProtectionRule -Uri 'https://github.com/master/PowerShellForGitHub' -BranchPatternName release/**/* -Force + + Removes branch pattern 'release/**/*' protection rules from the PowerShellForGithub repository + without prompting for confirmation. +#> + [CmdletBinding( + PositionalBinding = $false, + SupportsShouldProcess, + DefaultParameterSetName = 'Elements', + ConfirmImpact = "High")] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", + Justification = "The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1.")] + [Alias('Delete-GitHubRepositoryBranchPatternProtectionRule')] + param( + [Parameter(ParameterSetName = 'Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName = 'Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + Position = 1, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + Position = 2)] + [string] $BranchPatternName, + + [switch] $Force, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $hashbody = @{query = "query branchProtectionRule { repository(name: ""$RepositoryName"", " + + "owner: ""$OwnerName"") { branchProtectionRules(first: $script:MaxProtectionRules) { nodes { id pattern } } } }" + } + + $params = @{ + Body = ConvertTo-Json -InputObject $hashBody + Description = "Querying $OwnerName/$RepositoryName repository for branch protection rules" + AccessToken = $AccessToken + TelemetryEventName = 'Get-GitHubRepositoryQ1' + TelemetryProperties = $telemetryProperties + } + + try + { + $result = Invoke-GHGraphQl @params + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } + + if ($result.data.repository.branchProtectionRules) + { + $ruleId = ($result.data.repository.branchProtectionRules.nodes | + Where-Object -Property pattern -eq $BranchPatternName).id + } + + if (!$ruleId) + { + $newErrorRecordParms = @{ + ErrorMessage = "Branch Protection Rule '$BranchPatternName' not found on repository '$OwnerName/$RepositoryName'" + ErrorId = 'BranchProtectionRuleNotFound' + ErrorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound + TargetObject = $BranchPatternName + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + $hashbody = @{query = "mutation ProtectionRule { deleteBranchProtectionRule(input: " + + "{ branchProtectionRuleId: ""$ruleId"" } ) { clientMutationId } }" + } + + $body = ConvertTo-Json -InputObject $hashBody + + if (-not $PSCmdlet.ShouldProcess("$OwnerName/$RepositoryName", + "Remove GitHub Repository Branch Pattern Protection Rule '$BranchPatternName'")) + { + return + } + + $params = @{ + Body = $body + Description = "Removing GitHub Repository Branch Pattern Protection Rule '$BranchPatternName' from $OwnerName/$RepositoryName" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + try + { + $result = Invoke-GHGraphQl @params + } + catch + { + $PSCmdlet.ThrowTerminatingError($_) + } +} + +filter Add-GitHubBranchAdditionalProperties +{ +<# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Branch objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + [PSCustomObject] + + .OUTPUTS + GitHub.Branch +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Internal helper that is definitely adding more than one property.")] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubBranchTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + if ($null -ne $item.url) + { + $elements = Split-GitHubUri -Uri $item.url + } + else + { + $elements = Split-GitHubUri -Uri $item.commit.url + } + $repositoryUrl = Join-GitHubUri @elements + + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + + $branchName = $item.name + if ($null -eq $branchName) + { + $branchName = $item.ref -replace ('refs/heads/', '') + } + + Add-Member -InputObject $item -Name 'BranchName' -Value $branchName -MemberType NoteProperty -Force + + if ($null -ne $item.commit) + { + Add-Member -InputObject $item -Name 'Sha' -Value $item.commit.sha -MemberType NoteProperty -Force + } + elseif ($null -ne $item.object) + { + Add-Member -InputObject $item -Name 'Sha' -Value $item.object.sha -MemberType NoteProperty -Force + } + } + + Write-Output $item + } +} + +filter Add-GitHubBranchProtectionRuleAdditionalProperties +{ + <# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Branch Protection Rule objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + PSCustomObject + + .OUTPUTS + GitHub.Branch +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', + Justification = 'Internal helper that is definitely adding more than one property.')] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubBranchProtectionRuleTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + $elements = Split-GitHubUri -Uri $item.url + $repositoryUrl = Join-GitHubUri @elements + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + + $hostName = $(Get-GitHubConfiguration -Name 'ApiHostName') + + if ($item.url -match "^https?://(?:www\.|api\.|)$hostName/repos/(?:[^/]+)/(?:[^/]+)/branches/([^/]+)/.*$") + { + Add-Member -InputObject $item -Name 'BranchName' -Value $Matches[1] -MemberType NoteProperty -Force + } + } + + Write-Output $item + } +} + +filter Add-GitHubBranchPatternProtectionRuleAdditionalProperties +{ + <# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Branch Pattern Protection Rule objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + PSCustomObject + + .OUTPUTS + GitHub.BranchPatternProtection Rule +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', + Justification = 'Internal helper that is definitely adding more than one property.')] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubBranchPatternProtectionRuleTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + $elements = Split-GitHubUri -Uri $item.repository.url + $repositoryUrl = Join-GitHubUri @elements + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + } + + $restrictPushApps = @() + $restrictPushTeams = @() + $restrictPushUsers = @() + + foreach ($actor in $item.pushAllowances.nodes.actor) + { + if ($actor.__typename -eq 'App') + { + $restrictPushApps += $actor.name + } + elseif ($actor.__typename -eq 'Team') + { + $restrictPushTeams += $actor.name + } + elseif ($actor.__typename -eq 'User') + { + $restrictPushUsers += $actor.login + } + else + { + Write-Log -Message "Unknown restrict push actor type found $($actor.__typename). Ignoring" -Level Warning + } + } + + Add-Member -InputObject $item -Name 'RestrictPushApps' -Value $restrictPushApps -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'RestrictPushTeams' -Value $restrictPushTeams -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'RestrictPushUsers' -Value $restrictPushUsers -MemberType NoteProperty -Force + + $dismissalTeams = @() + $dismissalUsers = @() + + foreach ($actor in $item.reviewDismissalAllowances.nodes.actor) + { + if ($actor.__typename -eq 'Team') + { + $dismissalTeams += $actor.name + } + elseif ($actor.__typename -eq 'User') + { + $dismissalUsers += $actor.login + } + else + { + Write-Log -Message "Unknown dismissal actor type found $($actor.__typename). Ignoring" -Level Warning + } + } + + Add-Member -InputObject $item -Name 'DismissalTeams' -Value $dismissalTeams -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'DismissalUsers' -Value $dismissalUsers -MemberType NoteProperty -Force Write-Output $item } diff --git a/GitHubGraphQl.ps1 b/GitHubGraphQl.ps1 new file mode 100644 index 00000000..d8501fb2 --- /dev/null +++ b/GitHubGraphQl.ps1 @@ -0,0 +1,365 @@ +function Invoke-GHGraphQl +{ + <# + .SYNOPSIS + A wrapper around Invoke-WebRequest that understands the GitHub GraphQL API. + + .DESCRIPTION + A very heavy wrapper around Invoke-WebRequest that understands the GitHub QraphQL API. + It also understands how to parse and handle errors from the GraphQL calls. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER Description + A friendly description of the operation being performed for logging. + + .PARAMETER Body + This parameter forms the body of the request. It will be automatically + encoded to UTF8 and sent as Content Type: "application/json; charset=UTF-8" + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + GraphQL Api as opposed to requesting a new one. + + .PARAMETER TelemetryEventName + If provided, the successful execution of this GraphQL command will be logged to telemetry + using this event name. + + .PARAMETER TelemetryProperties + If provided, the successful execution of this GraphQL command will be logged to telemetry + with these additional properties. This will be silently ignored if TelemetryEventName + is not provided as well. + + .PARAMETER TelemetryExceptionBucket + If provided, any exception that occurs will be logged to telemetry using this bucket. + It's possible that users will wish to log exceptions but not success (by providing + TelemetryEventName) if this is being executed as part of a larger scenario. If this + isn't provided, but TelemetryEventName *is* provided, then TelemetryEventName will be + used as the exception bucket value in the event of an exception. If neither is specified, + no bucket value will be used. + + .OUTPUTS + PSCustomObject + + .EXAMPLE + Invoke-GHGraphQl + + .NOTES + This wraps Invoke-WebRequest as opposed to Invoke-RestMethod because we want access + to the headers that are returned in the response, and Invoke-RestMethod drops those headers. +#> + [CmdletBinding()] + [OutputType([System.Management.Automation.ErrorRecord])] + param( + [string] $Description, + + [Parameter(Mandatory)] + [string] $Body, + + [string] $AccessToken, + + [string] $TelemetryEventName = $null, + + [hashtable] $TelemetryProperties = @{}, + + [string] $TelemetryExceptionBucket = $null + ) + + Invoke-UpdateCheck + + # Telemetry-related + $stopwatch = New-Object -TypeName System.Diagnostics.Stopwatch + $localTelemetryProperties = @{} + $TelemetryProperties.Keys | ForEach-Object { $localTelemetryProperties[$_] = $TelemetryProperties[$_] } + $errorBucket = $TelemetryExceptionBucket + if ([String]::IsNullOrEmpty($errorBucket)) + { + $errorBucket = $TelemetryEventName + } + + $stopwatch.Start() + + $hostName = $(Get-GitHubConfiguration -Name 'ApiHostName') + + if ($hostName -eq 'github.com') + { + $url = "https://api.$hostname/graphql" + } + else + { + $url = "https://$hostname/api/v3/graphql" + } + + $headers = @{ + 'User-Agent' = 'PowerShellForGitHub' + } + + $AccessToken = Get-AccessToken -AccessToken $AccessToken + if (-not [String]::IsNullOrEmpty($AccessToken)) + { + $headers['Authorization'] = "token $AccessToken" + } + + $timeOut = Get-GitHubConfiguration -Name WebRequestTimeoutSec + $method = 'Post' + + Write-Log -Message $Description -Level Debug + Write-Log -Message "Accessing [$method] $url [Timeout = $timeOut]" -Level Debug + + if (Get-GitHubConfiguration -Name LogRequestBody) + { + Write-Log -Message $Body -Level Debug + } + + $bodyAsBytes = [System.Text.Encoding]::UTF8.GetBytes($Body) + + # Disable Progress Bar in function scope during Invoke-WebRequest + $ProgressPreference = 'SilentlyContinue' + + # Save Current Security Protocol + $originalSecurityProtocol = [Net.ServicePointManager]::SecurityProtocol + + # Enforce TLS v1.2 Security Protocol + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + + $invokeWebRequestParms = @{ + Uri = $url + Method = $method + Headers = $headers + Body = $bodyAsBytes + UseDefaultCredentials = $true + UseBasicParsing = $true + TimeoutSec = $timeOut + Verbose = $false + } + + try + { + $result = Invoke-WebRequest @invokeWebRequestParms + } + catch + { + $ex = $_.Exception + + <# + PowerShell 5 Invoke-WebRequest returns a 'System.Net.WebException' object on error. + PowerShell 6+ Invoke-WebRequest returns a 'Microsoft.PowerShell.Commands.HttpResponseException' or + a 'System.Net.Http.HttpRequestException' object on error. + #> + + if ($ex.PSTypeNames[0] -eq 'System.Net.Http.HttpRequestException') + { + Write-Debug -Message "Processing PowerShell Core 'System.Net.Http.HttpRequestException'" + + $newErrorRecordParms = @{ + ErrorMessage = $ex.Message + ErrorId = $_.FullyQualifiedErrorId + ErrorCategory = $_.CategoryInfo.Category + TargetObject = $_.TargetObject + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + Set-TelemetryException -Exception $ex -ErrorBucket $errorBucket -Properties $localTelemetryProperties + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + elseif ($ex.PSTypeNames[0] -eq 'Microsoft.PowerShell.Commands.HttpResponseException' -or + $ex.PSTypeNames[0] -eq 'System.Net.WebException') + { + Write-Debug -Message "Processing '$($ex.PSTypeNames[0])'" + + $errorMessage = @() + $errorMessage += $ex.Message + + $errorDetailsMessage = $_.ErrorDetails.Message + + if (-not [string]::IsNullOrEmpty($errorDetailsMessage)) + { + Write-Debug -Message "Processing Error Details message '$errorDetailsMessage'" + + try + { + Write-Debug -Message 'Checking Error Details message for JSON content' + + $errorDetailsMessageJson = $errorDetailsMessage | ConvertFrom-Json + } + catch [System.ArgumentException] + { + # Will be thrown if $errorDetailsMessage isn't JSON content + Write-Debug -Message 'No Error Details Message JSON content Found' + + $errorDetailsMessageJson = $false + } + + if ($errorDetailsMessageJson) + { + Write-Debug -Message 'Adding Error Details Message JSON content to output' + Write-Debug -Message "Error Details Message: $($errorDetailsMessageJson.message)" + Write-Debug -Message "Error Details Documentation URL: $($errorDetailsMessageJson.documentation_url)" + + $errorMessage += ($errorDetailsMessageJson.message.Trim() + + ' | ' + $errorDetailsMessageJson.documentation_url.Trim()) + + if ($errorDetailsMessageJson.details) + { + $errorMessage += $errorDetailsMessageJson.details | Format-Table | Out-String + } + } + else + { + # In this case, it's probably not a normal message from the API + Write-Debug -Message 'Adding Error Details Message String to output' + + $errorMessage += $_.ErrorDetails.Message | Out-String + } + } + + if (-not [System.String]::IsNullOrEmpty($ex.Response)) + { + Write-Debug -Message "Processing '$($ex.Response.PSTypeNames[0])' Object" + + <# + PowerShell 5.x returns a 'System.Net.HttpWebResponse' exception response object and + PowerShell 6+ returns a 'System.Net.Http.HttpResponseMessage' exception response object. + #> + + $requestId = '' + + if ($ex.Response.PSTypeNames[0] -eq 'System.Net.HttpWebResponse') + { + if (($ex.Response.Headers.Count -gt 0) -and + (-not [System.String]::IsNullOrEmpty($ex.Response.Headers['X-GitHub-Request-Id']))) + { + $requestId = $ex.Response.Headers['X-GitHub-Request-Id'] + } + } + elseif ($ex.Response.PSTypeNames[0] -eq 'System.Net.Http.HttpResponseMessage') + { + $requestId = ($ex.Response.Headers | Where-Object -Property Key -eq 'X-GitHub-Request-Id').Value + } + + if (-not [System.String]::IsNullOrEmpty($requestId)) + { + Write-Debug -Message "GitHub RequestID '$requestId' in response header" + + $localTelemetryProperties['RequestId'] = $requestId + $requestIdMessage += "RequestId: $requestId" + $errorMessage += $requestIdMessage + + Write-Log -Message $requestIdMessage -Level Debug + } + } + + $newErrorRecordParms = @{ + ErrorMessage = $errorMessage -join [Environment]::NewLine + ErrorId = $_.FullyQualifiedErrorId + ErrorCategory = $_.CategoryInfo.Category + TargetObject = $Body + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + Set-TelemetryException -Exception $ex -ErrorBucket $errorBucket -Properties $localTelemetryProperties + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + else + { + Write-Debug -Message "Processing Other Exception '$($ex.PSTypeNames[0])'" + + $newErrorRecordParms = @{ + ErrorMessage = $ex.Message + ErrorId = $_.FullyQualifiedErrorId + ErrorCategory = $_.CategoryInfo.Category + TargetObject = $body + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errorRecord -Level Error + Set-TelemetryException -Exception $ex -ErrorBucket $errorBucket -Properties $localTelemetryProperties + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + } + finally + { + # Restore original security protocol + [Net.ServicePointManager]::SecurityProtocol = $originalSecurityProtocol + } + + # Record the telemetry for this event. + $stopwatch.Stop() + if (-not [String]::IsNullOrEmpty($TelemetryEventName)) + { + $telemetryMetrics = @{ 'Duration' = $stopwatch.Elapsed.TotalSeconds } + Set-TelemetryEvent -EventName $TelemetryEventName -Properties $localTelemetryProperties -Metrics $telemetryMetrics -Verbose:$false + } + + Write-Debug -Message "GraphQl result: '$($result.Content)'" + + $graphQlResult = $result.Content | ConvertFrom-Json + + if ($graphQlResult.errors) + { + Write-Debug -Message "GraphQl Error: $($graphQLResult.errors | Out-String)" + + if (-not [System.String]::IsNullOrEmpty($graphQlResult.errors[0].type)) + { + $errorId = $graphQlResult.errors[0].type + switch ($errorId) + { + 'NOT_FOUND' + { + Write-Debug -Message "GraphQl Error Type: $errorId" + + $errorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound + } + + Default + { + Write-Debug -Message "GraphQL Unknown Error Type: $errorId" + + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidOperation + } + } + } + else + { + Write-Debug -Message "GraphQl Unspecified Error" + + $errorId = 'UnspecifiedError' + $errorCategory = [System.Management.Automation.ErrorCategory]::NotSpecified + } + + $errorMessage = @() + $errorMessage += "GraphQl Error: $($graphQlResult.errors[0].message)" + + if ($result.Headers.Count -gt 0 -and + -not [System.String]::IsNullOrEmpty($result.Headers['X-GitHub-Request-Id'])) + { + $requestId = $result.Headers['X-GitHub-Request-Id'] + + $requestIdMessage += "RequestId: $requestId" + $errorMessage += $requestIdMessage + + Write-Log -Message $requestIdMessage -Level Debug + } + + $newErrorRecordParms = @{ + ErrorMessage = $errorMessage -join [Environment]::NewLine + ErrorId = $errorId + ErrorCategory = $errorCategory + TargetObject = $Body + } + $errorRecord = New-ErrorRecord @newErrorRecordParms + + Write-Log -Exception $errrorRecord -Level Error + + $PSCmdlet.ThrowTerminatingError($errorRecord) + } + else + { + return $graphQlResult + } +} diff --git a/Helpers.ps1 b/Helpers.ps1 index 4e9116da..d915140c 100644 --- a/Helpers.ps1 +++ b/Helpers.ps1 @@ -663,3 +663,55 @@ function Get-HttpWebResponseContent } } } + +function New-ErrorRecord +{ +<# + .SYNOPSIS + Returns an ErrorRecord object for use by $PSCmdlet.ThrowTerminatingError + + .DESCRIPTION + Returns an ErrorRecord object for use by $PSCmdlet.ThrowTerminatingError + + .PARAMETER ErrorMessage + The message that describes the error + + .PARAMETER ErrorId + The Id to be used to construct the FullyQualifiedErrorId property of the error record. + + .PARAMETER ErrorCategory + This is the ErrorCategory which best describes the error. + + .PARAMETER TargetObject + This is the object against which the cmdlet was operating when the error occurred. This is optional. + + .OUTPUTS + System.Management.Automation.ErrorRecord + + .NOTES + ErrorRecord Class - https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.errorrecord + Exception Class - https://docs.microsoft.com/en-us/dotnet/api/system.exception + Cmdlet.ThrowTerminationError - https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.cmdlet.throwterminatingerror +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', + Justification = 'This function is non state changing.')] + [OutputType([System.Management.Automation.ErrorRecord])] + param( + [Parameter(Mandatory)] + [System.String] $ErrorMessage, + + [System.String] $ErrorId, + + [Parameter(Mandatory)] + [System.Management.Automation.ErrorCategory] $ErrorCategory, + + [System.Management.Automation.PSObject] $TargetObject + ) + + $exception = New-Object -TypeName System.Exception -ArgumentList $ErrorMessage + $errorRecordArgumentList = $exception, $ErrorId, $ErrorCategory, $TargetObject + $errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $errorRecordArgumentList + + return $errorRecord +} diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 73f2bd10..44369427 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -15,6 +15,7 @@ # Format files (.ps1xml) to be loaded when importing this module FormatsToProcess = @( + 'Formatters/GitHubBranches.Format.ps1xml', 'Formatters/GitHubGistComments.Format.ps1xml', 'Formatters/GitHubGists.Format.ps1xml', 'Formatters/GitHubReleases.Format.ps1xml' @@ -37,6 +38,7 @@ 'GitHubEvents.ps1', 'GitHubGistComments.ps1', 'GitHubGists.ps1', + 'GitHubGraphQl.ps1', 'GitHubIssueComments.ps1', 'GitHubIssues.ps1', 'GitHubLabels.ps1', @@ -103,6 +105,7 @@ 'Get-GitHubRepository', 'Get-GitHubRepositoryActionsPermission', 'Get-GitHubRepositoryBranch', + 'Get-GitHubRepositoryBranchPatternProtectionRule', 'Get-GitHubRepositoryBranchProtectionRule', 'Get-GitHubRepositoryCollaborator', 'Get-GitHubRepositoryContributor', @@ -120,6 +123,7 @@ 'Group-GitHubIssue', 'Group-GitHubPullRequest', 'Initialize-GitHubLabel', + 'Invoke-GHGraphQl', 'Invoke-GHRestMethod', 'Invoke-GHRestMethodMultipleResult', 'Join-GitHubUri', @@ -142,6 +146,7 @@ 'New-GitHubRepository', 'New-GitHubRepositoryFromTemplate', 'New-GitHubRepositoryBranch', + 'New-GitHubRepositoryBranchPatternProtectionRule', 'New-GitHubRepositoryBranchProtectionRule', 'New-GitHubRepositoryFork', 'New-GitHubTeam', @@ -163,6 +168,7 @@ 'Remove-GitHubReleaseAsset', 'Remove-GitHubRepository', 'Remove-GitHubRepositoryBranch' + 'Remove-GitHubRepositoryBranchPatternProtectionRule', 'Remove-GitHubRepositoryBranchProtectionRule', 'Remove-GitHubRepositoryTeamPermission', 'Remove-GitHubTeam', @@ -223,6 +229,7 @@ 'Delete-GitHubReleaseAsset', 'Delete-GitHubRepository', 'Delete-GitHubRepositoryBranch', + 'Delete-GitHubRepositoryBranchPatternProtectionRule', 'Delete-GitHubRepositoryBranchProtectionRule', 'Delete-GitHubRepositoryTeamPermission', 'Delete-GitHubTeam', diff --git a/Tests/Common.ps1 b/Tests/Common.ps1 index d7ced214..fc89f781 100644 --- a/Tests/Common.ps1 +++ b/Tests/Common.ps1 @@ -41,6 +41,7 @@ function Initialize-CommonTestSetup [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification="Needed to configure with the stored, encrypted string value in Azure DevOps.")] param() + $script:moduleName = 'PowerShellForGitHub' $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent $settingsPath = Join-Path -Path $moduleRootPath -ChildPath 'Tests/Config/Settings.ps1' . $settingsPath diff --git a/Tests/GitHubBranches.tests.ps1 b/Tests/GitHubBranches.tests.ps1 index 78768d12..21d55f6d 100644 --- a/Tests/GitHubBranches.tests.ps1 +++ b/Tests/GitHubBranches.tests.ps1 @@ -611,7 +611,7 @@ try $newGitHubRepositoryBranchProtectionParms = @{ Uri = $repo.svn_url BranchName = $targetBranchName - RestrictPushUsers = $script:OwnerName + RestrictPushUser = $script:OwnerName } $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms @@ -782,6 +782,584 @@ try } } + Describe 'GitHubBranches\Get-GitHubRepositoryBranchPatternProtectionRule' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + + $newGitHubRepositoryParms = @{ + OrganizationName = $script:organizationName + RepositoryName = $repoName + } + $repo = New-GitHubRepository @newGitHubRepositoryParms + + $teamName = [Guid]::NewGuid().Guid + + $newGithubTeamParms = @{ + OrganizationName = $script:OrganizationName + TeamName = $teamName + } + $team = New-GitHubTeam @newGithubTeamParms + + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = 'Push' + } + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + } + + Context 'When getting branch pattern protection default options' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + } + + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeFalse + $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty + $rule.dismissesStaleReviews | Should -BeFalse + $rule.requiresCodeOwnerReviews | Should -BeFalse + $rule.restrictsReviewDismissals | Should -BeFalse + $rule.DismissalTeams | Should -BeNullOrEmpty + $rule.DismissalUsers | Should -BeNullOrEmpty + $rule.requiresStatusChecks | Should -BeFalse + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty + $rule.requiresCommitSignatures | Should -BeFalse + $rule.requiresLinearHistory | Should -BeFalse + $rule.isAdminEnforced | Should -BeFalse + $rule.restrictsPushes | Should -BeFalse + $rule.RestrictPushUsers | Should -BeNullOrEmpty + $rule.RestrictPushTeams | Should -BeNullOrEmpty + $rule.RestictPushApps | Should -BeNullOrEmpty + $rule.allowsForcePushes | Should -BeFalse + $rule.allowsDeletions | Should -BeFalse + } + } + + Context 'When getting base protection options' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequireCommitSignatures = $true + RequireLinearHistory = $true + IsAdminEnforced = $true + RestrictPushUser = $script:OwnerName + RestrictPushTeam = $TeamName + AllowForcePushes = $true + AllowDeletions = $true + } + New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms + + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + } + + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeFalse + $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty + $rule.dismissesStaleReviews | Should -BeFalse + $rule.requiresCodeOwnerReviews | Should -BeFalse + $rule.restrictsReviewDismissals | Should -BeFalse + $rule.DismissalTeams | Should -BeNullOrEmpty + $rule.DismissalUsers | Should -BeNullOrEmpty + $rule.requiresStatusChecks | Should -BeFalse + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty + $rule.requiresCommitSignatures | Should -BeTrue + $rule.requiresLinearHistory | Should -BeTrue + $rule.isAdminEnforced | Should -BeTrue + $rule.restrictsPushes | Should -BeTrue + $rule.RestrictPushUsers.Count | Should -Be 1 + $rule.RestrictPushUsers | Should -Contain $script:OwnerName + $rule.RestrictPushTeams.Count | Should -Be 1 + $rule.RestrictPushTeams | Should -Contain $teamName + $rule.RestrictPushApps | Should -BeNullOrEmpty + $rule.allowsForcePushes | Should -BeTrue + $rule.allowsDeletions | Should -BeTrue + } + } + + Context 'When getting required pull request reviews' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequiredApprovingReviewCount = 1 + DismissStaleReviews = $true + RequireCodeOwnerReviews = $true + DismissalUser = $script:OwnerName + DismissalTeam = $teamName + } + New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms + + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + } + + It 'Should have the expected type and addititional properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeTrue + $rule.requiredApprovingReviewCount | Should -Be 1 + $rule.dismissesStaleReviews | Should -BeTrue + $rule.requiresCodeOwnerReviews | Should -BeTrue + $rule.restrictsReviewDismissals | Should -BeTrue + $rule.DismissalTeams.Count | Should -Be 1 + $rule.DismissalTeams | Should -Contain $teamName + $rule.DismissalUsers.Count | Should -Be 1 + $rule.DismissalUsers | Should -Contain $script:OwnerName + } + } + + Context 'When getting required status checks' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + $statusChecks = 'test' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequireStrictStatusChecks = $true + StatusCheck = $statusChecks + } + New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms + + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + } + + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresStatusChecks | Should -BeTrue + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -Contain $statusChecks + } + } + + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $rule = $repo | Get-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName + } + + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + } + } + + AfterAll -ScriptBlock { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } + + Describe 'GitHubBranches\New-GitHubRepositoryBranchPatternProtectionRule' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + + $newGitHubRepositoryParms = @{ + OrganizationName = $script:organizationName + RepositoryName = $repoName + } + $repo = New-GitHubRepository @newGitHubRepositoryParms + + $pushTeamName = [Guid]::NewGuid().Guid + + $newGithubTeamParms = @{ + OrganizationName = $script:OrganizationName + TeamName = $pushTeamName + } + $pushTeam = New-GitHubTeam @newGithubTeamParms + + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $pushTeam.slug + Permission = 'Push' + } + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + + $pullTeamName = [Guid]::NewGuid().Guid + + $newGithubTeamParms = @{ + OrganizationName = $script:OrganizationName + TeamName = $pullTeamName + } + $pullTeam = New-GitHubTeam @newGithubTeamParms + + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $pullTeam.slug + + Permission = 'Pull' + } + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + } + + Context 'When setting default protection options' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + } + } + + It 'Should not throw' { + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Not -Throw + } + + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeFalse + $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty + $rule.dismissesStaleReviews | Should -BeFalse + $rule.requiresCodeOwnerReviews | Should -BeFalse + $rule.restrictsReviewDismissals | Should -BeFalse + $rule.DismissalTeams | Should -BeNullOrEmpty + $rule.DismissalUsers | Should -BeNullOrEmpty + $rule.requiresStatusChecks | Should -BeFalse + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty + $rule.requiresCommitSignatures | Should -BeFalse + $rule.requiresLinearHistory | Should -BeFalse + $rule.isAdminEnforced | Should -BeFalse + $rule.restrictsPushes | Should -BeFalse + $rule.RestrictPushUsers | Should -BeNullOrEmpty + $rule.RestrictPushTeams | Should -BeNullOrEmpty + $rule.RestictPushApps | Should -BeNullOrEmpty + $rule.allowsForcePushes | Should -BeFalse + $rule.allowsDeletions | Should -BeFalse + } + } + + Context 'When setting base protection options' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequireCommitSignatures = $true + RequireLinearHistory = $true + IsAdminEnforced = $true + RestrictPushUser = $script:OwnerName + RestrictPushTeam = $pushTeamName + AllowForcePushes = $true + AllowDeletions = $true + } + } + + It 'Should not throw' { + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Not -Throw + } + + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeFalse + $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty + $rule.dismissesStaleReviews | Should -BeFalse + $rule.requiresCodeOwnerReviews | Should -BeFalse + $rule.restrictsReviewDismissals | Should -BeFalse + $rule.DismissalTeams | Should -BeNullOrEmpty + $rule.DismissalUsers | Should -BeNullOrEmpty + $rule.requiresStatusChecks | Should -BeFalse + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty + $rule.requiresCommitSignatures | Should -BeTrue + $rule.requiresLinearHistory | Should -BeTrue + $rule.isAdminEnforced | Should -BeTrue + $rule.restrictsPushes | Should -BeTrue + $rule.RestrictPushUsers.Count | Should -Be 1 + $rule.RestrictPushUsers | Should -Contain $script:OwnerName + $rule.RestrictPushTeams.Count | Should -Be 1 + $rule.RestrictPushTeams | Should -Contain $pushTeamName + $rule.RestrictPushApps | Should -BeNullOrEmpty + $rule.allowsForcePushes | Should -BeTrue + $rule.allowsDeletions | Should -BeTrue + } + + Context 'When the Restrict Push Team does not exist in the organization' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + $mockTeamName = 'MockTeam' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RestrictPushTeam = $mockTeamName + } + } + + It 'Should throw the correct exception' { + $errorMessage = "Team '$mockTeamName' not found in organization '$OrganizationName'" + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Throw $errorMessage + } + } + + Context 'When the Restrict Push Team does not have push Permissions to the Repository' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RestrictPushTeam = $pullTeamName + } + } + + It 'Should throw the correct exception' { + $errorMessage = "Team '$pullTeamName' does not have push or maintain permissions on repository '$OrganizationName/$repoName'" + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Throw $errorMessage + } + } + } + + Context 'When setting required pull request reviews' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequiredApprovingReviewCount = 1 + DismissStaleReviews = $true + RequireCodeOwnerReviews = $true + DismissalUser = $script:OwnerName + DismissalTeam = $pushTeamName + } + } + + It 'Should not throw' { + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Not -Throw + } + + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeTrue + $rule.requiredApprovingReviewCount | Should -Be 1 + $rule.dismissesStaleReviews | Should -BeTrue + $rule.requiresCodeOwnerReviews | Should -BeTrue + $rule.restrictsReviewDismissals | Should -BeTrue + $rule.DismissalTeams.Count | Should -Be 1 + $rule.DismissalTeams | Should -Contain $pushTeamName + $rule.DismissalUsers.Count | Should -Be 1 + $rule.DismissalUsers | Should -Contain $script:OwnerName + } + + Context 'When the Dismissal Team does not exist in the organization' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + $mockTeamName = 'MockTeam' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + DismissalTeam = $mockTeamName + } + } + + It 'Should throw the correct exception' { + $errorMessage = "Team '$mockTeamName' not found in organization '$OrganizationName'" + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Throw $errorMessage + } + } + + Context 'When the Dismissal Team does not have write Permissions to the Repository' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + DismissalTeam = $pullTeamName + } + } + + It 'Should throw the correct exception' { + $errorMessage = "Team '$pullTeamName' does not have push or maintain permissions on repository '$OrganizationName/$repoName'" + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Throw $errorMessage + } + } + } + + Context 'When setting required status checks' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + $statusCheck = 'test' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequireStrictStatusChecks = $true + StatusCheck = $statusCheck + } + } + + It 'Should not throw' { + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Not -Throw + } + + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresStatusChecks | Should -BeTrue + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -Contain $statusCheck + } + } + + Context 'When the branch pattern rule already exists' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + } + $rule = New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms + } + + It 'Should throw the correct exception' { + $errorMessage = "Name already protected: $branchPatternName" + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Throw $errorMessage + } + } + + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + } + + It 'Should not throw' { + { $repo | New-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName } | + Should -Not -Throw + } + + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + } + } + + AfterAll -ScriptBlock { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + + if (Get-Variable -Name pushTeam -ErrorAction SilentlyContinue) + { + $pushTeam | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name pullTeam -ErrorAction SilentlyContinue) + { + $pullTeam | Remove-GitHubTeam -Force + } + } + } + + Describe 'GitHubBranches\Remove-GitHubRepositoryBranchPatternProtectionRule' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + + $repo = New-GitHubRepository -RepositoryName $repoName + } + + Context 'When removing GitHub repository branch pattern protection' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + } + + It 'Should not throw' { + { Remove-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName -Force } | + Should -Not -Throw + } + + It 'Should have removed the protection rule' { + { Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } | + Should -Throw + } + } + + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + $rule = New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + } + + It 'Should not throw' { + { $repo | Remove-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName -Force} | + Should -Not -Throw + } + + It 'Should have removed the protection rule' { + { Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } | + Should -Throw + } + } + + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } + } } finally { diff --git a/Tests/GitHubGraphQl.Tests.ps1 b/Tests/GitHubGraphQl.Tests.ps1 new file mode 100644 index 00000000..0c94719b --- /dev/null +++ b/Tests/GitHubGraphQl.Tests.ps1 @@ -0,0 +1,237 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# +.Synopsis + Tests for GitHubGraphQl.ps1 module +#> + +[CmdletBinding()] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', + Justification='Suppress false positives in Pester code blocks')] +param() + +# This is common test code setup logic for all Pester test files +$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent +. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') + +try +{ + Describe 'GitHubCore/Invoke-GHGraphQl' { + BeforeAll { + $Description = 'description' + $AccessToken = '' + $TelemetryEventName = $null + $TelemetryProperties = @{} + $TelemetryExceptionBucket = $null + + Mock -CommandName Invoke-UpdateCheck -ModuleName $script:moduleName + } + + Context 'When a valid query is specified' { + BeforeAll { + $testBody = '{ "query": "query login { viewer { login } }" }' + } + + It 'Should return the expected result' { + $invokeGHGraphQLParms = @{ + Body = $testBody + } + $result = Invoke-GHGraphQl @invokeGHGraphQLParms + + $result.data.viewer.login | Should -Be $script:ownerName + } + + It 'Should call the expected mocks' { + Assert-MockCalled -CommandName Invoke-UpdateCheck ` + -ModuleName $script:moduleName ` + -Exactly -Times 1 + } + } + + Context 'When there is a Web/HTTP Request exception in Invoke-WebRequest' { + BeforeAll { + $testHostName = 'invalidhostname' + $testBody = 'testBody' + + if ($PSVersionTable.PSEdition -eq 'Core') + { + # The exception message varies per platform. We could special-case it, but the exact message + # may change over time and the module itself doesn't care about the specific message. + # We'll just do a best-case match. + # Windows: "No such host is known. ($($testHostName):443)" + # Mac: "nodename nor servname provided, or not known ($($testHostName):443)" + # Linux: "Resource temporarily unavailable ($($testHostName):443)" + $exceptionMessage = "*$testHostName*" + $categoryInfo = 'InvalidOperation' + $targetName = "*$testHostName*" + } + else + { + $exceptionMessage = "The remote name could not be resolved: '$testHostName'" + $categoryInfo = 'NotSpecified' + $targetName = $testBody + } + + Mock -CommandName Get-GitHubConfiguration -ModuleName $script:moduleName ` + -ParameterFilter { $Name -eq 'ApiHostName' } ` + -MockWith { 'invalidhostname' } + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody + } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | + Should -Throw + + $Error[0].Exception.Message | Should -BeLike $exceptionMessage + $Error[0].CategoryInfo.Category | Should -Be $categoryInfo + $Error[0].CategoryInfo.TargetName | Should -BeLike $targetName + $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' + } + } + + Context 'When there is a Web/HTTP Response exception in Invoke-WebRequest' { + Context 'When there is invalid JSON in the request body' { + BeforeAll { + $testBody = 'InvalidJson' + + if ($PSVersionTable.PSEdition -eq 'Core') + { + $exceptionMessage1 = '*Response status code does not indicate success: 400 (Bad Request)*' + } + else + { + $exceptionMessage1 = '*The remote server returned an error: (400) Bad Request*' + } + + $exceptionMessage2 = '*Problems parsing JSON | https://docs.github.com/graphql*' + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody + } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | + Should -Throw + + $Error[0].Exception.Message | Should -BeLike $exceptionMessage1 + $Error[0].Exception.Message | Should -BeLike $exceptionMessage2 + $Error[0].Exception.Message | Should -BeLike '*RequestId:*' + $Error[0].CategoryInfo.Category | Should -Be 'InvalidOperation' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody + $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' + } + } + + Context 'When the query user is not authenticated' { + BeforeAll { + $testBody = '{ "query": "query login { viewer { login } }" }' + + if ($PSVersionTable.PSEdition -eq 'Core') + { + $exceptionMessage1 = '*Response status code does not indicate success: 401 (Unauthorized)*' + } + else + { + $exceptionMessage1 = '*The remote server returned an error: (401) Unauthorized*' + } + + $exceptionMessage2 = '*This endpoint requires you to be authenticated.*' + + Mock -CommandName Get-AccessToken -ModuleName $script:moduleName + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody + } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | + Should -Throw + + $Error[0].Exception.Message | Should -BeLike $exceptionMessage1 + $Error[0].Exception.Message | Should -BeLike $exceptionMessage2 + $Error[0].Exception.Message | Should -BeLike '*RequestId:*' + $Error[0].CategoryInfo.Category | Should -Be 'InvalidOperation' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody + $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' + } + } + } + + Context 'When there is an other exception in Invoke-WebRequest' { + BeforeAll { + $testWebRequestTimeoutSec = 'invalid' + $testBody = 'testBody' + + Mock -CommandName Get-GitHubConfiguration -ModuleName $script:moduleName ` + -ParameterFilter { $Name -eq 'WebRequestTimeoutSec' } ` + -MockWith { 'invalid' } + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody + } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | + Should -Throw "Cannot convert value ""$testWebRequestTimeoutSec""" + + $Error[0].CategoryInfo.Category | Should -Be 'InvalidArgument' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody + $Error[0].FullyQualifiedErrorId | Should -BeLike 'CannotConvertArgumentNoMessage*' + } + } + + Context 'When the GraphQl JSON Query is Invalid' { + BeforeAll { + $invalidQuery = 'InvalidQuery' + $testBody = "{ ""query"":""$invalidQuery"" }" + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody + } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | Should -Throw + + $Error[0].Exception.Message | Should -BeLike "*Parse error on ""$invalidQuery""*" + $Error[0].Exception.Message | Should -BeLike '*RequestId:*' + $Error[0].CategoryInfo.Category | Should -Be 'NotSpecified' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody + $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' + } + } + + Context 'When the GraphQl JSON query returns an error of ''NOT_FOUND''' { + BeforeAll { + $testOwner = 'microsoft' + $testRepo = 'nonexisting-repo' + $testQuery = "query repo { repository(name: \""$testRepo\"", owner: \""$testOwner\"") { id } }" + $testBody = "{ ""query"": ""$testQuery"" }" + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody + } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | Should -Throw + + $Error[0].Exception.Message | Should -BeLike "*Could not resolve to a Repository with the name '$testOwner/$testRepo'*" + $Error[0].Exception.Message | Should -BeLike '*RequestId:*' + $Error[0].CategoryInfo.Category | Should -Be 'ObjectNotFound' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody + $Error[0].FullyQualifiedErrorId | Should -Be 'NOT_FOUND,Invoke-GHGraphQl' + } + } + } +} +finally +{ + if (Test-Path -Path $script:originalConfigFile -PathType Leaf) + { + # Restore the user's configuration to its pre-test state + Restore-GitHubConfiguration -Path $script:originalConfigFile + $script:originalConfigFile = $null + } +} diff --git a/USAGE.md b/USAGE.md index e3b9ad51..82a076e3 100644 --- a/USAGE.md +++ b/USAGE.md @@ -64,6 +64,9 @@ * [Getting a repository branch protection rule](#getting-a-repository-branch-protection-rule) * [Creating a repository branch protection rule](#creating-a-repository-branch-protection-rule) * [Removing a repository branch protection rule](#removing-a-repository-branch-protection-rule) + * [Getting a repository branch pattern protection rule](#getting-a-repository-branch-pattern-protection-rule) + * [Creating a repository branch pattern protection rule](#creating-a-repository-branch-pattern-protection-rule) + * [Removing a repository branch pattern protection rule](#removing-a-repository-branch-pattern-protection-rule) * [Forks](#forks) * [Get all the forks for a repository](#get-all-the-forks-for-a-repository) * [Create a new fork](#create-a-new-fork) @@ -703,6 +706,24 @@ New-GitHubRepositoryBranchProtectionRule -OwnerName microsoft -RepositoryName Po Remove-GitHubRepositoryBranchProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchName master ``` +#### Getting a repository branch pattern protection rule + +```powershell +Get-GitHubRepositoryBranchPatternProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchPatternName 'Release/**/*' +``` + +#### Creating a repository branch pattern protection rule + +```powershell +New-GitHubRepositoryBranchPatternProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchPatternName 'Release/**/*' -RequiredApprovingReviewCount 1 -DismissStaleReviews -RequireStrictStatusChecks -StatusCheck 'CICheck' +``` + +#### Removing a repository branch pattern protection rule + +```powershell +Remove-GitHubRepositoryBranchPatternProtectionRule -OwnerName microsoft -RepositoryName PowerShellForGitHub -BranchPatternName 'Release/**/*' +``` + ---------- ### Forks From 8b46226ba5347155470c2d789ef2356e4aef118a Mon Sep 17 00:00:00 2001 From: Matt Gucci Date: Sat, 25 Sep 2021 10:13:36 +0900 Subject: [PATCH 28/51] Fix help: Set-GitHubConfiguration -DefaultRepositoryName (#341) Would be a copy-paste error from `-DefaultOwnerName `. --- GitHubConfiguration.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GitHubConfiguration.ps1 b/GitHubConfiguration.ps1 index 70e57d6d..5c1f74c4 100644 --- a/GitHubConfiguration.ps1 +++ b/GitHubConfiguration.ps1 @@ -87,7 +87,7 @@ function Set-GitHubConfiguration -PassThru:$false on an individual command. .PARAMETER DefaultRepositoryName - The owner name that should be used with a command that takes RepositoryName as a parameter + The repository name that should be used with a command that takes RepositoryName as a parameter when no value has been supplied. .PARAMETER DisableLogging From fe881f683041bf7eb4f0e1b6d3b41d735af9e6f8 Mon Sep 17 00:00:00 2001 From: laustta Date: Fri, 19 Nov 2021 03:12:37 +1100 Subject: [PATCH 29/51] Fixed typo in New-GitHubRepositoryFork for USAGE.md (#345) --- USAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/USAGE.md b/USAGE.md index 82a076e3..1edffac6 100644 --- a/USAGE.md +++ b/USAGE.md @@ -735,7 +735,7 @@ Get-GitHubRepositoryFork -OwnerName microsoft -RepositoryName PowerShellForGitHu #### Create a new fork ```powershell -New-GitHubRepositoryForm -OwnerName microsoft -RepositoryName PowerShellForGitHub +New-GitHubRepositoryFork -OwnerName microsoft -RepositoryName PowerShellForGitHub ``` ---------- From 4b48946d81924a8508be2b16c28d9842da7d5b37 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Mon, 25 Jul 2022 11:39:09 -0700 Subject: [PATCH 30/51] Fix telemetry failure for long-running sessions (#355) The telemetry code was creating a singleton base telemetry event the first time that telemetry was being sent. That base event included the date. If a PowerShell session lasted multiple days, the telemetry reporting would eventually start to fail because the date being reported for the event was too old. We now just create a new telemetry event every time one is requested (this also ensures that it honors changes to the ApplicationInsightsKey), and now we only cache a GUID that we use to represent the "session" ID which we consider to be the duration of the current PowerShell session. --- Telemetry.ps1 | 60 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/Telemetry.ps1 b/Telemetry.ps1 index 3c9b94c5..88bf9d16 100644 --- a/Telemetry.ps1 +++ b/Telemetry.ps1 @@ -1,10 +1,11 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -# Singleton. Don't directly access this though....always get it -# by calling Get-BaseTelemetryEvent to ensure that it has been initialized and that you're always -# getting a fresh copy. -$script:GHBaseTelemetryEvent = $null +# Maintain a consistent ID for this PowerShell session that we'll use as our telemetry's session ID. +$script:TelemetrySessionId = [System.GUID]::NewGuid().ToString() + +# Tracks if we've seen the telemetry reminder this session. +$script:SeenTelemetryReminder = $false function Get-PiiSafeString { @@ -76,40 +77,37 @@ function Get-BaseTelemetryEvent [CmdletBinding()] param() - if ($null -eq $script:GHBaseTelemetryEvent) + if ((-not $script:SeenTelemetryReminder) -and + (-not (Get-GitHubConfiguration -Name SuppressTelemetryReminder))) { - if (-not (Get-GitHubConfiguration -Name SuppressTelemetryReminder)) - { - Write-Log -Message 'Telemetry is currently enabled. It can be disabled by calling "Set-GitHubConfiguration -DisableTelemetry". Refer to USAGE.md#telemetry for more information. Stop seeing this message in the future by calling "Set-GitHubConfiguration -SuppressTelemetryReminder".' - } + Write-Log -Message 'Telemetry is currently enabled. It can be disabled by calling "Set-GitHubConfiguration -DisableTelemetry". Refer to USAGE.md#telemetry for more information. Stop seeing this message in the future by calling "Set-GitHubConfiguration -SuppressTelemetryReminder".' + $script:SeenTelemetryReminder = $true + } - $username = Get-PiiSafeString -PlainText $env:USERNAME - - $script:GHBaseTelemetryEvent = [PSCustomObject] @{ - 'name' = 'Microsoft.ApplicationInsights.66d83c523070489b886b09860e05e78a.Event' - 'time' = (Get-Date).ToUniversalTime().ToString("O") - 'iKey' = (Get-GitHubConfiguration -Name ApplicationInsightsKey) - 'tags' = [PSCustomObject] @{ - 'ai.user.id' = $username - 'ai.session.id' = [System.GUID]::NewGuid().ToString() - 'ai.application.ver' = $MyInvocation.MyCommand.Module.Version.ToString() - 'ai.internal.sdkVersion' = '2.0.1.33027' # The version this schema was based off of. - } + $username = Get-PiiSafeString -PlainText $env:USERNAME + + return [PSCustomObject] @{ + 'name' = 'Microsoft.ApplicationInsights.66d83c523070489b886b09860e05e78a.Event' + 'time' = (Get-Date).ToUniversalTime().ToString("O") + 'iKey' = (Get-GitHubConfiguration -Name ApplicationInsightsKey) + 'tags' = [PSCustomObject] @{ + 'ai.user.id' = $username + 'ai.session.id' = $script:TelemetrySessionId + 'ai.application.ver' = $MyInvocation.MyCommand.Module.Version.ToString() + 'ai.internal.sdkVersion' = '2.0.1.33027' # The version this schema was based off of. + } - 'data' = [PSCustomObject] @{ - 'baseType' = 'EventData' - 'baseData' = [PSCustomObject] @{ - 'ver' = 2 - 'properties' = [PSCustomObject] @{ - 'DayOfWeek' = (Get-Date).DayOfWeek.ToString() - 'Username' = $username - } + 'data' = [PSCustomObject] @{ + 'baseType' = 'EventData' + 'baseData' = [PSCustomObject] @{ + 'ver' = 2 + 'properties' = [PSCustomObject] @{ + 'DayOfWeek' = (Get-Date).DayOfWeek.ToString() + 'Username' = $username } } } } - - return $script:GHBaseTelemetryEvent.PSObject.Copy() # Get a new instance, not a reference } function Invoke-SendTelemetryEvent From 9aac69728fb6221179cd876afb4923859d8442b1 Mon Sep 17 00:00:00 2001 From: "msftbot[bot]" <48340428+msftbot[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 09:26:56 -0700 Subject: [PATCH 31/51] Migrate FabricBot Tasks to Config-as-Code` (#356) **TL;DR;** Requesting to add [FabricBot](https://eng.ms/docs/products/1es-data-insights/merlinbot/extensions/fabricbot_overview) configuration associated with your repository to `.github/fabricbot.json`. **Context** FabricBot is now a [config-as-code-only](https://eng.ms/docs/products/1es-data-insights/merlinbot/extensions/bot-config-as-code) platform. As a result, while you can still use the [FabricBot Configuration Portal](https://portal.fabricbot.ms/bot/?repo=microsoft/PowerShellForGitHub) to modify your FabricBot configuration, you can no longer save the changes. The only way to save changes to your configuration at the moment is to _export configuration_ from the portal and upload the exported configuration to `.github/fabricbot.json` in your repository. In this pull request, we are adding your FabricBot configuration to your repository at `.github/fabricbot.json` so that you can make changes to it going forward. While the [FabricBot Configuration Portal](https://portal.fabricbot.ms/bot/?repo=microsoft/PowerShellForGitHub) is the *only way* to modify your FabricBot configuration at the moment, we have a feature on our backlog to publish the JSON schema defining the structure of the FabricBot configuration file. With the JSON schema, you can (1) use a plaintext editor of your choice to modify the FabricBot configuration file and use the schema to validate the file after editing or (2) [configure](https://code.visualstudio.com/Docs/languages/json#_json-schemas-and-settings) VS Code to use the schema when editing FabricBot configuration file to take advantage of convenience features such as automatic code completion and field description on mouseover. Co-authored-by: msftbot[bot] <48340428+msftbot[bot]@users.noreply.github.com> Co-authored-by: Howard Wolosky --- .github/fabricbot.json | 491 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 491 insertions(+) create mode 100644 .github/fabricbot.json diff --git a/.github/fabricbot.json b/.github/fabricbot.json new file mode 100644 index 00000000..2bb23948 --- /dev/null +++ b/.github/fabricbot.json @@ -0,0 +1,491 @@ +{ + "version": "1.0", + "tasks": [ + { + "taskType": "trigger", + "capabilityId": "CodeFlowLink", + "subCapability": "CodeFlowLink", + "version": "1.0", + "config": { + "taskName": "Add a CodeFlow link to new pull requests" + }, + "id": "YDkZFvdXmD3", + "disabled": true + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestReviewResponder", + "version": "1.0", + "config": { + "taskName": "Add needs author feedback label to pull requests when changes are requested", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "submitted" + } + }, + { + "name": "isReviewState", + "parameters": { + "state": "changes_requested" + } + } + ] + }, + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "needs-author-feedback" + } + } + ], + "eventType": "pull_request", + "eventNames": [ + "pull_request_review" + ] + }, + "id": "r_flUYyQmXt" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "taskName": "Remove needs author feedback label when the author responds to a pull request", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": { + "type": "author" + } + } + }, + { + "operator": "not", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "closed" + } + } + ] + }, + { + "name": "hasLabel", + "parameters": { + "label": "needs-author-feedback" + } + } + ] + }, + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "needs-author-feedback" + } + } + ], + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ] + }, + "id": "oXVx60lgowd" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestCommentResponder", + "version": "1.0", + "config": { + "taskName": "Remove needs author feedback label when the author comments on a pull request", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": { + "type": "author" + } + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "needs-author-feedback" + } + } + ] + }, + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "needs-author-feedback" + } + } + ], + "eventType": "pull_request", + "eventNames": [ + "issue_comment" + ] + }, + "id": "6DLGYbk_2cF" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestReviewResponder", + "version": "1.0", + "config": { + "taskName": "Remove needs author feedback label when the author responds to a pull request review comment", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "isActivitySender", + "parameters": { + "user": { + "type": "author" + } + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "needs-author-feedback" + } + } + ] + }, + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "needs-author-feedback" + } + } + ], + "eventType": "pull_request", + "eventNames": [ + "pull_request_review" + ] + }, + "id": "hE72Sl_8OtC" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestResponder", + "version": "1.0", + "config": { + "taskName": "Remove no recent activity label from pull requests", + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "isAction", + "parameters": { + "action": "closed" + } + } + ] + }, + { + "name": "hasLabel", + "parameters": { + "label": "status-no-recent-activity" + } + } + ] + }, + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "status-no-recent-activity" + } + } + ], + "eventType": "pull_request", + "eventNames": [ + "pull_request", + "issues", + "project_card" + ] + }, + "id": "OMHGEo10a0W" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestCommentResponder", + "version": "1.0", + "config": { + "taskName": "Remove no recent activity label when a pull request is commented on", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "status-no-recent-activity" + } + } + ] + }, + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "status-no-recent-activity" + } + } + ], + "eventType": "pull_request", + "eventNames": [ + "issue_comment" + ] + }, + "id": "wTrzllHtIDZ" + }, + { + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "PullRequestReviewResponder", + "version": "1.0", + "config": { + "taskName": "Remove no recent activity label when a pull request is reviewed", + "conditions": { + "operator": "and", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "status-no-recent-activity" + } + } + ] + }, + "actions": [ + { + "name": "removeLabel", + "parameters": { + "label": "status-no-recent-activity" + } + } + ], + "eventType": "pull_request", + "eventNames": [ + "pull_request_review" + ] + }, + "id": "Sg7hkGEr5kG" + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "config": { + "taskName": "Close stale pull requests", + "frequency": [ + { + "weekDay": 0, + "hours": [ + 8 + ], + "timezoneOffset": -7 + } + ], + "searchTerms": [ + { + "name": "isPr", + "parameters": {} + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "needs-author-feedback" + } + }, + { + "name": "hasLabel", + "parameters": { + "label": "status-no-recent-activity" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 14 + } + } + ], + "actions": [ + { + "name": "closeIssue", + "parameters": {} + }, + { + "name": "addLabel", + "parameters": { + "label": "auto-closed-unmerged" + } + }, + { + "name": "addReply", + "parameters": { + "comment": "This pull request has been automatically closed due to a lack of activity from the author. We understand. Life happens and other things likely came up. We would still love to see your contribution get merged in. Now that it has been closed, a different community member may wish to pick up where you left off. If so, they should speak up by commenting below. If _you're_ still interested in completing this yourself, just respond back and let us know." + } + } + ] + }, + "id": "t1vGBS8FEhE" + }, + { + "taskType": "scheduled", + "capabilityId": "ScheduledSearch", + "subCapability": "ScheduledSearch", + "version": "1.1", + "config": { + "taskName": "Add no recent activity label to pull requests", + "frequency": [ + { + "weekDay": 0, + "hours": [ + 8 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 1, + "hours": [ + 8 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 2, + "hours": [ + 8 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 3, + "hours": [ + 8 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 4, + "hours": [ + 8 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 5, + "hours": [ + 8 + ], + "timezoneOffset": -7 + }, + { + "weekDay": 6, + "hours": [ + 8 + ], + "timezoneOffset": -7 + } + ], + "searchTerms": [ + { + "name": "isPr", + "parameters": {} + }, + { + "name": "isOpen", + "parameters": {} + }, + { + "name": "hasLabel", + "parameters": { + "label": "needs-author-feedback" + } + }, + { + "name": "noActivitySince", + "parameters": { + "days": 7 + } + }, + { + "name": "noLabel", + "parameters": { + "label": "status-no-recent-activity" + } + } + ], + "actions": [ + { + "name": "addLabel", + "parameters": { + "label": "status-no-recent-activity" + } + }, + { + "name": "addReply", + "parameters": { + "comment": "This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **7 days**. It will be closed if no further activity occurs **within 14 days of this comment**." + } + } + ] + }, + "id": "xdjknroafok" + }, + { + "taskType": "trigger", + "capabilityId": "AutoMerge", + "subCapability": "AutoMerge", + "version": "1.0", + "config": { + "taskName": "Automatically merge pull requests", + "label": "auto-merge", + "silentMode": false, + "minMinutesOpen": 480, + "mergeType": "squash", + "allowAutoMergeInstructionsWithoutLabel": true, + "removeLabelOnPush": true, + "requireAllStatuses": false, + "usePrDescriptionAsCommitMessage": true + }, + "id": "6GIyYgxEaBW", + "disabled": false + } + ], + "userGroups": [] +} From 1466f1656b85e256917bc3057ba6dd6d1579a652 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 14 Dec 2022 17:21:06 -0800 Subject: [PATCH 32/51] Improve the 404 friendly message (#363) Doing some clarifying wording in the friendly error message that we add to a 404 to indicate that they could be getting the error because the item truly doesn't exist, not simply due to authentication issues. --- GitHubCore.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index f5cc17ac..e44a54e2 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -550,8 +550,13 @@ function Invoke-GHRestMethod if ($statusCode -eq 404) { - $explanation = @('This typically happens when the current user isn''t properly authenticated.', - 'You may need an Access Token with additional scopes checked.') + $explanation = @('This error will usually happen for one of the following reasons:', + '(1) The item you are requesting truly doesn''t exist (so make sure you don''t have', + 'a typo) or ', + '(2) The item _does_ exist, but you don''t currently have permission to access it. ', + 'If you think the item does exist and that you _should_ have access to it, then make', + 'sure that you are properly authenticated with Set-GitHubAuthentication and that', + 'your access token has the appropriate scopes checked.') $output += ($explanation -join ' ') } From 4d7667bcaf66523bf3b0194d847d8bfc3c6325f1 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 14 Dec 2022 17:22:08 -0800 Subject: [PATCH 33/51] Not forwarding AccessToken to sub-commands for Repo Team Permissions (#362) The Get/Set/Remove-GitHubRepositoryTeamPermission functions will sometimes call Get-GitHubTeam to get missing information. In those instances, they weren't passing along the `AccessToken` parameter if it had been provided by the user. In those scenarios, the result will be a 404 since the Get-GitHubTeam call won't have the same auth permissions as the core API being called. --- GitHubRepositories.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index 40215d26..cce71a04 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -3070,7 +3070,7 @@ filter Get-GitHubRepositoryTeamPermission if ($PSBoundParameters.ContainsKey('TeamName')) { - $team = Get-GitHubTeam -OrganizationName $OwnerName | + $team = Get-GitHubTeam -OrganizationName $OwnerName -AccessToken $AccessToken | Where-Object -Property name -eq $TeamName if ($null -eq $team) @@ -3104,7 +3104,7 @@ filter Get-GitHubRepositoryTeamPermission if ($PSBoundParameters.ContainsKey('TeamSlug')) { - $team = Get-GitHubTeam -OrganizationName $OwnerName -TeamSlug $TeamSlug + $team = Get-GitHubTeam -OrganizationName $OwnerName -TeamSlug $TeamSlug -AccessToken $AccessToken $TeamName = $team.name } @@ -3253,7 +3253,7 @@ filter Set-GitHubRepositoryTeamPermission if ($PSBoundParameters.ContainsKey('TeamName')) { - $team = Get-GitHubTeam -OrganizationName $OwnerName | + $team = Get-GitHubTeam -OrganizationName $OwnerName -AccessToken $AccessToken | Where-Object -Property name -eq $TeamName if ($null -eq $team) @@ -3426,7 +3426,7 @@ filter Remove-GitHubRepositoryTeamPermission if ($PSBoundParameters.ContainsKey('TeamName')) { - $team = Get-GitHubTeam -OrganizationName $OwnerName | + $team = Get-GitHubTeam -OrganizationName $OwnerName -AccessToken $AccessToken | Where-Object -Property name -eq $TeamName if ($null -eq $team) From d8ee50a7ad0fa1b12e3b5d7745aeed348a340708 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Wed, 14 Dec 2022 17:23:36 -0800 Subject: [PATCH 34/51] Fix coalesced Team permission property (#361) When retrieving the permissions granted to a team for a repository, the API returns an array of booleans indicating what individual permissions the team currently has. | name | permissions granted | | ---- | ------------------ | | pull | pull | | triage | pull, triage | | push | pull, triage, push | | maintain | pull, triage, push, maintain | | admin | pull, triage, push, maintain, admin | As you can see, each permissions builds on top of the previous permission. When adding extra properties to this returned object via `Add-GitHubRepositoryTeamPermissionAdditionalProperties`, we also add a new `permission` property that attempts to represent the collection of permissions with their current top-permission level. The logic however incorrectly favored `push` over `maintain` and thus would always said that a Team had `push` permission when in fact it may have actually had `maintain` permission. This simple change corrects that ordering mistake. --- GitHubRepositories.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index cce71a04..464f4856 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -3925,14 +3925,14 @@ filter Add-GitHubRepositoryTeamPermissionAdditionalProperties { $permission = 'admin' } - elseif ($result.permissions.push) - { - $permission = 'push' - } elseif ($result.permissions.maintain) { $permission = 'maintain' } + elseif ($result.permissions.push) + { + $permission = 'push' + } elseif ($result.permissions.triage) { $permission = 'triage' From 1afe5ac8728ca44c5cc433fd1cefe36d6197608b Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Thu, 15 Dec 2022 01:28:18 +0000 Subject: [PATCH 35/51] New/Set-GitHubRepository: Add AllowAutoMerge and UseSquashPrTitleAsDefault Parameters (#358) Adds the following parameters to the `New-GitHubRepository` and `Set-GitHubRepository` functions: * AllowAutoMerge * UseSquashPrTitleAsDefault References * https://docs.github.com/en/rest/repos/repos#create-an-organization-repository * https://docs.github.com/en/rest/repos/repos#update-a-repository Fixes #357 --- GitHubRepositories.ps1 | 26 ++++++++++++++++++++++++++ Tests/GitHubRepositories.tests.ps1 | 16 ++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index 464f4856..891ef5df 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -83,6 +83,13 @@ filter New-GitHubRepository By default, rebase-merge pull requests will be allowed. Specify this to disallow. + .PARAMETER AllowAutoMerge + Specifies whether to allow auto-merge on pull requests. + + .PARAMETER UseSquashPrTitleAsDefault + Specifies whether to use the pull request title for squash-merge commits rather than the + commit message. + .PARAMETER DeleteBranchOnMerge Specifies the automatic deleting of head branches when pull requests are merged. @@ -160,6 +167,10 @@ filter New-GitHubRepository [switch] $DisallowRebaseMerge, + [switch] $AllowAutoMerge, + + [switch] $UseSquashPrTitleAsDefault, + [switch] $DeleteBranchOnMerge, [switch] $IsTemplate, @@ -205,6 +216,8 @@ filter New-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } + if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } + if ($PSBoundParameters.ContainsKey('UseSquashPrTitleAsDefault')) { $hashBody['use_squash_pr_title_as_default'] = $UseSquashPrTitleAsDefault.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } @@ -1057,6 +1070,13 @@ filter Set-GitHubRepository By default, rebase-merge pull requests will be allowed. Specify this to disallow. + .PARAMETER AllowAutoMerge + Specifies whether to allow auto-merge on pull requests. + + .PARAMETER UseSquashPrTitleAsDefault + Specifies whether to use the pull request title for squash-merge commits rather than the + commit message. + .PARAMETER DeleteBranchOnMerge Specifies the automatic deleting of head branches when pull requests are merged. @@ -1159,6 +1179,10 @@ filter Set-GitHubRepository [switch] $DisallowRebaseMerge, + [switch] $AllowAutoMerge, + + [switch] $UseSquashPrTitleAsDefault, + [switch] $DeleteBranchOnMerge, [switch] $IsTemplate, @@ -1203,6 +1227,8 @@ filter Set-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } + if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } + if ($PSBoundParameters.ContainsKey('UseSquashPrTitleAsDefault')) { $hashBody['use_squash_pr_title_as_default'] = $UseSquashPrTitleAsDefault.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } if ($PSBoundParameters.ContainsKey('Archived')) { $hashBody['archived'] = $Archived.ToBool() } diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index f63d8f3e..03f5c03e 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -119,6 +119,8 @@ try DisallowSquashMerge = $true DisallowMergeCommit = $true DisallowRebaseMerge = $false + AllowAutoMerge = $true + UseSquashPrTitleAsDefault = $true DeleteBranchOnMerge = $true GitIgnoreTemplate = $testGitIgnoreTemplate LicenseTemplate = $testLicenseTemplate @@ -142,6 +144,8 @@ try $repo.allow_squash_merge | Should -BeFalse $repo.allow_merge_commit | Should -BeFalse $repo.allow_rebase_merge | Should -BeTrue + $repo.allow_auto_merge | Should -BeTrue + $repo.use_squash_pr_title_as_default | Should -BeTrue $repo.delete_branch_on_merge | Should -BeTrue $repo.is_template | Should -BeTrue } @@ -170,6 +174,8 @@ try DisallowSquashMerge = $true DisallowMergeCommit = $false DisallowRebaseMerge = $true + AllowAutoMerge = $false + UseSquashPrTitleAsDefault = $false } $repo = New-GitHubRepository @newGitHubRepositoryParms } @@ -183,6 +189,8 @@ try $repo.allow_squash_merge | Should -BeFalse $repo.allow_merge_commit | Should -BeTrue $repo.allow_rebase_merge | Should -BeFalse + $repo.allow_auto_merge | Should -BeFalse + $repo.use_squash_pr_title_as_default | Should -BeFalse } AfterAll -ScriptBlock { @@ -729,6 +737,8 @@ try DisallowMergeCommit = $true DisallowRebaseMerge = $false DeleteBranchOnMerge = $true + AllowAutoMerge = $true + UseSquashPrTitleAsDefault = $true IsTemplate = $true } @@ -750,6 +760,8 @@ try $updatedRepo.allow_squash_merge | Should -BeFalse $updatedRepo.allow_merge_commit | Should -BeFalse $updatedRepo.allow_rebase_merge | Should -BeTrue + $updatedRepo.allow_auto_merge | Should -BeTrue + $updatedRepo.use_squash_pr_title_as_default | Should -BeTrue $updatedRepo.delete_branch_on_merge | Should -BeTrue $updatedRepo.is_template | Should -BeTrue } @@ -763,6 +775,8 @@ try DisallowSquashMerge = $true DisallowMergeCommit = $false DisallowRebaseMerge = $true + AllowAutoMerge = $false + UseSquashPrTitleAsDefault = $false } $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru @@ -777,6 +791,8 @@ try $updatedRepo.allow_squash_merge | Should -BeFalse $updatedRepo.allow_merge_commit | Should -BeTrue $updatedRepo.allow_rebase_merge | Should -BeFalse + $updatedRepo.use_squash_pr_title_as_default | Should -BeFalse + $updatedRepo.delete_branch_on_merge | Should -BeFalse } } From 515e9bef7888d9c49ed738e165fe10ea9ea1f85e Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Thu, 15 Dec 2022 15:32:42 -0800 Subject: [PATCH 36/51] Revert "New/Set-GitHubRepository: Add AllowAutoMerge and UseSquashPrTitleAsDefault Parameters (#358)" (#381) This reverts commit 1afe5ac8728ca44c5cc433fd1cefe36d6197608b. It turns out that this isn't quite working right. The `use_squash_pr_title_as_default` parameter [has been deprecated per the documentation](https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#update-a-repository) in favor of `squash_merge_commit_title ` which works a bit differently. Additionally, there appears to be a GitHub-side bug at the moment with changing the value of `allow_auto_merge` (it does not honor the request being sent). Given this, for the time being we'll revert the change until we know that the feature is working correctly. --- GitHubRepositories.ps1 | 26 -------------------------- Tests/GitHubRepositories.tests.ps1 | 16 ---------------- 2 files changed, 42 deletions(-) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index 891ef5df..464f4856 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -83,13 +83,6 @@ filter New-GitHubRepository By default, rebase-merge pull requests will be allowed. Specify this to disallow. - .PARAMETER AllowAutoMerge - Specifies whether to allow auto-merge on pull requests. - - .PARAMETER UseSquashPrTitleAsDefault - Specifies whether to use the pull request title for squash-merge commits rather than the - commit message. - .PARAMETER DeleteBranchOnMerge Specifies the automatic deleting of head branches when pull requests are merged. @@ -167,10 +160,6 @@ filter New-GitHubRepository [switch] $DisallowRebaseMerge, - [switch] $AllowAutoMerge, - - [switch] $UseSquashPrTitleAsDefault, - [switch] $DeleteBranchOnMerge, [switch] $IsTemplate, @@ -216,8 +205,6 @@ filter New-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } - if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } - if ($PSBoundParameters.ContainsKey('UseSquashPrTitleAsDefault')) { $hashBody['use_squash_pr_title_as_default'] = $UseSquashPrTitleAsDefault.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } @@ -1070,13 +1057,6 @@ filter Set-GitHubRepository By default, rebase-merge pull requests will be allowed. Specify this to disallow. - .PARAMETER AllowAutoMerge - Specifies whether to allow auto-merge on pull requests. - - .PARAMETER UseSquashPrTitleAsDefault - Specifies whether to use the pull request title for squash-merge commits rather than the - commit message. - .PARAMETER DeleteBranchOnMerge Specifies the automatic deleting of head branches when pull requests are merged. @@ -1179,10 +1159,6 @@ filter Set-GitHubRepository [switch] $DisallowRebaseMerge, - [switch] $AllowAutoMerge, - - [switch] $UseSquashPrTitleAsDefault, - [switch] $DeleteBranchOnMerge, [switch] $IsTemplate, @@ -1227,8 +1203,6 @@ filter Set-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } - if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } - if ($PSBoundParameters.ContainsKey('UseSquashPrTitleAsDefault')) { $hashBody['use_squash_pr_title_as_default'] = $UseSquashPrTitleAsDefault.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } if ($PSBoundParameters.ContainsKey('Archived')) { $hashBody['archived'] = $Archived.ToBool() } diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 03f5c03e..f63d8f3e 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -119,8 +119,6 @@ try DisallowSquashMerge = $true DisallowMergeCommit = $true DisallowRebaseMerge = $false - AllowAutoMerge = $true - UseSquashPrTitleAsDefault = $true DeleteBranchOnMerge = $true GitIgnoreTemplate = $testGitIgnoreTemplate LicenseTemplate = $testLicenseTemplate @@ -144,8 +142,6 @@ try $repo.allow_squash_merge | Should -BeFalse $repo.allow_merge_commit | Should -BeFalse $repo.allow_rebase_merge | Should -BeTrue - $repo.allow_auto_merge | Should -BeTrue - $repo.use_squash_pr_title_as_default | Should -BeTrue $repo.delete_branch_on_merge | Should -BeTrue $repo.is_template | Should -BeTrue } @@ -174,8 +170,6 @@ try DisallowSquashMerge = $true DisallowMergeCommit = $false DisallowRebaseMerge = $true - AllowAutoMerge = $false - UseSquashPrTitleAsDefault = $false } $repo = New-GitHubRepository @newGitHubRepositoryParms } @@ -189,8 +183,6 @@ try $repo.allow_squash_merge | Should -BeFalse $repo.allow_merge_commit | Should -BeTrue $repo.allow_rebase_merge | Should -BeFalse - $repo.allow_auto_merge | Should -BeFalse - $repo.use_squash_pr_title_as_default | Should -BeFalse } AfterAll -ScriptBlock { @@ -737,8 +729,6 @@ try DisallowMergeCommit = $true DisallowRebaseMerge = $false DeleteBranchOnMerge = $true - AllowAutoMerge = $true - UseSquashPrTitleAsDefault = $true IsTemplate = $true } @@ -760,8 +750,6 @@ try $updatedRepo.allow_squash_merge | Should -BeFalse $updatedRepo.allow_merge_commit | Should -BeFalse $updatedRepo.allow_rebase_merge | Should -BeTrue - $updatedRepo.allow_auto_merge | Should -BeTrue - $updatedRepo.use_squash_pr_title_as_default | Should -BeTrue $updatedRepo.delete_branch_on_merge | Should -BeTrue $updatedRepo.is_template | Should -BeTrue } @@ -775,8 +763,6 @@ try DisallowSquashMerge = $true DisallowMergeCommit = $false DisallowRebaseMerge = $true - AllowAutoMerge = $false - UseSquashPrTitleAsDefault = $false } $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru @@ -791,8 +777,6 @@ try $updatedRepo.allow_squash_merge | Should -BeFalse $updatedRepo.allow_merge_commit | Should -BeTrue $updatedRepo.allow_rebase_merge | Should -BeFalse - $updatedRepo.use_squash_pr_title_as_default | Should -BeFalse - $updatedRepo.delete_branch_on_merge | Should -BeFalse } } From 938896738c7a8c8b6d3b7b798c761798e4fce651 Mon Sep 17 00:00:00 2001 From: Neil White Date: Fri, 16 Dec 2022 08:29:19 -0800 Subject: [PATCH 37/51] Added API versioning support (#379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub is introducing versioned API's. In order to get the expected behavior of an API, you need to invoke the API with its version in the request header. This change updates the core functions (`Invoke-GHRestMethod` and `Invoke-GHRestMethodMultipleResult`) to accept an ApiVersion as part of their param sets so that as the module continues to add new functionality, methods can request the appropriate API Version for their individual calls. Fixes #377 Reference: [To infinity and beyond: enabling the future of GitHub’s REST API with API versioning](https://github.blog/2022-11-28-to-infinity-and-beyond-enabling-the-future-of-githubs-rest-api-with-api-versioning/) [API Versions](https://docs.github.com/en/rest/overview/api-versions?apiVersion=2022-11-28) --- CONTRIBUTING.md | 1 + GitHubCore.ps1 | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b335618..a568492a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -614,6 +614,7 @@ Thank you to all of our contributors, no matter how big or small the contributio - **[Giuseppe Campanelli (@themilanfan)](https://github.com/themilanfan)** - **[Christoph Bergmeister (@bergmeister)](https://github.com/bergmeister)** - **[Simon Heather (@X-Guardian)](https://github.com/X-Guardian)** +- **[Neil White (@variableresistor)](https://github.com/variableresistor)** ---------- diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index e44a54e2..686458ea 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -80,6 +80,9 @@ function Invoke-GHRestMethod If specified, this will save the result to a temporary file and return the FileInfo of that temporary file. + .PARAMETER ApiVersion + Indicates the version of this API that should be used. Format is: 'yyyy-MM-dd'. + .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api as opposed to requesting a new one. @@ -145,6 +148,9 @@ function Invoke-GHRestMethod [switch] $Save, + [ValidatePattern('^\d{4}-\d{2}-\d{2}$')] + [string] $ApiVersion = "2022-11-28", + [string] $AccessToken, [string] $TelemetryEventName = $null, @@ -232,6 +238,7 @@ function Invoke-GHRestMethod $headers = @{ 'Accept' = $AcceptHeader 'User-Agent' = 'PowerShellForGitHub' + 'X-GitHub-Api-Version' = $ApiVersion } # Add any additional headers @@ -609,6 +616,9 @@ function Invoke-GHRestMethodMultipleResult Allows the caller to specify any number of additional headers that should be added to all of the requests made. + .PARAMETER ApiVersion + Indicates the version of this API that should be used. Format is: 'yyyy-MM-dd'. + .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api as opposed to requesting a new one. @@ -660,6 +670,9 @@ function Invoke-GHRestMethodMultipleResult [hashtable] $AdditionalHeader = @{}, + [ValidatePattern('^\d{4}-\d{2}-\d{2}$')] + [string] $ApiVersion = "2022-11-28", + [string] $AccessToken, [string] $TelemetryEventName = $null, @@ -700,6 +713,7 @@ function Invoke-GHRestMethodMultipleResult 'AcceptHeader' = $AcceptHeader 'AdditionalHeader' = $AdditionalHeader 'ExtendedResult' = $true + 'ApiVersion' = $ApiVersion 'AccessToken' = $AccessToken 'TelemetryProperties' = $telemetryProperties 'TelemetryExceptionBucket' = $errorBucket From 5e1a4b312996ac894e01fa13c9677b1f302becfb Mon Sep 17 00:00:00 2001 From: Mark <24516562+tigerfansga@users.noreply.github.com> Date: Fri, 16 Dec 2022 15:34:34 -0500 Subject: [PATCH 38/51] Pester v5 (#366) Updated all Pester tests in the project to support Pester v5. The main benefit that we get out of this, besides just moving on to the currently supported version of the test framework, is that we can now execute individual tests directly within VS Code. In the process of doing this migration: * Removed repository Code of Conduct tests from GitHubMiscellaneous.tests.ps1 since the command has been deprecated by GitHub * Updated GitHubReleases.tests.ps1 to account for pre-releases * Updated run-unitTests.yaml and CONTRIBUTING.md to have the Pester v5.3.3 install command, as well as to update its invocation commands. * Removed the language-specific error messages in some `-Throws` tests because the wording keeps changing. * Updated this project's VSCode settings.json to take advantage of the fact that the tests are now Pester 5 compatible. This allows each individual block to have a Run/Debug link associated with it. ([More info](https://pester.dev/docs/usage/vscode)). * Disabled all of the Projects/ProjectCards/ProjectColumns tests because Classic Projects have been deprecated by GitHub (#380 for more info) Fixes #194 Co-authored-by: Howard Wolosky --- .vscode/settings.json | 5 +- CONTRIBUTING.md | 21 +- Tests/Common.ps1 | 4 +- Tests/GitHubAnalytics.tests.ps1 | 19 +- Tests/GitHubAssignees.tests.ps1 | 232 +- Tests/GitHubBranches.tests.ps1 | 1985 ++++++------- Tests/GitHubContents.tests.ps1 | 607 ++-- Tests/GitHubCore.Tests.ps1 | 251 +- Tests/GitHubEvents.tests.ps1 | 178 +- Tests/GitHubGistComments.tests.ps1 | 387 +-- Tests/GitHubGists.tests.ps1 | 1427 +++++---- Tests/GitHubGraphQl.Tests.ps1 | 314 +- Tests/GitHubIssueComments.tests.ps1 | 267 +- Tests/GitHubIssues.tests.ps1 | 681 +++-- Tests/GitHubLabels.tests.ps1 | 1681 ++++++----- Tests/GitHubMilestones.tests.ps1 | 533 ++-- Tests/GitHubMiscellaneous.tests.ps1 | 42 +- Tests/GitHubOrganizations.tests.ps1 | 61 +- Tests/GitHubProjectCards.tests.ps1 | 730 ++--- Tests/GitHubProjectColumns.tests.ps1 | 423 +-- Tests/GitHubProjects.tests.ps1 | 886 +++--- Tests/GitHubPullRequests.tests.ps1 | 103 +- Tests/GitHubReactions.Tests.ps1 | 115 +- Tests/GitHubReleases.tests.ps1 | 1445 +++++---- Tests/GitHubRepositories.tests.ps1 | 2776 +++++++++--------- Tests/GitHubRepositoryForks.tests.ps1 | 120 +- Tests/GitHubRepositoryTraffic.tests.ps1 | 139 +- Tests/GitHubTeams.tests.ps1 | 1460 ++++----- Tests/GitHubUsers.tests.ps1 | 190 +- build/pipelines/templates/run-unitTests.yaml | 21 +- 30 files changed, 8917 insertions(+), 8186 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a24892b4..d39166ee 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,6 @@ "files.trimTrailingWhitespace": true }, "powershell.codeFormatting.openBraceOnSameLine": false, - "powershell.codeFormatting.alignPropertyValuePairs": false -} \ No newline at end of file + "powershell.codeFormatting.alignPropertyValuePairs": false, + "powershell.pester.useLegacyCodeLens": false +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a568492a..5f373b04 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -384,7 +384,7 @@ This module supports testing using the [Pester UT framework](https://github.com/ To install it: ```powershell -Install-Module -Name Pester -RequiredVersion 4.10.1 -AllowClobber -SkipPublisherCheck -Force +Install-Module -Name Pester -MinimumVersion 5.3.3 -AllowClobber -SkipPublisherCheck -Force ``` #### Configuring Your Environment @@ -421,21 +421,29 @@ Please keep in mind some tests may fail on your machine, as they test private it Pester can also be used to test code-coverage, like so: ```powershell -Invoke-Pester -CodeCoverage "$root\GitHubLabels.ps1" -TestName "*" +$pesterConfig = New-PesterConfiguration +$pesterConfig.CodeCoverage.Path = @("$root\GitHubLabels.ps1") +$pesterConfig.CodeCoverage.Enabled = $true + +Invoke-Pester -Configuration $pesterConfig +# Be sure you're not passing this in to -PesterOption, since that's different than the configuration. ``` This command tells Pester to check the `GitHubLabels.ps1` file for code-coverage. -The `-TestName` parameter tells Pester to run any `Describe` blocks with a `Name` like -`"*"` (which in this case, is every test, but can be made more specific). The code-coverage object can be captured and interacted with, like so: ```powershell -$cc = (Invoke-Pester -CodeCoverage "$root\GitHubLabels.ps1" -TestName "*" -PassThru -Quiet).CodeCoverage +$pesterConfig = New-PesterConfiguration +$pesterConfig.CodeCoverage.Path = @("$root\GitHubLabels.ps1") +$pesterConfig.CodeCoverage.Enabled = $true +$pesterConfig.Run.PassThru = $true + +$cc = (Invoke-Pester -Configuration $pesterConfig).CodeCoverage ``` There are many more nuances to code-coverage, see -[its documentation](https://github.com/pester/Pester/wiki/Code-Coverage) for more details. +[its documentation](https://pester.dev/docs/usage/code-coverage) for more details. #### Automated Tests [![Build status](https://dev.azure.com/ms/PowerShellForGitHub/_apis/build/status/PowerShellForGitHub-CI?branchName=master)](https://dev.azure.com/ms/PowerShellForGitHub/_build/latest?definitionId=109&branchName=master) @@ -615,6 +623,7 @@ Thank you to all of our contributors, no matter how big or small the contributio - **[Christoph Bergmeister (@bergmeister)](https://github.com/bergmeister)** - **[Simon Heather (@X-Guardian)](https://github.com/X-Guardian)** - **[Neil White (@variableresistor)](https://github.com/variableresistor)** +- **[Mark Curole(@tigerfansga)](https://github.com/tigerfansga)** ---------- diff --git a/Tests/Common.ps1 b/Tests/Common.ps1 index fc89f781..c3de5f08 100644 --- a/Tests/Common.ps1 +++ b/Tests/Common.ps1 @@ -18,7 +18,7 @@ $script:originalConfigFile = $null function Initialize-CommonTestSetup { -<# + <# .SYNOPSIS Configures the tests to run with the authentication information stored in the project's Azure DevOps pipeline (if that information exists in the environment). @@ -38,7 +38,7 @@ function Initialize-CommonTestSetup This method is invoked immediately after the declaration. #> [CmdletBinding()] - [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification="Needed to configure with the stored, encrypted string value in Azure DevOps.")] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "", Justification = "Needed to configure with the stored, encrypted string value in Azure DevOps.")] param() $script:moduleName = 'PowerShellForGitHub' diff --git a/Tests/GitHubAnalytics.tests.ps1 b/Tests/GitHubAnalytics.tests.ps1 index 1be29162..743ec1cd 100644 --- a/Tests/GitHubAnalytics.tests.ps1 +++ b/Tests/GitHubAnalytics.tests.ps1 @@ -8,19 +8,18 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') - -try -{ - # TODO +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') } -finally -{ + +# TODO + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubAssignees.tests.ps1 b/Tests/GitHubAssignees.tests.ps1 index ffda4154..4d27807c 100644 --- a/Tests/GitHubAssignees.tests.ps1 +++ b/Tests/GitHubAssignees.tests.ps1 @@ -8,113 +8,131 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} -try -{ - Describe 'Getting an Assignee' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - } +Describe 'Getting an Assignee' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - AfterAll { - $repo | Remove-GitHubRepository -Confirm:$false - } + AfterAll { + $repo | Remove-GitHubRepository -Confirm:$false + } - Context 'For getting assignees in a repository via parameters' { + Context 'For getting assignees in a repository via parameters' { + BeforeAll { $assigneeList = @(Get-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name) + } - It 'Should have returned the one assignee' { - $assigneeList.Count | Should -Be 1 - } + It 'Should have returned the one assignee' { + $assigneeList.Count | Should -Be 1 + } - It 'Should have the expected type' { - $assigneeList[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type' { + $assigneeList[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'For getting assignees in a repository with the repo on the pipeline' { + Context 'For getting assignees in a repository with the repo on the pipeline' { + BeforeAll { $assigneeList = @($repo | Get-GitHubAssignee) + } - It 'Should have returned the one assignee' { - $assigneeList.Count | Should -Be 1 - } + It 'Should have returned the one assignee' { + $assigneeList.Count | Should -Be 1 + } - It 'Should have the expected type' { - $assigneeList[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type' { + $assigneeList[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } +} - Describe 'Testing for a valid Assignee' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $octocat = Get-GitHubUser -UserName 'octocat' - $owner = Get-GitHubUser -UserName $script:ownerName - } +Describe 'Testing for a valid Assignee' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $octocat = Get-GitHubUser -UserName 'octocat' + $owner = Get-GitHubUser -UserName $script:ownerName + } - AfterAll { - $repo | Remove-GitHubRepository -Confirm:$false - } + AfterAll { + $repo | Remove-GitHubRepository -Confirm:$false + } - Context 'For testing valid owner with parameters' { + Context 'For testing valid owner with parameters' { + BeforeAll { $hasPermission = Test-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Assignee $script:ownerName + } - It 'Should consider the owner of the repo to be a valid assignee' { - $hasPermission | Should -BeTrue - } + It 'Should consider the owner of the repo to be a valid assignee' { + $hasPermission | Should -BeTrue } + } - Context 'For testing valid owner with the repo on the pipeline' { + Context 'For testing valid owner with the repo on the pipeline' { + BeforeAll { $hasPermission = $repo | Test-GitHubAssignee -Assignee $script:ownerName + } - It 'Should consider the owner of the repo to be a valid assignee' { - $hasPermission | Should -BeTrue - } + It 'Should consider the owner of the repo to be a valid assignee' { + $hasPermission | Should -BeTrue } + } - Context 'For testing valid owner with a user object on the pipeline' { + Context 'For testing valid owner with a user object on the pipeline' { + BeforeAll { $hasPermission = $owner | Test-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name + } - It 'Should consider the owner of the repo to be a valid assignee' { - $hasPermission | Should -BeTrue - } + It 'Should consider the owner of the repo to be a valid assignee' { + $hasPermission | Should -BeTrue } + } - Context 'For testing invalid owner with a user object on the pipeline' { + Context 'For testing invalid owner with a user object on the pipeline' { + BeforeAll { $hasPermission = $octocat | Test-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name + } - It 'Should consider the owner of the repo to be a valid assignee' { - $hasPermission | Should -BeFalse - } + It 'Should consider the owner of the repo to be a valid assignee' { + $hasPermission | Should -BeFalse } } +} - Describe 'Adding and Removing Assignees from an Issue' { +Describe 'Adding and Removing Assignees from an Issue' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $owner = Get-GitHubUser -UserName $script:ownerName + } + + AfterAll { + $repo | Remove-GitHubRepository -Confirm:$false + } + + Context 'Adding and removing an assignee via parameters' { BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $owner = Get-GitHubUser -UserName $script:ownerName + $issue = $repo | New-GitHubIssue -Title "Test issue" } - AfterAll { - $repo | Remove-GitHubRepository -Confirm:$false + It 'Should have no assignees when created' { + $issue.assignee.login | Should -BeNullOrEmpty + $issue.assignees | Should -BeNullOrEmpty } - Context 'Adding and removing an assignee via parameters' { - $issue = $repo | New-GitHubIssue -Title "Test issue" + Context 'Adding an assignee via parameters' { - It 'Should have no assignees when created' { - $issue.assignee.login | Should -BeNullOrEmpty - $issue.assignees | Should -BeNullOrEmpty + BeforeAll { + $updatedIssue = Add-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Assignee $owner.login -PassThru } - $updatedIssue = Add-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Assignee $owner.login -PassThru - It 'Should have returned the same issue' { $updatedIssue.number | Should -Be $issue.number } @@ -128,8 +146,14 @@ try It 'Should be of the expected type' { $updatedIssue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' } + } + + Context 'Remove an assignee via parameters' { + + BeforeAll { + $updatedIssue = Remove-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Assignee $owner.login -Confirm:$false + } - $updatedIssue = Remove-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Assignee $owner.login -Confirm:$false It 'Should have returned the same issue' { $updatedIssue.number | Should -Be $issue.number } @@ -143,16 +167,22 @@ try $updatedIssue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' } } + } - Context 'Adding an assignee with the repo on the pipeline' { + Context 'Adding an assignee with the repo on the pipeline' { + BeforeAll { $issue = $repo | New-GitHubIssue -Title "Test issue" + } - It 'Should have no assignees when created' { - $issue.assignee.login | Should -BeNullOrEmpty - $issue.assignees | Should -BeNullOrEmpty - } + It 'Should have no assignees when created' { + $issue.assignee.login | Should -BeNullOrEmpty + $issue.assignees | Should -BeNullOrEmpty + } - $updatedIssue = $repo | Add-GitHubAssignee -Issue $issue.number -Assignee $owner.login -PassThru + Context "Adding an assignee with the repo on the pipeline" { + BeforeAll { + $updatedIssue = $repo | Add-GitHubAssignee -Issue $issue.number -Assignee $owner.login -PassThru + } It 'Should have returned the same issue' { $updatedIssue.number | Should -Be $issue.number @@ -167,8 +197,13 @@ try It 'Should be of the expected type' { $updatedIssue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' } + } + + Context "Removing an assignee with the repo on the pipeline" { + BeforeAll { + $updatedIssue = $repo | Remove-GitHubAssignee -Issue $issue.number -Assignee $owner.login -Force -Confirm:$false + } - $updatedIssue = $repo | Remove-GitHubAssignee -Issue $issue.number -Assignee $owner.login -Force -Confirm:$false It 'Should have returned the same issue' { $updatedIssue.number | Should -Be $issue.number } @@ -182,16 +217,22 @@ try $updatedIssue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' } } + } - Context 'Adding an assignee with the issue on the pipeline' { + Context 'Adding an assignee with the issue on the pipeline' { + BeforeAll { $issue = $repo | New-GitHubIssue -Title "Test issue" + } - It 'Should have no assignees when created' { - $issue.assignee.login | Should -BeNullOrEmpty - $issue.assignees | Should -BeNullOrEmpty - } + It 'Should have no assignees when created' { + $issue.assignee.login | Should -BeNullOrEmpty + $issue.assignees | Should -BeNullOrEmpty + } - $updatedIssue = $issue | Add-GitHubAssignee -Assignee $owner.login -PassThru + Context "Add assignee with the issue on the pipeline" { + BeforeAll { + $updatedIssue = $issue | Add-GitHubAssignee -Assignee $owner.login -PassThru + } It 'Should have returned the same issue' { $updatedIssue.number | Should -Be $issue.number @@ -206,8 +247,13 @@ try It 'Should be of the expected type' { $updatedIssue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' } + } + + Context "Remove assignee with the issue on the pipeline" { + BeforeAll { + $updatedIssue = $issue | Remove-GitHubAssignee -Assignee $owner.login -Force + } - $updatedIssue = $issue | Remove-GitHubAssignee -Assignee $owner.login -Force It 'Should have returned the same issue' { $updatedIssue.number | Should -Be $issue.number } @@ -221,16 +267,22 @@ try $updatedIssue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' } } + } - Context 'Adding an assignee with the assignee user object on the pipeline' { + Context 'Adding an assignee with the assignee user object on the pipeline' { + BeforeAll { $issue = $repo | New-GitHubIssue -Title "Test issue" + } - It 'Should have no assignees when created' { - $issue.assignee.login | Should -BeNullOrEmpty - $issue.assignees | Should -BeNullOrEmpty - } + It 'Should have no assignees when created' { + $issue.assignee.login | Should -BeNullOrEmpty + $issue.assignees | Should -BeNullOrEmpty + } - $updatedIssue = $owner | Add-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -PassThru + Context 'Adding an assignee with the assignee user object on the pipeline' { + BeforeAll { + $updatedIssue = $owner | Add-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -PassThru + } It 'Should have returned the same issue' { $updatedIssue.number | Should -Be $issue.number @@ -245,8 +297,12 @@ try It 'Should be of the expected type' { $updatedIssue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' } + } - $updatedIssue = $owner | Remove-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Force + Context 'Removing an assignee with the assignee user object on the pipeline' { + BeforeAll { + $updatedIssue = $owner | Remove-GitHubAssignee -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Force + } It 'Should have returned the same issue' { $updatedIssue.number | Should -Be $issue.number @@ -263,8 +319,8 @@ try } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubBranches.tests.ps1 b/Tests/GitHubBranches.tests.ps1 index 21d55f6d..b988166b 100644 --- a/Tests/GitHubBranches.tests.ps1 +++ b/Tests/GitHubBranches.tests.ps1 @@ -8,137 +8,173 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} Set-StrictMode -Version 1.0 -try -{ - Describe 'Getting branches for repository' { - BeforeAll { - $repositoryName = [guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName -AutoInit - $branchName = 'master' - } +Describe 'Getting branches for repository' { + BeforeAll { + $repositoryName = [guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName -AutoInit + $branchName = 'master' + } - AfterAll { - $repo | Remove-GitHubRepository -Confirm:$false - } + AfterAll { + $repo | Remove-GitHubRepository -Confirm:$false + } - Context 'Getting all branches for a repository with parameters' { + Context 'Getting all branches for a repository with parameters' { + BeforeAll { $branches = @(Get-GitHubRepositoryBranch -OwnerName $script:ownerName -RepositoryName $repositoryName) + } - It 'Should return expected number of repository branches' { - $branches.Count | Should -Be 1 - } + It 'Should return expected number of repository branches' { + $branches.Count | Should -Be 1 + } - It 'Should return the name of the expected branch' { - $branches.name | Should -Contain $branchName - } + It 'Should return the name of the expected branch' { + $branches.name | Should -Contain $branchName + } - It 'Should have the expected type and addititional properties' { - $branches[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branches[0].RepositoryUrl | Should -Be $repo.RepositoryUrl - $branches[0].BranchName | Should -Be $branches[0].name - $branches[0].Sha | Should -Be $branches[0].commit.sha - } + It 'Should have the expected type and addititional properties' { + $branches[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branches[0].RepositoryUrl | Should -Be $repo.RepositoryUrl + $branches[0].BranchName | Should -Be $branches[0].name + $branches[0].Sha | Should -Be $branches[0].commit.sha } + } - Context 'Getting all branches for a repository with the repo on the pipeline' { + Context 'Getting all branches for a repository with the repo on the pipeline' { + BeforeAll { $branches = @($repo | Get-GitHubRepositoryBranch) + } - It 'Should return expected number of repository branches' { - $branches.Count | Should -Be 1 - } + It 'Should return expected number of repository branches' { + $branches.Count | Should -Be 1 + } - It 'Should return the name of the expected branch' { - $branches.name | Should -Contain $branchName - } + It 'Should return the name of the expected branch' { + $branches.name | Should -Contain $branchName + } - It 'Should have the expected type and addititional properties' { - $branches[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branches[0].RepositoryUrl | Should -Be $repo.RepositoryUrl - $branches[0].BranchName | Should -Be $branches[0].name - $branches[0].Sha | Should -Be $branches[0].commit.sha - } + It 'Should have the expected type and addititional properties' { + $branches[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branches[0].RepositoryUrl | Should -Be $repo.RepositoryUrl + $branches[0].BranchName | Should -Be $branches[0].name + $branches[0].Sha | Should -Be $branches[0].commit.sha } + } - Context 'Getting a specific branch for a repository with parameters' { + Context 'Getting a specific branch for a repository with parameters' { + BeforeAll { $branch = Get-GitHubRepositoryBranch -OwnerName $script:ownerName -RepositoryName $repositoryName -BranchName $branchName + } - It 'Should return the expected branch name' { - $branch.name | Should -Be $branchName - } + It 'Should return the expected branch name' { + $branch.name | Should -Be $branchName + } - It 'Should have the expected type and addititional properties' { - $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl - $branch.BranchName | Should -Be $branch.name - $branch.Sha | Should -Be $branch.commit.sha - } + It 'Should have the expected type and addititional properties' { + $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl + $branch.BranchName | Should -Be $branch.name + $branch.Sha | Should -Be $branch.commit.sha } + } - Context 'Getting a specific branch for a repository with the repo on the pipeline' { + Context 'Getting a specific branch for a repository with the repo on the pipeline' { + BeforeAll { $branch = $repo | Get-GitHubRepositoryBranch -BranchName $branchName + } - It 'Should return the expected branch name' { - $branch.name | Should -Be $branchName - } + It 'Should return the expected branch name' { + $branch.name | Should -Be $branchName + } - It 'Should have the expected type and addititional properties' { - $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl - $branch.BranchName | Should -Be $branch.name - $branch.Sha | Should -Be $branch.commit.sha - } + It 'Should have the expected type and addititional properties' { + $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl + $branch.BranchName | Should -Be $branch.name + $branch.Sha | Should -Be $branch.commit.sha } + } - Context 'Getting a specific branch for a repository with the branch object on the pipeline' { + Context 'Getting a specific branch for a repository with the branch object on the pipeline' { + BeforeAll { $branch = Get-GitHubRepositoryBranch -OwnerName $script:ownerName -RepositoryName $repositoryName -BranchName $branchName $branchAgain = $branch | Get-GitHubRepositoryBranch + } - It 'Should return the expected branch name' { - $branchAgain.name | Should -Be $branchName - } + It 'Should return the expected branch name' { + $branchAgain.name | Should -Be $branchName + } - It 'Should have the expected type and addititional properties' { - $branchAgain.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branchAgain.RepositoryUrl | Should -Be $repo.RepositoryUrl - $branchAgain.BranchName | Should -Be $branchAgain.name - $branchAgain.Sha | Should -Be $branchAgain.commit.sha - } + It 'Should have the expected type and addititional properties' { + $branchAgain.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branchAgain.RepositoryUrl | Should -Be $repo.RepositoryUrl + $branchAgain.BranchName | Should -Be $branchAgain.name + $branchAgain.Sha | Should -Be $branchAgain.commit.sha } } +} - Describe 'GitHubBranches\New-GitHubRepositoryBranch' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $originBranchName = 'master' - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - AutoInit = $true +Describe 'GitHubBranches\New-GitHubRepositoryBranch' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $originBranchName = 'master' + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + AutoInit = $true + } + + $repo = New-GitHubRepository @newGitHubRepositoryParms + } + + Context 'When creating a new GitHub repository branch' { + Context 'When using non-pipelined parameters' { + BeforeAll { + $newBranchName = 'develop1' + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $originBranchName + TargetBranchName = $newBranchName + } + + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms } - $repo = New-GitHubRepository @newGitHubRepositoryParms + It 'Should have the expected type and addititional properties' { + $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl + $branch.BranchName | Should -Be $newBranchName + $branch.Sha | Should -Be $branch.object.sha + } + + It 'Should have created the branch' { + $getGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $newBranchName + } + + { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | + Should -Not -Throw + } } - Context 'When creating a new GitHub repository branch' { - Context 'When using non-pipelined parameters' { + Context 'When using pipelined parameters' { + Context 'When providing pipeline input for the "Uri" parameter' { BeforeAll { - $newBranchName = 'develop1' - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $originBranchName - TargetBranchName = $newBranchName - } - - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + $newBranchName = 'develop2' + $branch = $repo | New-GitHubRepositoryBranch -TargetBranchName $newBranchName } It 'Should have the expected type and addititional properties' { @@ -156,264 +192,253 @@ try } { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | - Should -Not -Throw + Should -Not -Throw } } - Context 'When using pipelined parameters' { - Context 'When providing pipeline input for the "Uri" parameter' { - BeforeAll { - $newBranchName = 'develop2' - $branch = $repo | New-GitHubRepositoryBranch -TargetBranchName $newBranchName - } - - It 'Should have the expected type and addititional properties' { - $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl - $branch.BranchName | Should -Be $newBranchName - $branch.Sha | Should -Be $branch.object.sha - } - - It 'Should have created the branch' { - $getGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $newBranchName - } - - { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | - Should -Not -Throw - } + Context 'When providing pipeline input for the "TargetBranchName" parameter' { + BeforeAll { + $newBranchName = 'develop3' + $branch = $newBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url } - Context 'When providing pipeline input for the "TargetBranchName" parameter' { - BeforeAll { - $newBranchName = 'develop3' - $branch = $newBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url - } - - It 'Should have the expected type and addititional properties' { - $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl - $branch.BranchName | Should -Be $newBranchName - $branch.Sha | Should -Be $branch.object.sha - } - - It 'Should have created the branch' { - $getGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $newBranchName - } - - { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | - Should -Not -Throw - } + It 'Should have the expected type and addititional properties' { + $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl + $branch.BranchName | Should -Be $newBranchName + $branch.Sha | Should -Be $branch.object.sha } - Context 'When providing the GitHub.Branch on the pipeline' { - BeforeAll { - $baseBranchName = 'develop4' - $baseBranch = $baseBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url - - $newBranchName = 'develop5' - $branch = $baseBranch | New-GitHubRepositoryBranch -TargetBranchName $newBranchName - } - - It 'Should have been created from the right Sha' { - $branch.Sha | Should -Be $baseBranch.Sha + It 'Should have created the branch' { + $getGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $newBranchName } - It 'Should have the expected type and addititional properties' { - $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl - $branch.BranchName | Should -Be $newBranchName - $branch.Sha | Should -Be $branch.object.sha - } + { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | + Should -Not -Throw + } + } - It 'Should have created the branch' { - $getGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $newBranchName - } + Context 'When providing the GitHub.Branch on the pipeline' { + BeforeAll { + $baseBranchName = 'develop4' + $baseBranch = $baseBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url - { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | - Should -Not -Throw - } + $newBranchName = 'develop5' + $branch = $baseBranch | New-GitHubRepositoryBranch -TargetBranchName $newBranchName } - Context 'When providing the Repo on the pipeline and specifying the Sha' { - BeforeAll { - $baseBranchName = 'sha1' - $baseBranch = $baseBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url - - $newBranchName = 'sha2' - $branch = $repo | New-GitHubRepositoryBranch -Sha $baseBranch.Sha -TargetBranchName $newBranchName - } + It 'Should have been created from the right Sha' { + $branch.Sha | Should -Be $baseBranch.Sha + } - It 'Should have been created from the right Sha' { - $branch.Sha | Should -Be $baseBranch.Sha - } + It 'Should have the expected type and addititional properties' { + $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl + $branch.BranchName | Should -Be $newBranchName + $branch.Sha | Should -Be $branch.object.sha + } - It 'Should have the expected type and addititional properties' { - $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' - $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl - $branch.BranchName | Should -Be $newBranchName - $branch.Sha | Should -Be $branch.object.sha + It 'Should have created the branch' { + $getGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $newBranchName } - It 'Should have created the branch' { - $getGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $newBranchName - } - - { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | - Should -Not -Throw - } + { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | + Should -Not -Throw } } - Context 'When the origin branch cannot be found' { - BeforeAll -Scriptblock { - $missingOriginBranchName = 'Missing-Branch' - } + Context 'When providing the Repo on the pipeline and specifying the Sha' { + BeforeAll { + $baseBranchName = 'sha1' + $baseBranch = $baseBranchName | New-GitHubRepositoryBranch -Uri $repo.html_url - It 'Should throw the correct exception' { - $errorMessage = "Origin branch $missingOriginBranchName not found" + $newBranchName = 'sha2' + $branch = $repo | New-GitHubRepositoryBranch -Sha $baseBranch.Sha -TargetBranchName $newBranchName + } - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $missingOriginBranchName - TargetBranchName = $newBranchName - } + It 'Should have been created from the right Sha' { + $branch.Sha | Should -Be $baseBranch.Sha + } - { New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms } | - Should -Throw $errorMessage + It 'Should have the expected type and addititional properties' { + $branch.PSObject.TypeNames[0] | Should -Be 'GitHub.Branch' + $branch.RepositoryUrl | Should -Be $repo.RepositoryUrl + $branch.BranchName | Should -Be $newBranchName + $branch.Sha | Should -Be $branch.object.sha } - } - Context 'When Get-GitHubRepositoryBranch throws an undefined HttpResponseException' { - It 'Should throw the correct exception' { - $newGitHubRepositoryBranchParms = @{ + It 'Should have created the branch' { + $getGitHubRepositoryBranchParms = @{ OwnerName = $script:ownerName - RepositoryName = 'test' - BranchName = 'test' - TargetBranchName = 'test' + RepositoryName = $repoName + BranchName = $newBranchName } - { New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms } | - Should -Throw 'Not Found' + { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | + Should -Not -Throw } } } - AfterAll -ScriptBlock { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } - } - } - - Describe 'GitHubBranches\Remove-GitHubRepositoryBranch' { - BeforeAll -Scriptblock { - $repoName = [Guid]::NewGuid().Guid - $originBranchName = 'master' - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - AutoInit = $true + Context 'When the origin branch cannot be found' { + BeforeAll -Scriptblock { + $missingOriginBranchName = 'Missing-Branch' + $newBranchName = 'sha2' } - $repo = New-GitHubRepository @newGitHubRepositoryParms - } + It 'Should throw the correct exception' { + $errorMessage = "Origin branch $missingOriginBranchName not found" - Context 'When using non-pipelined parameters' { - BeforeAll { - $newBranchName = 'develop1' $newGitHubRepositoryBranchParms = @{ OwnerName = $script:ownerName RepositoryName = $repoName - BranchName = $originBranchName + BranchName = $missingOriginBranchName TargetBranchName = $newBranchName } - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + { New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms } | + Should -Throw $errorMessage } + } - It 'Should not throw an exception' { - $removeGitHubRepositoryBranchParms = @{ + Context 'When Get-GitHubRepositoryBranch throws an undefined HttpResponseException' { + It 'Should throw the correct exception' { + $newGitHubRepositoryBranchParms = @{ OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $newBranchName - Confirm = $false + RepositoryName = 'test' + BranchName = 'test' + TargetBranchName = 'test' } - { Remove-GitHubRepositoryBranch @removeGitHubRepositoryBranchParms } | - Should -Not -Throw + { New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms } | Should -Throw } + } + } - It 'Should have removed the branch' { - $getGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $newBranchName - } + AfterAll -ScriptBlock { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } +} - { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | - Should -Throw - } +Describe 'GitHubBranches\Remove-GitHubRepositoryBranch' { + BeforeAll -Scriptblock { + $repoName = [Guid]::NewGuid().Guid + $originBranchName = 'master' + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + AutoInit = $true } - Context 'When using pipelined parameters' { - BeforeAll { - $newBranchName = 'develop2' - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $originBranchName - TargetBranchName = $newBranchName - } + $repo = New-GitHubRepository @newGitHubRepositoryParms + } - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + Context 'When using non-pipelined parameters' { + BeforeAll { + $newBranchName = 'develop1' + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $originBranchName + TargetBranchName = $newBranchName } - It 'Should not throw an exception' { - { $branch | Remove-GitHubRepositoryBranch -Force } | Should -Not -Throw + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + } + + It 'Should not throw an exception' { + $removeGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $newBranchName + Confirm = $false } - It 'Should have removed the branch' { - $getGitHubRepositoryBranchParms = @{ - OwnerName = $script:ownerName - RepositoryName = $repoName - BranchName = $newBranchName - } + { Remove-GitHubRepositoryBranch @removeGitHubRepositoryBranchParms } | + Should -Not -Throw + } - { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | - Should -Throw + It 'Should have removed the branch' { + $getGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $newBranchName } + + { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | + Should -Throw } + } - AfterAll -ScriptBlock { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + Context 'When using pipelined parameters' { + BeforeAll { + $newBranchName = 'develop2' + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $originBranchName + TargetBranchName = $newBranchName } + + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + } + + It 'Should not throw an exception' { + { $branch | Remove-GitHubRepositoryBranch -Force } | Should -Not -Throw + } + + It 'Should have removed the branch' { + $getGitHubRepositoryBranchParms = @{ + OwnerName = $script:ownerName + RepositoryName = $repoName + BranchName = $newBranchName + } + + { Get-GitHubRepositoryBranch @getGitHubRepositoryBranchParms } | + Should -Throw + } + } + + AfterAll -ScriptBlock { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } - Describe 'GitHubBranches\Get-GitHubRepositoryBranchProtectionRule' { - Context 'When getting GitHub repository branch protection' { +} +Describe 'GitHubBranches\Get-GitHubRepositoryBranchProtectionRule' { + Context 'When getting GitHub repository branch protection' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $branchName = 'master' + $protectionUrl = ("https://api.github.com/repos/$script:ownerName/" + + "$repoName/branches/$branchName/protection") + $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit + New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName | Out-Null + $rule = Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName + } + + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' + $rule.url | Should -Be $protectionUrl + $rule.enforce_admins.enabled | Should -BeFalse + $rule.required_linear_history.enabled | Should -BeFalse + $rule.allow_force_pushes.enabled | Should -BeFalse + $rule.allow_deletions.enabled | Should -BeFalse + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + } + + Context 'When specifying the "Uri" parameter through the pipeline' { BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $branchName = 'master' - $protectionUrl = ("https://api.github.com/repos/$script:ownerName/" + - "$repoName/branches/$branchName/protection") - $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit - New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName | Out-Null - $rule = Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName + $rule = $repo | Get-GitHubRepositoryBranchProtectionRule -BranchName $branchName } It 'Should have the expected type and addititional properties' { @@ -425,944 +450,928 @@ try $rule.allow_deletions.enabled | Should -BeFalse $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl } + } - Context 'When specifying the "Uri" parameter through the pipeline' { - BeforeAll { - $rule = $repo | Get-GitHubRepositoryBranchProtectionRule -BranchName $branchName - } - - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' - $rule.url | Should -Be $protectionUrl - $rule.enforce_admins.enabled | Should -BeFalse - $rule.required_linear_history.enabled | Should -BeFalse - $rule.allow_force_pushes.enabled | Should -BeFalse - $rule.allow_deletions.enabled | Should -BeFalse - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + Context 'When specifying the "BranchName" and "Uri" parameters through the pipeline' { + BeforeAll { + $branch = Get-GitHubRepositoryBranch -Uri $repo.svn_url -BranchName $branchName + $rule = $branch | Get-GitHubRepositoryBranchProtectionRule } - Context 'When specifying the "BranchName" and "Uri" parameters through the pipeline' { - BeforeAll { - $branch = Get-GitHubRepositoryBranch -Uri $repo.svn_url -BranchName $branchName - $rule = $branch | Get-GitHubRepositoryBranchProtectionRule - } - - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' - $rule.url | Should -Be $protectionUrl - $rule.enforce_admins.enabled | Should -BeFalse - $rule.required_linear_history.enabled | Should -BeFalse - $rule.allow_force_pushes.enabled | Should -BeFalse - $rule.allow_deletions.enabled | Should -BeFalse - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' + $rule.url | Should -Be $protectionUrl + $rule.enforce_admins.enabled | Should -BeFalse + $rule.required_linear_history.enabled | Should -BeFalse + $rule.allow_force_pushes.enabled | Should -BeFalse + $rule.allow_deletions.enabled | Should -BeFalse + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl } + } - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } } +} - Describe 'GitHubBranches\New-GitHubRepositoryBranchProtectionRule' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $branchName = 'master' - $newGitHubRepositoryParms = @{ - OrganizationName = $script:organizationName - RepositoryName = $repoName - AutoInit = $true - } - - $repo = New-GitHubRepository @newGitHubRepositoryParms +Describe 'GitHubBranches\New-GitHubRepositoryBranchProtectionRule' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $branchName = 'master' + $newGitHubRepositoryParms = @{ + OrganizationName = $script:organizationName + RepositoryName = $repoName + AutoInit = $true } - Context 'When setting base protection options' { - BeforeAll { - $targetBranchName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository @newGitHubRepositoryParms + } - $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + - "$repoName/branches/$targetBranchName/protection") + Context 'When setting base protection options' { + BeforeAll { + $targetBranchName = [Guid]::NewGuid().Guid - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:organizationName - RepositoryName = $repoName - BranchName = $branchName - TargetBranchName = $targetBranchName - } + $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + + "$repoName/branches/$targetBranchName/protection") - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:organizationName + RepositoryName = $repoName + BranchName = $branchName + TargetBranchName = $targetBranchName + } - $newGitHubRepositoryBranchProtectionParms = @{ - Uri = $repo.svn_url - BranchName = $targetBranchName - EnforceAdmins = $true - RequireLinearHistory = $true - AllowForcePushes = $true - AllowDeletions = $true - } + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms - $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms + $newGitHubRepositoryBranchProtectionParms = @{ + Uri = $repo.svn_url + BranchName = $targetBranchName + EnforceAdmins = $true + RequireLinearHistory = $true + AllowForcePushes = $true + AllowDeletions = $true } - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' - $rule.url | Should -Be $protectionUrl - $rule.enforce_admins.enabled | Should -BeTrue - $rule.required_linear_history.enabled | Should -BeTrue - $rule.allow_force_pushes.enabled | Should -BeTrue - $rule.allow_deletions.enabled | Should -BeTrue - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms } - Context 'When setting required status checks' { - BeforeAll { - $targetBranchName = [Guid]::NewGuid().Guid + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' + $rule.url | Should -Be $protectionUrl + $rule.enforce_admins.enabled | Should -BeTrue + $rule.required_linear_history.enabled | Should -BeTrue + $rule.allow_force_pushes.enabled | Should -BeTrue + $rule.allow_deletions.enabled | Should -BeTrue + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + } + } - $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + - "$repoName/branches/$targetBranchName/protection") + Context 'When setting required status checks' { + BeforeAll { + $targetBranchName = [Guid]::NewGuid().Guid - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:organizationName - RepositoryName = $repoName - BranchName = $branchName - TargetBranchName = $targetBranchName - } + $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + + "$repoName/branches/$targetBranchName/protection") - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:organizationName + RepositoryName = $repoName + BranchName = $branchName + TargetBranchName = $targetBranchName + } - $statusChecks = 'test' + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms - $newGitHubRepositoryBranchProtectionParms = @{ - Uri = $repo.svn_url - BranchName = $targetBranchName - RequireUpToDateBranches = $true - StatusChecks = $statusChecks - } + $statusChecks = 'test' - $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms + $newGitHubRepositoryBranchProtectionParms = @{ + Uri = $repo.svn_url + BranchName = $targetBranchName + RequireUpToDateBranches = $true + StatusChecks = $statusChecks } - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' - $rule.url | Should -Be $protectionUrl - $rule.required_status_checks.strict | Should -BeTrue - $rule.required_status_checks.contexts | Should -Be $statusChecks - } + $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms } - Context 'When setting required pull request reviews' { - BeforeAll { - $targetBranchName = [Guid]::NewGuid().Guid + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' + $rule.url | Should -Be $protectionUrl + $rule.required_status_checks.strict | Should -BeTrue + $rule.required_status_checks.contexts | Should -Be $statusChecks + } + } - $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + - "$repoName/branches/$targetBranchName/protection") + Context 'When setting required pull request reviews' { + BeforeAll { + $targetBranchName = [Guid]::NewGuid().Guid - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:organizationName - RepositoryName = $repoName - BranchName = $branchName - TargetBranchName = $targetBranchName - } + $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + + "$repoName/branches/$targetBranchName/protection") - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:organizationName + RepositoryName = $repoName + BranchName = $branchName + TargetBranchName = $targetBranchName + } - $newGitHubRepositoryBranchProtectionParms = @{ - Uri = $repo.svn_url - BranchName = $targetBranchName - DismissalUsers = $script:ownerName - DismissStaleReviews = $true - RequireCodeOwnerReviews = $true - RequiredApprovingReviewCount = 1 - } + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms - $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms + $newGitHubRepositoryBranchProtectionParms = @{ + Uri = $repo.svn_url + BranchName = $targetBranchName + DismissalUsers = $script:ownerName + DismissStaleReviews = $true + RequireCodeOwnerReviews = $true + RequiredApprovingReviewCount = 1 } - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' - $rule.url | Should -Be $protectionUrl - $rule.required_pull_request_reviews.dismissal_restrictions.users.login | - Should -Contain $script:OwnerName - } + $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms } - Context 'When setting push restrictions' { - BeforeAll { - $targetBranchName = [Guid]::NewGuid().Guid + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' + $rule.url | Should -Be $protectionUrl + $rule.required_pull_request_reviews.dismissal_restrictions.users.login | + Should -Contain $script:OwnerName + } + } - $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + - "$repoName/branches/$targetBranchName/protection") + Context 'When setting push restrictions' { + BeforeAll { + $targetBranchName = [Guid]::NewGuid().Guid - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:organizationName - RepositoryName = $repoName - BranchName = $branchName - TargetBranchName = $targetBranchName - } + $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + + "$repoName/branches/$targetBranchName/protection") - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:organizationName + RepositoryName = $repoName + BranchName = $branchName + TargetBranchName = $targetBranchName + } - $newGitHubRepositoryBranchProtectionParms = @{ - Uri = $repo.svn_url - BranchName = $targetBranchName - RestrictPushUser = $script:OwnerName - } + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms - $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms + $newGitHubRepositoryBranchProtectionParms = @{ + Uri = $repo.svn_url + BranchName = $targetBranchName + RestrictPushUser = $script:OwnerName } - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' - $rule.url | Should -Be $protectionUrl - $rule.restrictions.users.login | Should -Contain $script:OwnerName - } + $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms } - Context 'When the branch rule already exists' { - BeforeAll { - $targetBranchName = [Guid]::NewGuid().Guid + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' + $rule.url | Should -Be $protectionUrl + $rule.restrictions.users.login | Should -Contain $script:OwnerName + } + } - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:organizationName - RepositoryName = $repoName - BranchName = $branchName - TargetBranchName = $targetBranchName - } + Context 'When the branch rule already exists' { + BeforeAll { + $targetBranchName = [Guid]::NewGuid().Guid - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:organizationName + RepositoryName = $repoName + BranchName = $branchName + TargetBranchName = $targetBranchName + } - $newGitHubRepositoryBranchProtectionParms = @{ - Uri = $repo.svn_url - BranchName = $targetBranchName - } + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms - $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms + $newGitHubRepositoryBranchProtectionParms = @{ + Uri = $repo.svn_url + BranchName = $targetBranchName } - It 'Should throw the correct exception' { - $errorMessage = "Branch protection rule for branch $targetBranchName already exists on Repository $repoName" - { New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms } | - Should -Throw $errorMessage - } + $rule = New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms } - Context 'When specifying the "Uri" parameter through the pipeline' { - BeforeAll { - $targetBranchName = [Guid]::NewGuid().Guid + It 'Should throw the correct exception' { + $errorMessage = "Branch protection rule for branch $targetBranchName already exists on Repository $repoName" + { New-GitHubRepositoryBranchProtectionRule @newGitHubRepositoryBranchProtectionParms } | + Should -Throw $errorMessage + } + } - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:organizationName - RepositoryName = $repoName - BranchName = $branchName - TargetBranchName = $targetBranchName - } + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $targetBranchName = [Guid]::NewGuid().Guid - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:organizationName + RepositoryName = $repoName + BranchName = $branchName + TargetBranchName = $targetBranchName + } + + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms - $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + + $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + "$repoName/branches/$targetBranchName/protection") - $rule = $repo | New-GitHubRepositoryBranchProtectionRule -BranchName $targetBranchName - } + $rule = $repo | New-GitHubRepositoryBranchProtectionRule -BranchName $targetBranchName + } - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' - $rule.url | Should -Be $protectionUrl - $rule.enforce_admins.enabled | Should -BeFalse - $rule.required_linear_history.enabled | Should -BeFalse - $rule.allow_force_pushes.enabled | Should -BeFalse - $rule.allow_deletions.enabled | Should -BeFalse - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' + $rule.url | Should -Be $protectionUrl + $rule.enforce_admins.enabled | Should -BeFalse + $rule.required_linear_history.enabled | Should -BeFalse + $rule.allow_force_pushes.enabled | Should -BeFalse + $rule.allow_deletions.enabled | Should -BeFalse + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl } + } - Context 'When specifying the "BranchName" and "Uri" parameters through the pipeline' { - BeforeAll { - $targetBranchName = [Guid]::NewGuid().Guid + Context 'When specifying the "BranchName" and "Uri" parameters through the pipeline' { + BeforeAll { + $targetBranchName = [Guid]::NewGuid().Guid - $newGitHubRepositoryBranchParms = @{ - OwnerName = $script:organizationName - RepositoryName = $repoName - BranchName = $branchName - TargetBranchName = $targetBranchName - } + $newGitHubRepositoryBranchParms = @{ + OwnerName = $script:organizationName + RepositoryName = $repoName + BranchName = $branchName + TargetBranchName = $targetBranchName + } - $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms + $branch = New-GitHubRepositoryBranch @newGitHubRepositoryBranchParms - $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + + $protectionUrl = ("https://api.github.com/repos/$script:organizationName/" + "$repoName/branches/$targetBranchName/protection") - $rule = $branch | New-GitHubRepositoryBranchProtectionRule + $rule = $branch | New-GitHubRepositoryBranchProtectionRule + } + + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' + $rule.url | Should -Be $protectionUrl + $rule.enforce_admins.enabled | Should -BeFalse + $rule.required_linear_history.enabled | Should -BeFalse + $rule.allow_force_pushes.enabled | Should -BeFalse + $rule.allow_deletions.enabled | Should -BeFalse + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + } + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } +} + +Describe 'GitHubBranches\Remove-GitHubRepositoryBranchProtectionRule' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $branchName = 'master' + $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit + + New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName | + Out-Null + } + + Context 'When removing GitHub repository branch protection' { + It 'Should not throw' { + { Remove-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName -Force } | + Should -Not -Throw + } + + It 'Should have removed the protection rule' { + { Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } | + Should -Throw + } + + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $rule = New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchProtectionRule' - $rule.url | Should -Be $protectionUrl - $rule.enforce_admins.enabled | Should -BeFalse - $rule.required_linear_history.enabled | Should -BeFalse - $rule.allow_force_pushes.enabled | Should -BeFalse - $rule.allow_deletions.enabled | Should -BeFalse - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + It 'Should not throw' { + { $repo | Remove-GitHubRepositoryBranchProtectionRule -BranchName $branchName -Force } | + Should -Not -Throw } - } - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + It 'Should have removed the protection rule' { + { Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } | + Should -Throw } } - } - Describe 'GitHubBranches\Remove-GitHubRepositoryBranchProtectionRule' { - Context 'When removing GitHub repository branch protection' { + Context 'When specifying the "Uri" and "BranchName" parameters through the pipeline' { BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $branchName = 'master' - $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit - - New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName | - Out-Null + $rule = New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } It 'Should not throw' { - { Remove-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName -Force } | - Should -Not -Throw + { $rule | Remove-GitHubRepositoryBranchProtectionRule -Force } | + Should -Not -Throw } It 'Should have removed the protection rule' { { Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } | - Should -Throw + Should -Throw } + } - Context 'When specifying the "Uri" parameter through the pipeline' { - BeforeAll { - $rule = New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName - } - - It 'Should not throw' { - { $repo | Remove-GitHubRepositoryBranchProtectionRule -BranchName $branchName -Force} | - Should -Not -Throw - } + } + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } +} - It 'Should have removed the protection rule' { - { Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } | - Should -Throw - } - } +Describe 'GitHubBranches\Get-GitHubRepositoryBranchPatternProtectionRule' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - Context 'When specifying the "Uri" and "BranchName" parameters through the pipeline' { - BeforeAll { - $rule = New-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName - } + $newGitHubRepositoryParms = @{ + OrganizationName = $script:organizationName + RepositoryName = $repoName + } + $repo = New-GitHubRepository @newGitHubRepositoryParms - It 'Should not throw' { - { $rule | Remove-GitHubRepositoryBranchProtectionRule -Force } | - Should -Not -Throw - } + $teamName = [Guid]::NewGuid().Guid - It 'Should have removed the protection rule' { - { Get-GitHubRepositoryBranchProtectionRule -Uri $repo.svn_url -BranchName $branchName } | - Should -Throw - } - } + $newGithubTeamParms = @{ + OrganizationName = $script:OrganizationName + TeamName = $teamName + } + $team = New-GitHubTeam @newGithubTeamParms - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } - } + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = 'Push' } + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } - Describe 'GitHubBranches\Get-GitHubRepositoryBranchPatternProtectionRule' { + Context 'When getting branch pattern protection default options' { BeforeAll { - $repoName = [Guid]::NewGuid().Guid + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $newGitHubRepositoryParms = @{ - OrganizationName = $script:organizationName - RepositoryName = $repoName - } - $repo = New-GitHubRepository @newGitHubRepositoryParms + New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - $teamName = [Guid]::NewGuid().Guid + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + } - $newGithubTeamParms = @{ - OrganizationName = $script:OrganizationName - TeamName = $teamName - } - $team = New-GitHubTeam @newGithubTeamParms + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeFalse + $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty + $rule.dismissesStaleReviews | Should -BeFalse + $rule.requiresCodeOwnerReviews | Should -BeFalse + $rule.restrictsReviewDismissals | Should -BeFalse + $rule.DismissalTeams | Should -BeNullOrEmpty + $rule.DismissalUsers | Should -BeNullOrEmpty + $rule.requiresStatusChecks | Should -BeFalse + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty + $rule.requiresCommitSignatures | Should -BeFalse + $rule.requiresLinearHistory | Should -BeFalse + $rule.isAdminEnforced | Should -BeFalse + $rule.restrictsPushes | Should -BeFalse + $rule.RestrictPushUsers | Should -BeNullOrEmpty + $rule.RestrictPushTeams | Should -BeNullOrEmpty + $rule.RestictPushApps | Should -BeNullOrEmpty + $rule.allowsForcePushes | Should -BeFalse + $rule.allowsDeletions | Should -BeFalse + } + } + + Context 'When getting base protection options' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $setGitHubRepositoryTeamPermissionParms = @{ + $newGitHubRepositoryBranchPatternProtectionParms = @{ Uri = $repo.svn_url - TeamSlug = $team.slug - Permission = 'Push' - } - Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + BranchPatternName = $branchPatternName + RequireCommitSignatures = $true + RequireLinearHistory = $true + IsAdminEnforced = $true + RestrictPushUser = $script:OwnerName + RestrictPushTeam = $TeamName + AllowForcePushes = $true + AllowDeletions = $true + } + New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms + + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } - Context 'When getting branch pattern protection default options' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeFalse + $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty + $rule.dismissesStaleReviews | Should -BeFalse + $rule.requiresCodeOwnerReviews | Should -BeFalse + $rule.restrictsReviewDismissals | Should -BeFalse + $rule.DismissalTeams | Should -BeNullOrEmpty + $rule.DismissalUsers | Should -BeNullOrEmpty + $rule.requiresStatusChecks | Should -BeFalse + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty + $rule.requiresCommitSignatures | Should -BeTrue + $rule.requiresLinearHistory | Should -BeTrue + $rule.isAdminEnforced | Should -BeTrue + $rule.restrictsPushes | Should -BeTrue + $rule.RestrictPushUsers.Count | Should -Be 1 + $rule.RestrictPushUsers | Should -Contain $script:OwnerName + $rule.RestrictPushTeams.Count | Should -Be 1 + $rule.RestrictPushTeams | Should -Contain $teamName + $rule.RestrictPushApps | Should -BeNullOrEmpty + $rule.allowsForcePushes | Should -BeTrue + $rule.allowsDeletions | Should -BeTrue + } + } - New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + Context 'When getting required pull request reviews' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequiredApprovingReviewCount = 1 + DismissStaleReviews = $true + RequireCodeOwnerReviews = $true + DismissalUser = $script:OwnerName + DismissalTeam = $teamName } + New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - $rule.requiresApprovingReviews | Should -BeFalse - $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty - $rule.dismissesStaleReviews | Should -BeFalse - $rule.requiresCodeOwnerReviews | Should -BeFalse - $rule.restrictsReviewDismissals | Should -BeFalse - $rule.DismissalTeams | Should -BeNullOrEmpty - $rule.DismissalUsers | Should -BeNullOrEmpty - $rule.requiresStatusChecks | Should -BeFalse - $rule.requiresStrictStatusChecks | Should -BeTrue - $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty - $rule.requiresCommitSignatures | Should -BeFalse - $rule.requiresLinearHistory | Should -BeFalse - $rule.isAdminEnforced | Should -BeFalse - $rule.restrictsPushes | Should -BeFalse - $rule.RestrictPushUsers | Should -BeNullOrEmpty - $rule.RestrictPushTeams | Should -BeNullOrEmpty - $rule.RestictPushApps | Should -BeNullOrEmpty - $rule.allowsForcePushes | Should -BeFalse - $rule.allowsDeletions | Should -BeFalse - } + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } - Context 'When getting base protection options' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + It 'Should have the expected type and addititional properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeTrue + $rule.requiredApprovingReviewCount | Should -Be 1 + $rule.dismissesStaleReviews | Should -BeTrue + $rule.requiresCodeOwnerReviews | Should -BeTrue + $rule.restrictsReviewDismissals | Should -BeTrue + $rule.DismissalTeams.Count | Should -Be 1 + $rule.DismissalTeams | Should -Contain $teamName + $rule.DismissalUsers.Count | Should -Be 1 + $rule.DismissalUsers | Should -Contain $script:OwnerName + } + } - $newGitHubRepositoryBranchPatternProtectionParms = @{ - Uri = $repo.svn_url - BranchPatternName = $branchPatternName - RequireCommitSignatures = $true - RequireLinearHistory = $true - IsAdminEnforced = $true - RestrictPushUser = $script:OwnerName - RestrictPushTeam = $TeamName - AllowForcePushes = $true - AllowDeletions = $true - } - New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms + Context 'When getting required status checks' { + BeforeAll { + $statusChecks = 'test' - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequireStrictStatusChecks = $true + StatusCheck = $statusChecks } + New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - $rule.requiresApprovingReviews | Should -BeFalse - $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty - $rule.dismissesStaleReviews | Should -BeFalse - $rule.requiresCodeOwnerReviews | Should -BeFalse - $rule.restrictsReviewDismissals | Should -BeFalse - $rule.DismissalTeams | Should -BeNullOrEmpty - $rule.DismissalUsers | Should -BeNullOrEmpty - $rule.requiresStatusChecks | Should -BeFalse - $rule.requiresStrictStatusChecks | Should -BeTrue - $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty - $rule.requiresCommitSignatures | Should -BeTrue - $rule.requiresLinearHistory | Should -BeTrue - $rule.isAdminEnforced | Should -BeTrue - $rule.restrictsPushes | Should -BeTrue - $rule.RestrictPushUsers.Count | Should -Be 1 - $rule.RestrictPushUsers | Should -Contain $script:OwnerName - $rule.RestrictPushTeams.Count | Should -Be 1 - $rule.RestrictPushTeams | Should -Contain $teamName - $rule.RestrictPushApps | Should -BeNullOrEmpty - $rule.allowsForcePushes | Should -BeTrue - $rule.allowsDeletions | Should -BeTrue - } + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } - Context 'When getting required pull request reviews' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresStatusChecks | Should -BeTrue + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -Contain $statusChecks + } + } - $newGitHubRepositoryBranchPatternProtectionParms = @{ - Uri = $repo.svn_url - BranchPatternName = $branchPatternName - RequiredApprovingReviewCount = 1 - DismissStaleReviews = $true - RequireCodeOwnerReviews = $true - DismissalUser = $script:OwnerName - DismissalTeam = $teamName - } - New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $rule = $repo | Get-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName + } - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - } + It 'Should have the expected type and addititional properties' { + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + } + } - It 'Should have the expected type and addititional properties' { - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - $rule.requiresApprovingReviews | Should -BeTrue - $rule.requiredApprovingReviewCount | Should -Be 1 - $rule.dismissesStaleReviews | Should -BeTrue - $rule.requiresCodeOwnerReviews | Should -BeTrue - $rule.restrictsReviewDismissals | Should -BeTrue - $rule.DismissalTeams.Count | Should -Be 1 - $rule.DismissalTeams | Should -Contain $teamName - $rule.DismissalUsers.Count | Should -Be 1 - $rule.DismissalUsers | Should -Contain $script:OwnerName - } + AfterAll -ScriptBlock { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force } - Context 'When getting required status checks' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $statusChecks = 'test' + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } +} - $newGitHubRepositoryBranchPatternProtectionParms = @{ - Uri = $repo.svn_url - BranchPatternName = $branchPatternName - RequireStrictStatusChecks = $true - StatusCheck = $statusChecks - } - New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms +Describe 'GitHubBranches\New-GitHubRepositoryBranchPatternProtectionRule' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - } + $newGitHubRepositoryParms = @{ + OrganizationName = $script:organizationName + RepositoryName = $repoName + } + $repo = New-GitHubRepository @newGitHubRepositoryParms - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - $rule.requiresStatusChecks | Should -BeTrue - $rule.requiresStrictStatusChecks | Should -BeTrue - $rule.requiredStatusCheckContexts | Should -Contain $statusChecks - } + $pushTeamName = [Guid]::NewGuid().Guid + + $newGithubTeamParms = @{ + OrganizationName = $script:OrganizationName + TeamName = $pushTeamName } + $pushTeam = New-GitHubTeam @newGithubTeamParms - Context 'When specifying the "Uri" parameter through the pipeline' { - BeforeAll { - $rule = $repo | Get-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName - } + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $pushTeam.slug + Permission = 'Push' + } + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms - It 'Should have the expected type and addititional properties' { - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + $pullTeamName = [Guid]::NewGuid().Guid + + $newGithubTeamParms = @{ + OrganizationName = $script:OrganizationName + TeamName = $pullTeamName } + $pullTeam = New-GitHubTeam @newGithubTeamParms - AfterAll -ScriptBlock { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - $repo | Remove-GitHubRepository -Force - } + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $pullTeam.slug - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } + Permission = 'Pull' } + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } - Describe 'GitHubBranches\New-GitHubRepositoryBranchPatternProtectionRule' { + Context 'When setting default protection options' { BeforeAll { - $repoName = [Guid]::NewGuid().Guid + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $newGitHubRepositoryParms = @{ - OrganizationName = $script:organizationName - RepositoryName = $repoName + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName } - $repo = New-GitHubRepository @newGitHubRepositoryParms - - $pushTeamName = [Guid]::NewGuid().Guid + } - $newGithubTeamParms = @{ - OrganizationName = $script:OrganizationName - TeamName = $pushTeamName - } - $pushTeam = New-GitHubTeam @newGithubTeamParms + It 'Should not throw' { + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Not -Throw + } - $setGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $pushTeam.slug - Permission = 'Push' - } - Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeFalse + $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty + $rule.dismissesStaleReviews | Should -BeFalse + $rule.requiresCodeOwnerReviews | Should -BeFalse + $rule.restrictsReviewDismissals | Should -BeFalse + $rule.DismissalTeams | Should -BeNullOrEmpty + $rule.DismissalUsers | Should -BeNullOrEmpty + $rule.requiresStatusChecks | Should -BeFalse + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty + $rule.requiresCommitSignatures | Should -BeFalse + $rule.requiresLinearHistory | Should -BeFalse + $rule.isAdminEnforced | Should -BeFalse + $rule.restrictsPushes | Should -BeFalse + $rule.RestrictPushUsers | Should -BeNullOrEmpty + $rule.RestrictPushTeams | Should -BeNullOrEmpty + $rule.RestictPushApps | Should -BeNullOrEmpty + $rule.allowsForcePushes | Should -BeFalse + $rule.allowsDeletions | Should -BeFalse + } + } - $pullTeamName = [Guid]::NewGuid().Guid + Context 'When setting base protection options' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $newGithubTeamParms = @{ - OrganizationName = $script:OrganizationName - TeamName = $pullTeamName + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequireCommitSignatures = $true + RequireLinearHistory = $true + IsAdminEnforced = $true + RestrictPushUser = $script:OwnerName + RestrictPushTeam = $pushTeamName + AllowForcePushes = $true + AllowDeletions = $true } - $pullTeam = New-GitHubTeam @newGithubTeamParms + } - $setGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $pullTeam.slug + It 'Should not throw' { + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Not -Throw + } - Permission = 'Pull' - } - Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeFalse + $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty + $rule.dismissesStaleReviews | Should -BeFalse + $rule.requiresCodeOwnerReviews | Should -BeFalse + $rule.restrictsReviewDismissals | Should -BeFalse + $rule.DismissalTeams | Should -BeNullOrEmpty + $rule.DismissalUsers | Should -BeNullOrEmpty + $rule.requiresStatusChecks | Should -BeFalse + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty + $rule.requiresCommitSignatures | Should -BeTrue + $rule.requiresLinearHistory | Should -BeTrue + $rule.isAdminEnforced | Should -BeTrue + $rule.restrictsPushes | Should -BeTrue + $rule.RestrictPushUsers.Count | Should -Be 1 + $rule.RestrictPushUsers | Should -Contain $script:OwnerName + $rule.RestrictPushTeams.Count | Should -Be 1 + $rule.RestrictPushTeams | Should -Contain $pushTeamName + $rule.RestrictPushApps | Should -BeNullOrEmpty + $rule.allowsForcePushes | Should -BeTrue + $rule.allowsDeletions | Should -BeTrue } - Context 'When setting default protection options' { + Context 'When the Restrict Push Team does not exist in the organization' { BeforeAll { $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + $mockTeamName = 'MockTeam' $newGitHubRepositoryBranchPatternProtectionParms = @{ Uri = $repo.svn_url BranchPatternName = $branchPatternName + RestrictPushTeam = $mockTeamName } } - It 'Should not throw' { + It 'Should throw the correct exception' { + $errorMessage = "Team '$mockTeamName' not found in organization '$OrganizationName'" { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Not -Throw - } - - It 'Should have set the correct properties' { - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - $rule.requiresApprovingReviews | Should -BeFalse - $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty - $rule.dismissesStaleReviews | Should -BeFalse - $rule.requiresCodeOwnerReviews | Should -BeFalse - $rule.restrictsReviewDismissals | Should -BeFalse - $rule.DismissalTeams | Should -BeNullOrEmpty - $rule.DismissalUsers | Should -BeNullOrEmpty - $rule.requiresStatusChecks | Should -BeFalse - $rule.requiresStrictStatusChecks | Should -BeTrue - $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty - $rule.requiresCommitSignatures | Should -BeFalse - $rule.requiresLinearHistory | Should -BeFalse - $rule.isAdminEnforced | Should -BeFalse - $rule.restrictsPushes | Should -BeFalse - $rule.RestrictPushUsers | Should -BeNullOrEmpty - $rule.RestrictPushTeams | Should -BeNullOrEmpty - $rule.RestictPushApps | Should -BeNullOrEmpty - $rule.allowsForcePushes | Should -BeFalse - $rule.allowsDeletions | Should -BeFalse + Should -Throw $errorMessage } } - Context 'When setting base protection options' { + Context 'When the Restrict Push Team does not have push Permissions to the Repository' { BeforeAll { $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' $newGitHubRepositoryBranchPatternProtectionParms = @{ Uri = $repo.svn_url BranchPatternName = $branchPatternName - RequireCommitSignatures = $true - RequireLinearHistory = $true - IsAdminEnforced = $true - RestrictPushUser = $script:OwnerName - RestrictPushTeam = $pushTeamName - AllowForcePushes = $true - AllowDeletions = $true + RestrictPushTeam = $pullTeamName } } - It 'Should not throw' { + It 'Should throw the correct exception' { + $errorMessage = "Team '$pullTeamName' does not have push or maintain permissions on repository '$OrganizationName/$repoName'" { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Not -Throw - } - - It 'Should have set the correct properties' { - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - $rule.requiresApprovingReviews | Should -BeFalse - $rule.requiredApprovingReviewCount | Should -BeNullOrEmpty - $rule.dismissesStaleReviews | Should -BeFalse - $rule.requiresCodeOwnerReviews | Should -BeFalse - $rule.restrictsReviewDismissals | Should -BeFalse - $rule.DismissalTeams | Should -BeNullOrEmpty - $rule.DismissalUsers | Should -BeNullOrEmpty - $rule.requiresStatusChecks | Should -BeFalse - $rule.requiresStrictStatusChecks | Should -BeTrue - $rule.requiredStatusCheckContexts | Should -BeNullOrEmpty - $rule.requiresCommitSignatures | Should -BeTrue - $rule.requiresLinearHistory | Should -BeTrue - $rule.isAdminEnforced | Should -BeTrue - $rule.restrictsPushes | Should -BeTrue - $rule.RestrictPushUsers.Count | Should -Be 1 - $rule.RestrictPushUsers | Should -Contain $script:OwnerName - $rule.RestrictPushTeams.Count | Should -Be 1 - $rule.RestrictPushTeams | Should -Contain $pushTeamName - $rule.RestrictPushApps | Should -BeNullOrEmpty - $rule.allowsForcePushes | Should -BeTrue - $rule.allowsDeletions | Should -BeTrue + Should -Throw $errorMessage } + } + } - Context 'When the Restrict Push Team does not exist in the organization' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $mockTeamName = 'MockTeam' - - $newGitHubRepositoryBranchPatternProtectionParms = @{ - Uri = $repo.svn_url - BranchPatternName = $branchPatternName - RestrictPushTeam = $mockTeamName - } - } + Context 'When setting required pull request reviews' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - It 'Should throw the correct exception' { - $errorMessage = "Team '$mockTeamName' not found in organization '$OrganizationName'" - { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Throw $errorMessage - } + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequiredApprovingReviewCount = 1 + DismissStaleReviews = $true + RequireCodeOwnerReviews = $true + DismissalUser = $script:OwnerName + DismissalTeam = $pushTeamName } + } - Context 'When the Restrict Push Team does not have push Permissions to the Repository' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - - $newGitHubRepositoryBranchPatternProtectionParms = @{ - Uri = $repo.svn_url - BranchPatternName = $branchPatternName - RestrictPushTeam = $pullTeamName - } - } + It 'Should not throw' { + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Not -Throw + } - It 'Should throw the correct exception' { - $errorMessage = "Team '$pullTeamName' does not have push or maintain permissions on repository '$OrganizationName/$repoName'" - { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Throw $errorMessage - } - } + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresApprovingReviews | Should -BeTrue + $rule.requiredApprovingReviewCount | Should -Be 1 + $rule.dismissesStaleReviews | Should -BeTrue + $rule.requiresCodeOwnerReviews | Should -BeTrue + $rule.restrictsReviewDismissals | Should -BeTrue + $rule.DismissalTeams.Count | Should -Be 1 + $rule.DismissalTeams | Should -Contain $pushTeamName + $rule.DismissalUsers.Count | Should -Be 1 + $rule.DismissalUsers | Should -Contain $script:OwnerName } - Context 'When setting required pull request reviews' { + Context 'When the Dismissal Team does not exist in the organization' { BeforeAll { $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + $mockTeamName = 'MockTeam' $newGitHubRepositoryBranchPatternProtectionParms = @{ Uri = $repo.svn_url BranchPatternName = $branchPatternName - RequiredApprovingReviewCount = 1 - DismissStaleReviews = $true - RequireCodeOwnerReviews = $true - DismissalUser = $script:OwnerName - DismissalTeam = $pushTeamName + DismissalTeam = $mockTeamName } } - It 'Should not throw' { + It 'Should throw the correct exception' { + $errorMessage = "Team '$mockTeamName' not found in organization '$OrganizationName'" { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Not -Throw - } - - It 'Should have set the correct properties' { - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - $rule.requiresApprovingReviews | Should -BeTrue - $rule.requiredApprovingReviewCount | Should -Be 1 - $rule.dismissesStaleReviews | Should -BeTrue - $rule.requiresCodeOwnerReviews | Should -BeTrue - $rule.restrictsReviewDismissals | Should -BeTrue - $rule.DismissalTeams.Count | Should -Be 1 - $rule.DismissalTeams | Should -Contain $pushTeamName - $rule.DismissalUsers.Count | Should -Be 1 - $rule.DismissalUsers | Should -Contain $script:OwnerName - } - - Context 'When the Dismissal Team does not exist in the organization' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $mockTeamName = 'MockTeam' - - $newGitHubRepositoryBranchPatternProtectionParms = @{ - Uri = $repo.svn_url - BranchPatternName = $branchPatternName - DismissalTeam = $mockTeamName - } - } - - It 'Should throw the correct exception' { - $errorMessage = "Team '$mockTeamName' not found in organization '$OrganizationName'" - { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Throw $errorMessage - } - } - - Context 'When the Dismissal Team does not have write Permissions to the Repository' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - - $newGitHubRepositoryBranchPatternProtectionParms = @{ - Uri = $repo.svn_url - BranchPatternName = $branchPatternName - DismissalTeam = $pullTeamName - } - } - - It 'Should throw the correct exception' { - $errorMessage = "Team '$pullTeamName' does not have push or maintain permissions on repository '$OrganizationName/$repoName'" - { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Throw $errorMessage - } + Should -Throw $errorMessage } } - Context 'When setting required status checks' { + Context 'When the Dismissal Team does not have write Permissions to the Repository' { BeforeAll { $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - $statusCheck = 'test' $newGitHubRepositoryBranchPatternProtectionParms = @{ Uri = $repo.svn_url BranchPatternName = $branchPatternName - RequireStrictStatusChecks = $true - StatusCheck = $statusCheck + DismissalTeam = $pullTeamName } } - It 'Should not throw' { + It 'Should throw the correct exception' { + $errorMessage = "Team '$pullTeamName' does not have push or maintain permissions on repository '$OrganizationName/$repoName'" { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Not -Throw + Should -Throw $errorMessage } + } + } - It 'Should have set the correct properties' { - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + Context 'When setting required status checks' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + $statusCheck = 'test' - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - $rule.requiresStatusChecks | Should -BeTrue - $rule.requiresStrictStatusChecks | Should -BeTrue - $rule.requiredStatusCheckContexts | Should -Contain $statusCheck + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName + RequireStrictStatusChecks = $true + StatusCheck = $statusCheck } } - Context 'When the branch pattern rule already exists' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + It 'Should not throw' { + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Not -Throw + } - $newGitHubRepositoryBranchPatternProtectionParms = @{ - Uri = $repo.svn_url - BranchPatternName = $branchPatternName - } - $rule = New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms - } + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - It 'Should throw the correct exception' { - $errorMessage = "Name already protected: $branchPatternName" - { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | - Should -Throw $errorMessage - } + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl + $rule.requiresStatusChecks | Should -BeTrue + $rule.requiresStrictStatusChecks | Should -BeTrue + $rule.requiredStatusCheckContexts | Should -Contain $statusCheck } + } - Context 'When specifying the "Uri" parameter through the pipeline' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - } + Context 'When the branch pattern rule already exists' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - It 'Should not throw' { - { $repo | New-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName } | - Should -Not -Throw + $newGitHubRepositoryBranchPatternProtectionParms = @{ + Uri = $repo.svn_url + BranchPatternName = $branchPatternName } + $rule = New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms + } - It 'Should have set the correct properties' { - $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName + It 'Should throw the correct exception' { + $errorMessage = "GraphQl Error: Name already protected: $branchPatternName" + { New-GitHubRepositoryBranchPatternProtectionRule @newGitHubRepositoryBranchPatternProtectionParms } | + Should -Throw $errorMessage + } + } - $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' - $rule.pattern | Should -Be $branchPatternName - $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' } - AfterAll -ScriptBlock { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - $repo | Remove-GitHubRepository -Force - } + It 'Should not throw' { + { $repo | New-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName } | + Should -Not -Throw + } - if (Get-Variable -Name pushTeam -ErrorAction SilentlyContinue) - { - $pushTeam | Remove-GitHubTeam -Force - } + It 'Should have set the correct properties' { + $rule = Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - if (Get-Variable -Name pullTeam -ErrorAction SilentlyContinue) - { - $pullTeam | Remove-GitHubTeam -Force - } + $rule.PSObject.TypeNames[0] | Should -Be 'GitHub.BranchPatternProtectionRule' + $rule.pattern | Should -Be $branchPatternName + $rule.RepositoryUrl | Should -Be $repo.RepositoryUrl } } - Describe 'GitHubBranches\Remove-GitHubRepositoryBranchPatternProtectionRule' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid + AfterAll -ScriptBlock { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } - $repo = New-GitHubRepository -RepositoryName $repoName + if (Get-Variable -Name pushTeam -ErrorAction SilentlyContinue) + { + $pushTeam | Remove-GitHubTeam -Force } - Context 'When removing GitHub repository branch pattern protection' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + if (Get-Variable -Name pullTeam -ErrorAction SilentlyContinue) + { + $pullTeam | Remove-GitHubTeam -Force + } + } +} - New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - } +Describe 'GitHubBranches\Remove-GitHubRepositoryBranchPatternProtectionRule' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid - It 'Should not throw' { - { Remove-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName -Force } | - Should -Not -Throw - } + $repo = New-GitHubRepository -RepositoryName $repoName + } - It 'Should have removed the protection rule' { - { Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } | - Should -Throw - } + Context 'When removing GitHub repository branch pattern protection' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + + New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } - Context 'When specifying the "Uri" parameter through the pipeline' { - BeforeAll { - $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' + It 'Should not throw' { + { Remove-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName -Force } | + Should -Not -Throw + } - $rule = New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName - } + It 'Should have removed the protection rule' { + { Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } | + Should -Throw + } + } - It 'Should not throw' { - { $repo | Remove-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName -Force} | - Should -Not -Throw - } + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $branchPatternName = [Guid]::NewGuid().Guid + '/**/*' - It 'Should have removed the protection rule' { - { Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } | - Should -Throw - } + $rule = New-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } - AfterAll { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - $repo | Remove-GitHubRepository -Force - } + It 'Should not throw' { + { $repo | Remove-GitHubRepositoryBranchPatternProtectionRule -BranchPatternName $branchPatternName -Force } | + Should -Not -Throw + } + + It 'Should have removed the protection rule' { + { Get-GitHubRepositoryBranchPatternProtectionRule -Uri $repo.svn_url -BranchPatternName $branchPatternName } | + Should -Throw + } + } + + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubContents.tests.ps1 b/Tests/GitHubContents.tests.ps1 index 10e85c79..f33ea354 100644 --- a/Tests/GitHubContents.tests.ps1 +++ b/Tests/GitHubContents.tests.ps1 @@ -8,15 +8,14 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readonly, hidden variables. @{ repoGuid = [Guid]::NewGuid().Guid @@ -32,364 +31,376 @@ try }.GetEnumerator() | ForEach-Object { Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value } +} - Describe 'Getting file and folder content' { - BeforeAll { - # AutoInit will create a readme with the GUID of the repo name - $repo = New-GitHubRepository -RepositoryName ($repoGuid) -AutoInit - } +Describe 'Getting file and folder content' { + BeforeAll { + # AutoInit will create a readme with the GUID of the repo name + $repo = New-GitHubRepository -RepositoryName ($repoGuid) -AutoInit + } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } - Context 'For getting folder contents with parameters' { + Context 'For getting folder contents with parameters' { + BeforeAll { $folderOutput = Get-GitHubContent -OwnerName $script:ownerName -RepositoryName $repo.name + } - It "Should have the expected name" { - $folderOutput.name | Should -BeNullOrEmpty - } + It "Should have the expected name" { + $folderOutput.name | Should -BeNullOrEmpty + } - It "Should have the expected path" { - $folderOutput.path | Should -BeNullOrEmpty - } + It "Should have the expected path" { + $folderOutput.path | Should -BeNullOrEmpty + } - It "Should have the expected type" { - $folderOutput.type | Should -Be "dir" - } + It "Should have the expected type" { + $folderOutput.type | Should -Be "dir" + } - It "Should have the expected entries" { - $folderOutput.entries.length | Should -Be 1 - } + It "Should have the expected entries" { + $folderOutput.entries.length | Should -Be 1 + } - It "Should have the expected entry data" { - $folderOutput.entries[0].name | Should -Be $readmeFileName - $folderOutput.entries[0].path | Should -Be $readmeFileName - } + It "Should have the expected entry data" { + $folderOutput.entries[0].name | Should -Be $readmeFileName + $folderOutput.entries[0].path | Should -Be $readmeFileName + } - It "Should have the expected type and additional properties" { - $folderOutput.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' - $folderOutput.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + It "Should have the expected type and additional properties" { + $folderOutput.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' + $folderOutput.RepositoryUrl | Should -Be $repo.RepositoryUrl } + } - Context 'For getting folder contents via URL' { + Context 'For getting folder contents via URL' { + BeforeAll { $folderOutput = Get-GitHubContent -Uri "https://github.com/$($script:ownerName)/$($repo.name)" + } - It "Should have the expected name" { - $folderOutput.name | Should -BeNullOrEmpty - } + It "Should have the expected name" { + $folderOutput.name | Should -BeNullOrEmpty + } - It "Should have the expected path" { - $folderOutput.path | Should -BeNullOrEmpty - } + It "Should have the expected path" { + $folderOutput.path | Should -BeNullOrEmpty + } - It "Should have the expected type" { - $folderOutput.type | Should -Be "dir" - } + It "Should have the expected type" { + $folderOutput.type | Should -Be "dir" + } - It "Should have the expected entries" { - $folderOutput.entries.length | Should -Be 1 - } + It "Should have the expected entries" { + $folderOutput.entries.length | Should -Be 1 + } - It "Should have the expected entry data" { - $folderOutput.entries[0].name | Should -Be $readmeFileName - $folderOutput.entries[0].path | Should -Be $readmeFileName - } + It "Should have the expected entry data" { + $folderOutput.entries[0].name | Should -Be $readmeFileName + $folderOutput.entries[0].path | Should -Be $readmeFileName + } - It "Should have the expected type" { - $folderOutput.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' - $folderOutput.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + It "Should have the expected type" { + $folderOutput.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' + $folderOutput.RepositoryUrl | Should -Be $repo.RepositoryUrl } + } - Context 'For getting folder contents with the repo on the pipeline' { + Context 'For getting folder contents with the repo on the pipeline' { + BeforeAll { $folderOutput = $repo | Get-GitHubContent + } - It "Should have the expected name" { - $folderOutput.name | Should -BeNullOrEmpty - } + It "Should have the expected name" { + $folderOutput.name | Should -BeNullOrEmpty + } - It "Should have the expected path" { - $folderOutput.path | Should -BeNullOrEmpty - } + It "Should have the expected path" { + $folderOutput.path | Should -BeNullOrEmpty + } - It "Should have the expected type" { - $folderOutput.type | Should -Be "dir" - } + It "Should have the expected type" { + $folderOutput.type | Should -Be "dir" + } - It "Should have the expected entries" { - $folderOutput.entries.length | Should -Be 1 - } + It "Should have the expected entries" { + $folderOutput.entries.length | Should -Be 1 + } - It "Should have the expected entry data" { - $folderOutput.entries[0].name | Should -Be $readmeFileName - $folderOutput.entries[0].path | Should -Be $readmeFileName - } + It "Should have the expected entry data" { + $folderOutput.entries[0].name | Should -Be $readmeFileName + $folderOutput.entries[0].path | Should -Be $readmeFileName + } - It "Should have the expected type" { - $folderOutput.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' - $folderOutput.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + It "Should have the expected type" { + $folderOutput.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' + $folderOutput.RepositoryUrl | Should -Be $repo.RepositoryUrl } + } - Context 'For getting raw (byte) file contents' { + Context 'For getting raw (byte) file contents' { + BeforeAll { $readmeFileBytes = Get-GitHubContent -OwnerName $script:ownerName -RepositoryName $repo.name -Path $readmeFileName -MediaType Raw $readmeFileString = [System.Text.Encoding]::UTF8.GetString($readmeFileBytes) + } - It "Should have the expected content" { - $readmeFileString | Should -Be $rawOutput - } + It "Should have the expected content" { + $readmeFileString | Should -Be $rawOutput + } - It "Should have the expected type" { - $readmeFileString.PSObject.TypeNames[0] | Should -Not -Be 'GitHub.Content' - $readmeFileString.RepositoryUrl | Should -BeNullOrEmpty - } + It "Should have the expected type" { + $readmeFileString.PSObject.TypeNames[0] | Should -Not -Be 'GitHub.Content' + $readmeFileString.RepositoryUrl | Should -BeNullOrEmpty } + } - Context 'For getting raw (string) file contents' { + Context 'For getting raw (string) file contents' { + BeforeAll { $readmeFileString = Get-GitHubContent -OwnerName $script:ownerName -RepositoryName $repo.name -Path $readmeFileName -MediaType Raw -ResultAsString + } - It "Should have the expected content" { - $readmeFileString | Should -Be $rawOutput - } + It "Should have the expected content" { + $readmeFileString | Should -Be $rawOutput + } - It "Should have the expected type" { - $readmeFileString.PSObject.TypeNames[0] | Should -Not -Be 'GitHub.Content' - $readmeFileString.RepositoryUrl | Should -BeNullOrEmpty - } + It "Should have the expected type" { + $readmeFileString.PSObject.TypeNames[0] | Should -Not -Be 'GitHub.Content' + $readmeFileString.RepositoryUrl | Should -BeNullOrEmpty } + } - Context 'For getting html (byte) file contents' { + Context 'For getting html (byte) file contents' { + BeforeAll { $readmeFileBytes = Get-GitHubContent -OwnerName $script:ownerName -RepositoryName $repo.name -Path $readmeFileName -MediaType Html $readmeFileString = [System.Text.Encoding]::UTF8.GetString($readmeFileBytes) # Replace newlines with empty for comparison purposes $readmeNoBreaks = $readmeFileString.Replace("`n", "").Replace("`r", "") - It "Should have the expected content" { - # GitHub changes the syntax for this file too frequently, so we'll just do some - # partial matches to make sure we're getting HTML output for the right repo. - $readmeNoBreaks.StartsWith($htmlOutputStart) | Should -BeTrue - $readmeNoBreaks.IndexOf($repoGuid) | Should -BeGreaterOrEqual 0 - } + } - It "Should have the expected type" { - $readmeNoBreaks.PSObject.TypeNames[0] | Should -Not -Be 'GitHub.Content' - $readmeNoBreaks.RepositoryUrl | Should -BeNullOrEmpty - } + It "Should have the expected content" { + # GitHub changes the syntax for this file too frequently, so we'll just do some + # partial matches to make sure we're getting HTML output for the right repo. + $readmeNoBreaks.StartsWith($htmlOutputStart) | Should -BeTrue + $readmeNoBreaks.IndexOf($repoGuid) | Should -BeGreaterOrEqual 0 + } + + It "Should have the expected type" { + $readmeNoBreaks.PSObject.TypeNames[0] | Should -Not -Be 'GitHub.Content' + $readmeNoBreaks.RepositoryUrl | Should -BeNullOrEmpty } + } - Context 'For getting html (string) file contents' { + Context 'For getting html (string) file contents' { + BeforeAll { $readmeFileString = Get-GitHubContent -OwnerName $script:ownerName -RepositoryName $repo.name -Path $readmeFileName -MediaType Html -ResultAsString # Replace newlines with empty for comparison purposes $readmeNoBreaks = $readmeFileString.Replace("`n", "").Replace("`r", "") - It "Should have the expected content" { - # GitHub changes the syntax for this file too frequently, so we'll just do some - # partial matches to make sure we're getting HTML output for the right repo. - $readmeNoBreaks.StartsWith($htmlOutputStart) | Should -BeTrue - $readmeNoBreaks.IndexOf($repoGuid) | Should -BeGreaterOrEqual 0 - } + } - It "Should have the expected type" { - $readmeFileString.PSObject.TypeNames[0] | Should -Not -Be 'GitHub.Content' - $readmeFileString.RepositoryUrl | Should -BeNullOrEmpty - } + It "Should have the expected content" { + # GitHub changes the syntax for this file too frequently, so we'll just do some + # partial matches to make sure we're getting HTML output for the right repo. + $readmeNoBreaks.StartsWith($htmlOutputStart) | Should -BeTrue + $readmeNoBreaks.IndexOf($repoGuid) | Should -BeGreaterOrEqual 0 } - Context 'For getting object (default) file result' { + It "Should have the expected type" { + $readmeFileString.PSObject.TypeNames[0] | Should -Not -Be 'GitHub.Content' + $readmeFileString.RepositoryUrl | Should -BeNullOrEmpty + } + } + + Context 'For getting object (default) file result' { + BeforeAll { $readmeFileObject = Get-GitHubContent -OwnerName $script:ownerName -RepositoryName $repo.name -Path $readmeFileName + } - It "Should have the expected name" { - $readmeFileObject.name | Should -Be $readmeFileName - } + It "Should have the expected name" { + $readmeFileObject.name | Should -Be $readmeFileName + } - It "Should have the expected path" { - $readmeFileObject.path | Should -Be $readmeFileName - } + It "Should have the expected path" { + $readmeFileObject.path | Should -Be $readmeFileName + } - It "Should have the expected type" { - $readmeFileObject.type | Should -Be "file" - } + It "Should have the expected type" { + $readmeFileObject.type | Should -Be "file" + } - It "Should have the expected encoding" { - $readmeFileObject.encoding | Should -Be "base64" - } + It "Should have the expected encoding" { + $readmeFileObject.encoding | Should -Be "base64" + } - It "Should have the expected content" { - # Convert from base64 - $readmeFileString = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($readmeFileObject.content)) - $readmeFileString | Should -Be $rawOutput - } + It "Should have the expected content" { + # Convert from base64 + $readmeFileString = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($readmeFileObject.content)) + $readmeFileString | Should -Be $rawOutput + } - It "Should have the expected type" { - $readmeFileObject.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' - $readmeFileObject.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + It "Should have the expected type" { + $readmeFileObject.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' + $readmeFileObject.RepositoryUrl | Should -Be $repo.RepositoryUrl } + } - Context 'For getting object file result as string' { + Context 'For getting object file result as string' { + BeforeAll { $readmeFileObject = Get-GitHubContent -OwnerName $script:ownerName -RepositoryName $repo.name -Path $readmeFileName -MediaType Object -ResultAsString + } - It "Should have the expected name" { - $readmeFileObject.name | Should -Be $readmeFileName - } - It "Should have the expected path" { - $readmeFileObject.path | Should -Be $readmeFileName - } - It "Should have the expected type" { - $readmeFileObject.type | Should -Be "file" - } - It "Should have the expected encoding" { - $readmeFileObject.encoding | Should -Be "base64" - } + It "Should have the expected name" { + $readmeFileObject.name | Should -Be $readmeFileName + } + It "Should have the expected path" { + $readmeFileObject.path | Should -Be $readmeFileName + } + It "Should have the expected type" { + $readmeFileObject.type | Should -Be "file" + } + It "Should have the expected encoding" { + $readmeFileObject.encoding | Should -Be "base64" + } - It "Should have the expected content" { - $readmeFileObject.contentAsString | Should -Be $rawOutput - } + It "Should have the expected content" { + $readmeFileObject.contentAsString | Should -Be $rawOutput + } - It "Should have the expected type" { - $readmeFileObject.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' - $readmeFileObject.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + It "Should have the expected type" { + $readmeFileObject.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' + $readmeFileObject.RepositoryUrl | Should -Be $repo.RepositoryUrl } } +} - Describe 'GitHubContents/Set-GitHubContent' { +Describe 'GitHubContents/Set-GitHubContent' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit + + $filePath = 'notes' + $fileName = 'hello.txt' + $commitMessage = 'Commit Message 2' + $content = 'This is the new content for test.txt' + $branchName = 'master' + $committerName = 'John Doe' + $committerEmail = 'john.doe@testdomain.com' + $authorName = 'Jane Doe' + $authorEmail = 'jane.doe@testdomain.com' + } + + Context 'When setting new file content' { BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit - } - - Context 'When setting new file content' { - BeforeAll { - $filePath = 'notes' - $fileName = 'hello.txt' - $commitMessage = 'Commit Message' - $content = 'This is the content for test.txt' - $branchName = 'master' - $committerName = 'John Doe' - $committerEmail = 'john.doe@testdomain.com' - $authorName = 'Jane Doe' - $authorEmail = 'jane.doe@testdomain.com' - - $setGitHubContentParms = @{ - Path = "$filePath/$fileName" - CommitMessage = $commitMessage - Branch = $branchName - Content = $content - Uri = $repo.svn_url - CommitterName = $committerName - CommitterEmail = $committerEmail - authorName = $authorName - authorEmail = $authorEmail - } - - $result = Set-GitHubContent @setGitHubContentParms -PassThru + $setGitHubContentParms = @{ + Path = "$filePath/$fileName" + CommitMessage = $commitMessage + Branch = $branchName + Content = $content + Uri = $repo.svn_url + CommitterName = $committerName + CommitterEmail = $committerEmail + authorName = $authorName + authorEmail = $authorEmail } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' - $result.content.name | Should -Be $fileName - $result.content.path | Should -Be "$filePath/$fileName" - $result.content.url | Should -Be ("https://api.github.com/repos/$($script:ownerName)" + - "/$repoName/contents/$filePath/$($fileName)?ref=$BranchName") - $result.commit.author.name | Should -Be $authorName - $result.commit.author.email | Should -Be $authorEmail - $result.commit.committer.name | Should -Be $committerName - $result.commit.committer.email | Should -Be $committerEmail - $result.commit.message | Should -Be $commitMessage + $result = Set-GitHubContent @setGitHubContentParms -PassThru + } + + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' + $result.content.name | Should -Be $fileName + $result.content.path | Should -Be "$filePath/$fileName" + $result.content.url | Should -Be ("https://api.github.com/repos/$($script:ownerName)" + + "/$repoName/contents/$filePath/$($fileName)?ref=$BranchName") + $result.commit.author.name | Should -Be $authorName + $result.commit.author.email | Should -Be $authorEmail + $result.commit.committer.name | Should -Be $committerName + $result.commit.committer.email | Should -Be $committerEmail + $result.commit.message | Should -Be $commitMessage + } + + It 'Should have written the correct content' { + $getGitHubContentParms = @{ + Path = "$filePath/$fileName" + Uri = $repo.svn_url + MediaType = 'Raw' + ResultAsString = $true } - It 'Should have written the correct content' { - $getGitHubContentParms = @{ - Path = "$filePath/$fileName" - Uri = $repo.svn_url - MediaType = 'Raw' - ResultAsString = $true - } + $writtenContent = Get-GitHubContent @getGitHubContentParms - $writtenContent = Get-GitHubContent @getGitHubContentParms + $content | Should -Be $writtenContent + } - $content | Should -Be $writtenContent + It 'Should support pipeline input' { + $getGitHubContentParms = @{ + Path = "$filePath/$fileName" + Uri = $repo.svn_url } - It 'Should support pipeline input' { - $getGitHubContentParms = @{ - Path = "$filePath/$fileName" - Uri = $repo.svn_url - } + $writtenContent = Get-GitHubContent @getGitHubContentParms - $writtenContent = Get-GitHubContent @getGitHubContentParms + $setGitHubContentParms = @{ + CommitMessage = $commitMessage + Content = $content + CommitterName = $committerName + CommitterEmail = $committerEmail + authorName = $authorName + authorEmail = $authorEmail + } - $setGitHubContentParms = @{ - CommitMessage = $commitMessage - Content = $content - CommitterName = $committerName - CommitterEmail = $committerEmail - authorName = $authorName - authorEmail = $authorEmail - } + { $writtenContent | Set-GitHubContent @setGitHubContentParms -WhatIf } | Should -Not -Throw + } + } - { $writtenContent | Set-GitHubContent @setGitHubContentParms -WhatIf } | Should -Not -Throw + Context 'When overwriting file content' { + BeforeAll { + $setGitHubContentParms = @{ + Path = "$filePath/$fileName" + CommitMessage = $commitMessage + BranchName = $branchName + Content = $content + Uri = $repo.svn_url + CommitterName = $committerName + CommitterEmail = $committerEmail + authorName = $authorName + authorEmail = $authorEmail } + + $result = Set-GitHubContent @setGitHubContentParms -PassThru } - Context 'When overwriting file content' { - BeforeAll { - $filePath = 'notes' - $fileName = 'hello.txt' - $commitMessage = 'Commit Message 2' - $content = 'This is the new content for test.txt' - $branchName = 'master' - $committerName = 'John Doe' - $committerEmail = 'john.doe@testdomain.com' - $authorName = 'Jane Doe' - $authorEmail = 'jane.doe@testdomain.com' - - $setGitHubContentParms = @{ - Path = "$filePath/$fileName" - CommitMessage = $commitMessage - BranchName = $branchName - Content = $content - Uri = $repo.svn_url - CommitterName = $committerName - CommitterEmail = $committerEmail - authorName = $authorName - authorEmail = $authorEmail - } - - $result = Set-GitHubContent @setGitHubContentParms -PassThru - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' + $result.content.name | Should -Be $fileName + $result.content.path | Should -Be "$filePath/$fileName" + $result.content.url | Should -Be ("https://api.github.com/repos/$($script:ownerName)" + + "/$repoName/contents/$filePath/$($fileName)?ref=$BranchName") + $result.commit.author.name | Should -Be $authorName + $result.commit.author.email | Should -Be $authorEmail + $result.commit.committer.name | Should -Be $committerName + $result.commit.committer.email | Should -Be $committerEmail + $result.commit.message | Should -Be $commitMessage + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Content' - $result.content.name | Should -Be $fileName - $result.content.path | Should -Be "$filePath/$fileName" - $result.content.url | Should -Be ("https://api.github.com/repos/$($script:ownerName)" + - "/$repoName/contents/$filePath/$($fileName)?ref=$BranchName") - $result.commit.author.name | Should -Be $authorName - $result.commit.author.email | Should -Be $authorEmail - $result.commit.committer.name | Should -Be $committerName - $result.commit.committer.email | Should -Be $committerEmail - $result.commit.message | Should -Be $commitMessage + It 'Should have written the correct content' { + $getGitHubContentParms = @{ + Path = "$filePath/$fileName" + Uri = $repo.svn_url + MediaType = 'Raw' + ResultAsString = $true } - It 'Should have written the correct content' { - $getGitHubContentParms = @{ - Path = "$filePath/$fileName" - Uri = $repo.svn_url - MediaType = 'Raw' - ResultAsString = $true - } - - $writtenContent = Get-GitHubContent @getGitHubContentParms + $writtenContent = Get-GitHubContent @getGitHubContentParms - $content | Should -Be $writtenContent - } + $content | Should -Be $writtenContent } + } - Context 'When Specifying only one Committer parameter' { + Context 'When Specifying only one Committer parameter' { + BeforeAll { $setGitHubContentParms = @{ Path = "$filePath/$fileName" CommitMessage = $commitMessage @@ -398,14 +409,16 @@ try Uri = $repo.svn_url CommitterName = $committerName } + } - It 'Shoud throw the correct exception' { - $errorMessage = 'Both CommiterName and CommitterEmail need to be specified.' - { Set-GitHubContent @setGitHubContentParms } | Should -Throw $errorMessage - } + It 'Shoud throw the correct exception' { + $errorMessage = 'Both CommiterName and CommitterEmail need to be specified.' + { Set-GitHubContent @setGitHubContentParms } | Should -Throw $errorMessage } + } - Context 'When Specifying only one Author parameter' { + Context 'When Specifying only one Author parameter' { + BeforeAll { $setGitHubContentParms = @{ Path = "$filePath/$fileName" Uri = $repo.svn_url @@ -414,35 +427,35 @@ try Content = $content AuthorName = $authorName } - - It 'Shoud throw the correct exception' { - $errorMessage = 'Both AuthorName and AuthorEmail need to be specified.' - { Set-GitHubContent @setGitHubContentParms } | Should -Throw $errorMessage - } } - Context 'When Invoke-GHRestMethod returns an unexpected error' { - It 'Should throw' { - $setGitHubContentParms = @{ - Path = "$filePath/$fileName" - OwnerName = $script:ownerName - RepositoryName = 'IncorrectRepositoryName' - BranchName = $branchName - CommitMessage = $commitMessage - Content = $content - } + It 'Shoud throw the correct exception' { + $errorMessage = 'Both AuthorName and AuthorEmail need to be specified.' + { Set-GitHubContent @setGitHubContentParms } | Should -Throw $errorMessage + } + } - { Set-GitHubContent @setGitHubContentParms } | Should -Throw + Context 'When Invoke-GHRestMethod returns an unexpected error' { + It 'Should throw' { + $setGitHubContentParms = @{ + Path = "$filePath/$fileName" + OwnerName = $script:ownerName + RepositoryName = 'IncorrectRepositoryName' + BranchName = $branchName + CommitMessage = $commitMessage + Content = $content } - } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Force + { Set-GitHubContent @setGitHubContentParms } | Should -Throw } } + + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Force + } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubCore.Tests.ps1 b/Tests/GitHubCore.Tests.ps1 index cb6c3533..7276ac06 100644 --- a/Tests/GitHubCore.Tests.ps1 +++ b/Tests/GitHubCore.Tests.ps1 @@ -8,20 +8,23 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} -try -{ - Describe 'Testing ConvertTo-SmarterObject behavior' { - InModuleScope PowerShellForGitHub { +Describe 'Testing ConvertTo-SmarterObject behavior' { + InModuleScope PowerShellForGitHub { + BeforeAll { $jsonConversionDepth = 20 + } - Context 'When a property is a simple type' { + Context 'When a property is a simple type' { + BeforeAll { $original = [PSCustomObject]@{ 'prop1' = 'value1' 'prop2' = 3 @@ -29,35 +32,39 @@ try } $converted = ConvertTo-SmarterObject -InputObject $original + } - It 'Should return the same values' { - $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) - $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) - $originalJson -eq $convertedJson | Should -Be $true - } + It 'Should return the same values' { + $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) + $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) + $originalJson -eq $convertedJson | Should -Be $true } + } - Context 'When a property is a PSCustomObject' { + Context 'When a property is a PSCustomObject' { + BeforeAll { $original = [PSCustomObject]@{ 'prop1' = [PSCustomObject]@{ 'prop1' = 'value1' 'prop2' = 3 'prop3' = $null } - 'prop2' = 3 - 'prop3' = $null - } + 'prop2' = 3 + 'prop3' = $null + } $converted = ConvertTo-SmarterObject -InputObject $original + } - It 'Should return the correct values' { - $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) - $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) - $originalJson -eq $convertedJson | Should -Be $true - } + It 'Should return the correct values' { + $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) + $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) + $originalJson -eq $convertedJson | Should -Be $true } + } - Context 'When a known date property has a date string' { + Context 'When a known date property has a date string' { + BeforeAll { $date = Get-Date $dateString = $date.ToUniversalTime().ToString('o') $original = [PSCustomObject]@{ @@ -81,32 +88,34 @@ try } $converted = ConvertTo-SmarterObject -InputObject $original + } - It 'Should convert the value to a [DateTime]' { - $converted.closed_at -is [DateTime] | Should -Be $true - $converted.committed_at -is [DateTime] | Should -Be $true - $converted.completed_at -is [DateTime] | Should -Be $true - $converted.created_at -is [DateTime] | Should -Be $true - $converted.date -is [DateTime] | Should -Be $true - $converted.due_on -is [DateTime] | Should -Be $true - $converted.last_edited_at -is [DateTime] | Should -Be $true - $converted.last_read_at -is [DateTime] | Should -Be $true - $converted.merged_at -is [DateTime] | Should -Be $true - $converted.published_at -is [DateTime] | Should -Be $true - $converted.pushed_at -is [DateTime] | Should -Be $true - $converted.starred_at -is [DateTime] | Should -Be $true - $converted.started_at -is [DateTime] | Should -Be $true - $converted.submitted_at -is [DateTime] | Should -Be $true - $converted.timestamp -is [DateTime] | Should -Be $true - $converted.updated_at -is [DateTime] | Should -Be $true - } + It 'Should convert the value to a [DateTime]' { + $converted.closed_at -is [DateTime] | Should -Be $true + $converted.committed_at -is [DateTime] | Should -Be $true + $converted.completed_at -is [DateTime] | Should -Be $true + $converted.created_at -is [DateTime] | Should -Be $true + $converted.date -is [DateTime] | Should -Be $true + $converted.due_on -is [DateTime] | Should -Be $true + $converted.last_edited_at -is [DateTime] | Should -Be $true + $converted.last_read_at -is [DateTime] | Should -Be $true + $converted.merged_at -is [DateTime] | Should -Be $true + $converted.published_at -is [DateTime] | Should -Be $true + $converted.pushed_at -is [DateTime] | Should -Be $true + $converted.starred_at -is [DateTime] | Should -Be $true + $converted.started_at -is [DateTime] | Should -Be $true + $converted.submitted_at -is [DateTime] | Should -Be $true + $converted.timestamp -is [DateTime] | Should -Be $true + $converted.updated_at -is [DateTime] | Should -Be $true + } - It 'Should NOT convert the value to a [DateTime] if it''s not a known property' { - $converted.prop1 -is [DateTime] | Should -Be $false - } + It 'Should NOT convert the value to a [DateTime] if it''s not a known property' { + $converted.prop1 -is [DateTime] | Should -Be $false } + } - Context 'When a known date property has a null, empty or invalid date string' { + Context 'When a known date property has a null, empty or invalid date string' { + BeforeAll { $original = [PSCustomObject]@{ 'closed_at' = $null 'committed_at' = '123' @@ -127,28 +136,30 @@ try } $converted = ConvertTo-SmarterObject -InputObject $original + } - It 'Should keep the existing value' { - $original.closed_at -eq $converted.closed_at | Should -Be $true - $original.committed_at -eq $converted.committed_at | Should -Be $true - $original.completed_at -eq $converted.completed_at | Should -Be $true - $original.created_at -eq $converted.created_at | Should -Be $true - $original.date -eq $converted.date | Should -Be $true - $original.due_on -eq $converted.due_on | Should -Be $true - $original.last_edited_at -eq $converted.last_edited_at | Should -Be $true - $original.last_read_at -eq $converted.last_read_at | Should -Be $true - $original.merged_at -eq $converted.merged_at | Should -Be $true - $original.published_at -eq $converted.published_at | Should -Be $true - $original.pushed_at -eq $converted.pushed_at | Should -Be $true - $original.starred_at -eq $converted.starred_at | Should -Be $true - $original.started_at -eq $converted.started_at | Should -Be $true - $original.submitted_at -eq $converted.submitted_at | Should -Be $true - $original.timestamp -eq $converted.timestamp | Should -Be $true - $original.updated_at -eq $converted.updated_at | Should -Be $true - } + It 'Should keep the existing value' { + $original.closed_at -eq $converted.closed_at | Should -Be $true + $original.committed_at -eq $converted.committed_at | Should -Be $true + $original.completed_at -eq $converted.completed_at | Should -Be $true + $original.created_at -eq $converted.created_at | Should -Be $true + $original.date -eq $converted.date | Should -Be $true + $original.due_on -eq $converted.due_on | Should -Be $true + $original.last_edited_at -eq $converted.last_edited_at | Should -Be $true + $original.last_read_at -eq $converted.last_read_at | Should -Be $true + $original.merged_at -eq $converted.merged_at | Should -Be $true + $original.published_at -eq $converted.published_at | Should -Be $true + $original.pushed_at -eq $converted.pushed_at | Should -Be $true + $original.starred_at -eq $converted.starred_at | Should -Be $true + $original.started_at -eq $converted.started_at | Should -Be $true + $original.submitted_at -eq $converted.submitted_at | Should -Be $true + $original.timestamp -eq $converted.timestamp | Should -Be $true + $original.updated_at -eq $converted.updated_at | Should -Be $true } + } - Context 'When an object has an empty array' { + Context 'When an object has an empty array' { + BeforeAll { $original = [PSCustomObject]@{ 'prop1' = 'value1' 'prop2' = 3 @@ -157,15 +168,17 @@ try } $converted = ConvertTo-SmarterObject -InputObject $original + } - It 'Should still be an empty array after conversion' { - $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) - $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) - $originalJson -eq $convertedJson | Should -Be $true - } + It 'Should still be an empty array after conversion' { + $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) + $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) + $originalJson -eq $convertedJson | Should -Be $true } + } - Context 'When an object has a single item array' { + Context 'When an object has a single item array' { + BeforeAll { $original = [PSCustomObject]@{ 'prop1' = 'value1' 'prop2' = 3 @@ -174,15 +187,17 @@ try } $converted = ConvertTo-SmarterObject -InputObject $original + } - It 'Should still be a single item array after conversion' { - $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) - $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) - $originalJson -eq $convertedJson | Should -Be $true - } + It 'Should still be a single item array after conversion' { + $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) + $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) + $originalJson -eq $convertedJson | Should -Be $true } + } - Context 'When an object has a multi-item array' { + Context 'When an object has a multi-item array' { + BeforeAll { $original = [PSCustomObject]@{ 'prop1' = 'value1' 'prop2' = 3 @@ -191,63 +206,63 @@ try } $converted = ConvertTo-SmarterObject -InputObject $original + } - It 'Should still be a multi item array after conversion' { - $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) - $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) - $originalJson -eq $convertedJson | Should -Be $true - } + It 'Should still be a multi item array after conversion' { + $originalJson = (ConvertTo-Json -InputObject $original -Depth $jsonConversionDepth) + $convertedJson = (ConvertTo-Json -InputObject $converted -Depth $jsonConversionDepth) + $originalJson -eq $convertedJson | Should -Be $true } } } +} - Describe 'Testing Split-GitHubUri' { - BeforeAll { - $repositoryName = [guid]::NewGuid().Guid - $url = "https://github.com/$script:ownerName/$repositoryName" - } +Describe 'Testing Split-GitHubUri' { + BeforeAll { + $repositoryName = [guid]::NewGuid().Guid + $url = "https://github.com/$script:ownerName/$repositoryName" + } - Context 'For getting the OwnerName' { - It 'Should return expected repository name' { - $name = Split-GitHubUri -Uri $url -RepositoryName - $name | Should -Be $repositoryName - } + Context 'For getting the OwnerName' { + It 'Should return expected repository name' { + $name = Split-GitHubUri -Uri $url -RepositoryName + $name | Should -Be $repositoryName + } - It 'Should return expected repository name with the pipeline' { - $name = $url | Split-GitHubUri -RepositoryName - $name | Should -Be $repositoryName - } + It 'Should return expected repository name with the pipeline' { + $name = $url | Split-GitHubUri -RepositoryName + $name | Should -Be $repositoryName } + } - Context 'For getting the RepositoryName' { - It 'Should return expected owner name' { - $name = Split-GitHubUri -Uri $url -OwnerName - $name | Should -Be $script:ownerName - } + Context 'For getting the RepositoryName' { + It 'Should return expected owner name' { + $name = Split-GitHubUri -Uri $url -OwnerName + $name | Should -Be $script:ownerName + } - It 'Should return expected owner name with the pipeline' { - $owner = $url | Split-GitHubUri -OwnerName - $owner | Should -Be $script:ownerName - } + It 'Should return expected owner name with the pipeline' { + $owner = $url | Split-GitHubUri -OwnerName + $owner | Should -Be $script:ownerName } + } - Context 'For getting both the OwnerName and the RepositoryName' { - It 'Should return both OwnerName and RepositoryName' { - $elements = Split-GitHubUri -Uri $url - $elements.ownerName | Should -Be $script:ownerName - $elements.repositoryName | Should -Be $repositoryName - } + Context 'For getting both the OwnerName and the RepositoryName' { + It 'Should return both OwnerName and RepositoryName' { + $elements = Split-GitHubUri -Uri $url + $elements.ownerName | Should -Be $script:ownerName + $elements.repositoryName | Should -Be $repositoryName + } - It 'Should return both OwnerName and RepositoryName with the pipeline' { - $elements = $url | Split-GitHubUri - $elements.ownerName | Should -Be $script:ownerName - $elements.repositoryName | Should -Be $repositoryName - } + It 'Should return both OwnerName and RepositoryName with the pipeline' { + $elements = $url | Split-GitHubUri + $elements.ownerName | Should -Be $script:ownerName + $elements.repositoryName | Should -Be $repositoryName } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubEvents.tests.ps1 b/Tests/GitHubEvents.tests.ps1 index 17e23ce2..1bea568c 100644 --- a/Tests/GitHubEvents.tests.ps1 +++ b/Tests/GitHubEvents.tests.ps1 @@ -8,135 +8,141 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} -try -{ - Describe 'Getting events from repository' { - BeforeAll { - $repositoryName = [Guid]::NewGuid() - $repo = New-GitHubRepository -RepositoryName $repositoryName - } +Describe 'Getting events from repository' { + BeforeAll { + $repositoryName = [Guid]::NewGuid() + $repo = New-GitHubRepository -RepositoryName $repositoryName + } - AfterAll { - $null = $repo | Remove-GitHubRepository -Force - } + AfterAll { + $null = $repo | Remove-GitHubRepository -Force + } - Context 'For getting events from a new repository (via parameter)' { - $events = @(Get-GitHubEvent -OwnerName $ownerName -RepositoryName $repositoryName) + Context 'For getting events from a new repository (via parameter)' { - It 'Should have no events (via parameter)' { - $events.Count | Should -Be 0 - } + It 'Should have no events (via parameter)' { + $events = @(Get-GitHubEvent -OwnerName $ownerName -RepositoryName $repositoryName) + $events.Count | Should -Be 0 } + } - Context 'For getting events from a new repository (via pipeline)' { - $events = @($repo | Get-GitHubEvent) + Context 'For getting events from a new repository (via pipeline)' { - It 'Should have no events (via parameter)' { - $events.Count | Should -Be 0 - } + It 'Should have no events (via parameter)' { + $events = @($repo | Get-GitHubEvent) + $events.Count | Should -Be 0 } + } - Context 'For getting Issue events from a repository' { + Context 'For getting Issue events from a repository' { + + BeforeAll { $issue = $repo | New-GitHubIssue -Title 'New Issue' $issue = $issue | Set-GitHubIssue -State Closed -PassThru $events = @($repo | Get-GitHubEvent) - - It 'Should have an event from closing an issue' { - $events.Count | Should -Be 1 - } - - It 'Should have the expected type and additional properties' { - $events[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Event' - $events[0].issue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' - $events[0].IssueId | Should -Be $events[0].issue.id - $events[0].IssueNumber | Should -Be $events[0].issue.number - $events[0].actor.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } } - } - Describe 'Getting events from an issue' { - BeforeAll { - $repositoryName = [Guid]::NewGuid() - $repo = New-GitHubRepository -RepositoryName $repositoryName - $issue = New-GitHubIssue -OwnerName $ownerName -RepositoryName $repositoryName -Title "New Issue" + It 'Should have an event from closing an issue' { + $events.Count | Should -Be 1 } - AfterAll { - $repo | Remove-GitHubRepository -Confirm:$false + It 'Should have the expected type and additional properties' { + $events[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Event' + $events[0].issue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' + $events[0].IssueId | Should -Be $events[0].issue.id + $events[0].IssueNumber | Should -Be $events[0].issue.number + $events[0].actor.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } +} - Context 'For getting events from a new issue' { - $events = @(Get-GitHubEvent -OwnerName $ownerName -RepositoryName $repositoryName -Issue $issue.number) +Describe 'Getting events from an issue' { + BeforeAll { + $repositoryName = [Guid]::NewGuid() + $repo = New-GitHubRepository -RepositoryName $repositoryName + $issue = New-GitHubIssue -OwnerName $ownerName -RepositoryName $repositoryName -Title "New Issue" + } + + AfterAll { + $repo | Remove-GitHubRepository -Confirm:$false + } - It 'Should have no events' { - $events.Count | Should -Be 0 - } + Context 'For getting events from a new issue' { + + It 'Should have no events' { + $events = @(Get-GitHubEvent -OwnerName $ownerName -RepositoryName $repositoryName -Issue $issue.number) + $events.Count | Should -Be 0 } + } - Context 'For getting events from an issue' { + Context 'For getting events from an issue' { + + It 'Should have two events from closing and opening the issue' { $issue = $issue | Set-GitHubIssue -State Closed -PassThru $issue = $issue | Set-GitHubIssue -State Open -PassThru $events = @(Get-GitHubEvent -OwnerName $ownerName -RepositoryName $repositoryName) - It 'Should have two events from closing and opening the issue' { - $events.Count | Should -Be 2 - } + $events.Count | Should -Be 2 } + } + +} +Describe 'Getting an event directly' { + BeforeAll { + $repositoryName = [Guid]::NewGuid() + $repo = New-GitHubRepository -RepositoryName $repositoryName + $issue = $repo | New-GitHubIssue -Title 'New Issue' + $issue = $issue | Set-GitHubIssue -State Closed -PassThru + $issue = $issue | Set-GitHubIssue -State Open -PassThru + $events = @($repo | Get-GitHubEvent) } - Describe 'Getting an event directly' { - BeforeAll { - $repositoryName = [Guid]::NewGuid() - $repo = New-GitHubRepository -RepositoryName $repositoryName - $issue = $repo | New-GitHubIssue -Title 'New Issue' - $issue = $issue | Set-GitHubIssue -State Closed -PassThru - $issue = $issue | Set-GitHubIssue -State Open -PassThru - $events = @($repo | Get-GitHubEvent) - } + AfterAll { + $repo | Remove-GitHubRepository -Confirm:$false + } - AfterAll { - $repo | Remove-GitHubRepository -Confirm:$false - } + Context 'For getting a single event directly by parameter' { - Context 'For getting a single event directly by parameter'{ + It 'Should have the correct event type' { $singleEvent = Get-GitHubEvent -OwnerName $ownerName -RepositoryName $repositoryName -EventID $events[0].id - - It 'Should have the correct event type' { - $singleEvent.event | Should -Be 'reopened' - } + $singleEvent.event | Should -Be 'reopened' } + } + + Context 'For getting a single event directly by pipeline' { - Context 'For getting a single event directly by pipeline'{ + BeforeAll { $singleEvent = $events[0] | Get-GitHubEvent + } - It 'Should have the expected event type' { - $singleEvent.event | Should -Be $events[0].event - } + It 'Should have the expected event type' { + $singleEvent.event | Should -Be $events[0].event + } - It 'Should have the same id' { - $singleEvent.id | Should -Be $events[0].id - } + It 'Should have the same id' { + $singleEvent.id | Should -Be $events[0].id + } - It 'Should have the expected type and additional properties' { - $singleEvent.PSObject.TypeNames[0] | Should -Be 'GitHub.Event' - $singleEvent.RepositoryUrl | Should -Be $repo.RepositoryUrl - $singleEvent.EventId | Should -Be $singleEvent.id - $singleEvent.actor.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $singleEvent.PSObject.TypeNames[0] | Should -Be 'GitHub.Event' + $singleEvent.RepositoryUrl | Should -Be $repo.RepositoryUrl + $singleEvent.EventId | Should -Be $singleEvent.id + $singleEvent.actor.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubGistComments.tests.ps1 b/Tests/GitHubGistComments.tests.ps1 index 69ff5064..b7074d17 100644 --- a/Tests/GitHubGistComments.tests.ps1 +++ b/Tests/GitHubGistComments.tests.ps1 @@ -8,37 +8,40 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} + +Describe 'Get-GitHubGistComment' { + BeforeAll { + $body = 'Comment body' + } -try -{ - Describe 'Get-GitHubGistComment' { + Context 'By parameters' { BeforeAll { + $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' $body = 'Comment body' } - Context 'By parameters' { - BeforeAll { - $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' - $body = 'Comment body' - } - - AfterAll { - $gist | Remove-GitHubGist -Force - } + AfterAll { + $gist | Remove-GitHubGist -Force + } + It 'Should have no comments so far' { $comments = @(Get-GitHubGistComment -Gist $gist.id -MediaType 'Raw') - It 'Should have no comments so far' { - $comments.Count | Should -Be 0 - } + $comments.Count | Should -Be 0 + } - $firstComment = New-GitHubGistComment -Gist $gist.id -Body $body - $comments = @(Get-GitHubGistComment -Gist $gist.id -MediaType 'Text') + Context 'Add comment to Gist' { + BeforeAll { + $firstComment = New-GitHubGistComment -Gist $gist.id -Body $body + $comments = @(Get-GitHubGistComment -Gist $gist.id -MediaType 'Text') + } It 'Should have one comments so far' { $comments.Count | Should -Be 1 $comments[0].id | Should -Be $firstComment.id @@ -54,62 +57,75 @@ try $comments[0].user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } - $null = New-GitHubGistComment -Gist $gist.id -Body $body - $comments = @(Get-GitHubGistComment -Gist $gist.id -MediaType 'Html') - It 'Should have one comments so far' { - $comments.Count | Should -Be 2 - foreach ($comment in $comments) - { + Context 'Add second comment to gist' { + BeforeAll { + $null = New-GitHubGistComment -Gist $gist.id -Body $body + $comments = @(Get-GitHubGistComment -Gist $gist.id -MediaType 'Html') + } + It 'Should have one comments so far' { + $comments.Count | Should -Be 2 + foreach ($comment in $comments) + { + $comment.body | Should -BeNullOrEmpty + $comment.body_html | Should -Not -BeNullOrEmpty + $comment.body_text | Should -BeNullOrEmpty + } + } + + It 'Should have the expected type and additional properties' { + foreach ($comment in $comments) + { + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' + $comment.GistCommentId | Should -Be $comment.id + $comment.GistId | Should -Be $gist.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + } + + Context 'Retrieve a specific comment' { + BeforeAll { + $comment = Get-GitHubGistComment -Gist $gist.id -Comment $firstComment.id -MediaType 'Html' + } + It 'Should retrieve the specific comment' { + $comment.id | Should -Be $firstComment.id $comment.body | Should -BeNullOrEmpty $comment.body_html | Should -Not -BeNullOrEmpty $comment.body_text | Should -BeNullOrEmpty } - } - It 'Should have the expected type and additional properties' { - foreach ($comment in $comments) - { + It 'Should have the expected type and additional properties' { $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' $comment.GistCommentId | Should -Be $comment.id $comment.GistId | Should -Be $gist.id $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } - - $comment = Get-GitHubGistComment -Gist $gist.id -Comment $firstComment.id -MediaType 'Html' - It 'Should retrieve the specific comment' { - $comment.id | Should -Be $firstComment.id - $comment.body | Should -BeNullOrEmpty - $comment.body_html | Should -Not -BeNullOrEmpty - $comment.body_text | Should -BeNullOrEmpty - } - - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' - $comment.GistCommentId | Should -Be $comment.id - $comment.GistId | Should -Be $gist.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } } + } - Context 'Gist on the pipeline' { - BeforeAll { - $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' - $body = 'Comment body' - } + Context 'Gist on the pipeline' { + BeforeAll { + $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' + $body = 'Comment body' + } - AfterAll { - $gist | Remove-GitHubGist -Force - } + AfterAll { + $gist | Remove-GitHubGist -Force + } + It 'Should have no comments so far' { $comments = @(Get-GitHubGistComment -Gist $gist.id -MediaType 'Text') - It 'Should have no comments so far' { - $comments.Count | Should -Be 0 + $comments.Count | Should -Be 0 + } + + Context 'Create first comment' { + BeforeAll { + $firstComment = $gist | New-GitHubGistComment -Body $body } - $firstComment = $gist | New-GitHubGistComment -Body $body - $comments = @($gist | Get-GitHubGistComment -MediaType 'Raw') It 'Should have one comments so far' { + $comments = @($gist | Get-GitHubGistComment -MediaType 'Raw') $comments.Count | Should -Be 1 $comments[0].id | Should -Be $firstComment.id $comments[0].body | Should -Not -BeNullOrEmpty @@ -118,36 +134,42 @@ try } It 'Should have the expected type and additional properties' { + $comments = @($gist | Get-GitHubGistComment -MediaType 'Raw') $comments[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' $comments[0].GistCommentId | Should -Be $comments[0].id $comments[0].GistId | Should -Be $gist.id $comments[0].user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } - $null = $gist | New-GitHubGistComment -Body $body - $comments = @($gist | Get-GitHubGistComment -MediaType 'Full') - It 'Should have one comments so far' { - $comments.Count | Should -Be 2 - foreach ($comment in $comments) - { - $comment.body | Should -Not -BeNullOrEmpty - $comment.body_html | Should -Not -BeNullOrEmpty - $comment.body_text | Should -Not -BeNullOrEmpty + Context 'Add second comment' { + BeforeAll { + $null = $gist | New-GitHubGistComment -Body $body + } + It 'Should have one comments so far' { + $comments = @($gist | Get-GitHubGistComment -MediaType 'Full') + $comments.Count | Should -Be 2 + foreach ($comment in $comments) + { + $comment.body | Should -Not -BeNullOrEmpty + $comment.body_html | Should -Not -BeNullOrEmpty + $comment.body_text | Should -Not -BeNullOrEmpty + } } - } - It 'Should have the expected type and additional properties' { - foreach ($comment in $comments) - { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' - $comment.GistCommentId | Should -Be $comment.id - $comment.GistId | Should -Be $gist.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should have the expected type and additional properties' { + $comments = @($gist | Get-GitHubGistComment -MediaType 'Full') + foreach ($comment in $comments) + { + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' + $comment.GistCommentId | Should -Be $comment.id + $comment.GistId | Should -Be $gist.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } } } - $comment = Get-GitHubGistComment -Gist $gist.id -Comment $firstComment.id -MediaType 'Html' It 'Should retrieve the specific comment' { + $comment = Get-GitHubGistComment -Gist $gist.id -Comment $firstComment.id -MediaType 'Html' $comment.id | Should -Be $firstComment.id $comment.body | Should -BeNullOrEmpty $comment.body_html | Should -Not -BeNullOrEmpty @@ -155,14 +177,15 @@ try } It 'Should have the expected type and additional properties' { + $comment = Get-GitHubGistComment -Gist $gist.id -Comment $firstComment.id -MediaType 'Html' $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' $comment.GistCommentId | Should -Be $comment.id $comment.GistId | Should -Be $gist.id $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } - $comment = $firstComment | Get-GitHubGistComment -MediaType 'Html' It 'Should retrieve the specific comment with the comment on the pipeline' { + $comment = $firstComment | Get-GitHubGistComment -MediaType 'Html' $comment.id | Should -Be $firstComment.id $comment.body | Should -BeNullOrEmpty $comment.body_html | Should -Not -BeNullOrEmpty @@ -170,6 +193,7 @@ try } It 'Should have the expected type and additional properties' { + $comment = $firstComment | Get-GitHubGistComment -MediaType 'Html' $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' $comment.GistCommentId | Should -Be $comment.id $comment.GistId | Should -Be $gist.id @@ -177,155 +201,168 @@ try } } } +} - Describe 'New-GitHubGistComment' { - BeforeAll { - $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' - $body = 'Comment body' - } +Describe 'New-GitHubGistComment' { + BeforeAll { + $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' + $body = 'Comment body' + } - AfterAll { - $gist | Remove-GitHubGist -Force - } + AfterAll { + $gist | Remove-GitHubGist -Force + } - Context 'By parameters' { + Context 'By parameters' { + BeforeAll { $comment = New-GitHubGistComment -Gist $gist.id -Body $body - It 'Should have the expected result' { - $comment.body | Should -Be $body - } - - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' - $comment.GistCommentId | Should -Be $comment.id - $comment.GistId | Should -Be $gist.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + } + It 'Should have the expected result' { + $comment.body | Should -Be $body } - Context 'Gist on the pipeline' { - $comment = $gist | New-GitHubGistComment -Body $body - It 'Should have the expected result' { - $comment.body | Should -Be $body - } - - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' - $comment.GistCommentId | Should -Be $comment.id - $comment.GistId | Should -Be $gist.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' + $comment.GistCommentId | Should -Be $comment.id + $comment.GistId | Should -Be $gist.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } - Describe 'New-GitHubGistComment' { + Context 'Gist on the pipeline' { BeforeAll { - $gist = New-GitHubGist -Filename 'sample.txt' -Content 'Sample text' - $body = 'Comment body' - $updatedBody = 'Updated comment body' + $comment = $gist | New-GitHubGistComment -Body $body + } + It 'Should have the expected result' { + $comment.body | Should -Be $body } - AfterAll { - $gist | Remove-GitHubGist -Force + It 'Should have the expected type and additional properties' { + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' + $comment.GistCommentId | Should -Be $comment.id + $comment.GistId | Should -Be $gist.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } +} + +Describe 'New-GitHubGistComment' { + BeforeAll { + $gist = New-GitHubGist -Filename 'sample.txt' -Content 'Sample text' + $body = 'Comment body' + $updatedBody = 'Updated comment body' + } + + AfterAll { + $gist | Remove-GitHubGist -Force + } - Context 'By parameters' { + Context 'By parameters' { + BeforeAll { $comment = New-GitHubGistComment -Gist $gist.id -Body $body - It 'Should have the expected result' { - $comment.body | Should -Be $body - } + } + It 'Should have the expected result' { + $comment.body | Should -Be $body + } + It 'Should have the expected result' { $comment = Set-GitHubGistComment -Gist $gist.id -Comment $comment.id -Body $updatedBody -PassThru - It 'Should have the expected result' { - $comment.body | Should -Be $updatedBody - } + $comment.body | Should -Be $updatedBody + } - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' - $comment.GistCommentId | Should -Be $comment.id - $comment.GistId | Should -Be $gist.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $comment = Set-GitHubGistComment -Gist $gist.id -Comment $comment.id -Body $updatedBody -PassThru + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' + $comment.GistCommentId | Should -Be $comment.id + $comment.GistId | Should -Be $gist.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Gist on the pipeline' { + Context 'Gist on the pipeline' { + BeforeAll { $comment = $gist | New-GitHubGistComment -Body $body - It 'Should have the expected result' { - $comment.body | Should -Be $body - } + } + It 'Should have the expected result' { + $comment.body | Should -Be $body + } + It 'Should have the expected result' { $comment = $gist | Set-GitHubGistComment -Comment $comment.id -Body $updatedBody -PassThru - It 'Should have the expected result' { - $comment.body | Should -Be $updatedBody - } + $comment.body | Should -Be $updatedBody + } - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' - $comment.GistCommentId | Should -Be $comment.id - $comment.GistId | Should -Be $gist.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $comment = $gist | Set-GitHubGistComment -Comment $comment.id -Body $updatedBody -PassThru + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' + $comment.GistCommentId | Should -Be $comment.id + $comment.GistId | Should -Be $gist.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Gist Comment on the pipeline' { + Context 'Gist Comment on the pipeline' { + BeforeAll { $comment = $gist | New-GitHubGistComment -Body $body - It 'Should have the expected result' { - $comment.body | Should -Be $body - } + } + It 'Should have the expected result' { + $comment.body | Should -Be $body + } + It 'Should have the expected result' { $comment = $comment | Set-GitHubGistComment -Body $updatedBody -PassThru - It 'Should have the expected result' { - $comment.body | Should -Be $updatedBody - } + $comment.body | Should -Be $updatedBody + } - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' - $comment.GistCommentId | Should -Be $comment.id - $comment.GistId | Should -Be $gist.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $comment = $comment | Set-GitHubGistComment -Body $updatedBody -PassThru + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.GistComment' + $comment.GistCommentId | Should -Be $comment.id + $comment.GistId | Should -Be $gist.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } +} - Describe 'Remove-GitHubGistComment' { - BeforeAll { - $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' - $body = 'Comment body' - } +Describe 'Remove-GitHubGistComment' { + BeforeAll { + $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' + $body = 'Comment body' + } - AfterAll { - $gist | Remove-GitHubGist -Force - } + AfterAll { + $gist | Remove-GitHubGist -Force + } - Context 'By parameters' { + Context 'By parameters' { + It 'Should be gone' { $comment = New-GitHubGistComment -Gist $gist.id -Body $body Remove-GitHubGistComment -Gist $gist.id -Comment $comment.id -Force - It 'Should be gone' { - { Get-GitHubGistComment -Gist $gist.id -Comment $comment.id } | Should -Throw - } + { Get-GitHubGistComment -Gist $gist.id -Comment $comment.id } | Should -Throw } + } - Context 'Gist on the pipeline' { + Context 'Gist on the pipeline' { + It 'Should be gone' { $comment = $gist | New-GitHubGistComment -Body $body $gist | Remove-GitHubGistComment -Comment $comment.id -Force - It 'Should be gone' { - { $gist | Get-GitHubGistComment -Comment $comment.id } | Should -Throw - } + { $gist | Get-GitHubGistComment -Comment $comment.id } | Should -Throw } + } - Context 'Gist Comment on the pipeline' { + Context 'Gist Comment on the pipeline' { + It 'Should be gone' { $comment = $gist | New-GitHubGistComment -Body $body $comment | Remove-GitHubGistComment -Force - It 'Should be gone' { - { $comment | Get-GitHubGistComment } | Should -Throw - } + { $comment | Get-GitHubGistComment } | Should -Throw } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubGists.tests.ps1 b/Tests/GitHubGists.tests.ps1 index 61c1053b..cfd0d91e 100644 --- a/Tests/GitHubGists.tests.ps1 +++ b/Tests/GitHubGists.tests.ps1 @@ -8,16 +8,17 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -filter New-LargeFile -{ -<# + filter New-LargeFile + { + <# .SYNOPSIS Creates a large dummy file with random conntent @@ -41,556 +42,589 @@ filter New-LargeFile New-LargeFile -Path C:\Temp\LF\bigfile.txt -SizeMB 10 #> - [CmdletBinding(SupportsShouldProcess)] - param( - [Parameter(ValueFromPipeline)] - [String] $Path, + [CmdletBinding(SupportsShouldProcess)] + param( + [Parameter(ValueFromPipeline)] + [String] $Path, - [ValidateRange(1, 5120)] - [UInt16] $SizeMB = 1, + [ValidateRange(1, 5120)] + [UInt16] $SizeMB = 1, - [ValidateSet('Text', 'Binary')] - [string] $Type = 'Text', + [ValidateSet('Text', 'Binary')] + [string] $Type = 'Text', - [switch] $Force - ) + [switch] $Force + ) - $tempFile = New-TemporaryFile + $tempFile = New-TemporaryFile - if ($Type -eq 'Text') - { - $streamWriter = New-Object -TypeName IO.StreamWriter -ArgumentList ($tempFile) - try + if ($Type -eq 'Text') { - # get a 64 element Char[]; I added the - and \n to have 64 chars - [char[]]$chars = 'azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789-\n' - 1..$SizeMB | ForEach-Object { - # get 1MB of chars from 4 256KB strings - 1..4 | ForEach-Object { - $randomizedChars = $chars | Get-Random -Count $chars.Count + $streamWriter = New-Object -TypeName IO.StreamWriter -ArgumentList ($tempFile) + try + { + # get a 64 element Char[]; I added the - and \n to have 64 chars + [char[]]$chars = 'azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789-\n' + 1..$SizeMB | ForEach-Object { + # get 1MB of chars from 4 256KB strings + 1..4 | ForEach-Object { + $randomizedChars = $chars | Get-Random -Count $chars.Count - # repeat random string 4096 times to get a 256KB string - $output = (-join $randomizedChars) * 4kb + # repeat random string 4096 times to get a 256KB string + $output = (-join $randomizedChars) * 4kb - # write 256KB string to file - $streamWriter.Write($output) + # write 256KB string to file + $streamWriter.Write($output) - # release resources - Clear-Variable -Name @('randomizedChars', 'output') + # release resources + Clear-Variable -Name @('randomizedChars', 'output') + } } } - } - catch - { - Remove-File -Path $tempFile -ErrorAction SilentlyContinue - } - finally - { - $streamWriter.Close() - $streamWriter.Dispose() + catch + { + Remove-File -Path $tempFile -ErrorAction SilentlyContinue + } + finally + { + $streamWriter.Close() + $streamWriter.Dispose() - # Force the immediate garbage collection of allocated resources - [GC]::Collect() + # Force the immediate garbage collection of allocated resources + [GC]::Collect() + } } - } - else - { - $content = New-Object -TypeName Byte[] -ArgumentList ($SizeMB * 1mb) + else + { + $content = New-Object -TypeName Byte[] -ArgumentList ($SizeMB * 1mb) (New-Object -TypeName Random).NextBytes($content) - [IO.File]::WriteAllBytes($tempFile, $content) - } + [IO.File]::WriteAllBytes($tempFile, $content) + } - try - { - if ($PSBoundParameters.ContainsKey('Path')) + try { - return (Move-Item -Path $tempFile -Destination $Path -Force:$Force) + if ($PSBoundParameters.ContainsKey('Path')) + { + return (Move-Item -Path $tempFile -Destination $Path -Force:$Force) + } + else + { + return (Get-Item -Path $tempFile) + } } - else + catch { - return (Get-Item -Path $tempFile) + Remove-File -Path $tempFile -ErrorAction SilentlyContinue } } - catch - { - Remove-File -Path $tempFile -ErrorAction SilentlyContinue - } } -try -{ - Describe 'Get-GitHubGist' { - Context 'Specific Gist' { +Describe 'Get-GitHubGist' { + Context 'Specific Gist' { + BeforeAll { $id = '0831f3fbd83ac4d46451' # octocat/git-author-rewrite.sh $gist = Get-GitHubGist -Gist $id - It 'Should be the expected gist' { - $gist.id | Should -Be $id - } + } - It 'Should have the expected type and additional properties' { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $gist.history[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistCommit' - $gist.forks[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistFork' - } + It 'Should be the expected gist' { + $gist.id | Should -Be $id + } + + It 'Should have the expected type and additional properties' { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $gist.history[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistCommit' + $gist.forks[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistFork' + } + It 'Should be the expected gist with the gist on the pipeline' { $gist = $gist | Get-GitHubGist - It 'Should be the expected gist with the gist on the pipeline' { - $gist.id | Should -Be $id - } + $gist.id | Should -Be $id } + } - Context 'Commits and specific Gist with Sha' { + Context 'Commits and specific Gist with Sha' { + BeforeAll { $id = '0831f3fbd83ac4d46451' # octocat/git-author-rewrite.sh $gist = Get-GitHubGist -Gist $id $commits = Get-GitHubGist -Gist $gist.id -Commits + $oldestSha = $commits | Sort-Object -Property 'committed_at' | Select-Object -First 1 + } - It 'Should have multiple commits' { - $commits.Count | Should -BeGreaterThan 1 - } + It 'Should have multiple commits' { + $commits.Count | Should -BeGreaterThan 1 + } - It 'Should have the expected type and additional properties' { - foreach ($commit in $commits) - { - $commit.PSObject.TypeNames[0] | Should -Be 'GitHub.GistCommit' - $commit.GistId | Should -Be $gist.id - $commit.Sha | Should -Be $commit.version - $commit.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + foreach ($commit in $commits) + { + $commit.PSObject.TypeNames[0] | Should -Be 'GitHub.GistCommit' + $commit.GistId | Should -Be $gist.id + $commit.Sha | Should -Be $commit.version + $commit.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - $oldestSha = $commits | Sort-Object -Property 'committed_at' | Select-Object -First 1 - + It 'Should be the expected commit' { $firstGistCommit = Get-GitHubGist -Gist $gist.id -Sha $oldestSha.version - It 'Should be the expected commit' { - $firstGistCommit.created_at | Should -Be $oldestSha.committed_at - } + $firstGistCommit.created_at | Should -Be $oldestSha.committed_at + } - It 'Should have the expected type and additional properties' { - $firstGistCommit.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' - $firstGistCommit.GistId | Should -Be $firstGistCommit.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $gist.history[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistCommit' - $gist.forks[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistFork' - } + It 'Should have the expected type and additional properties' { + $firstGistCommit = Get-GitHubGist -Gist $gist.id -Sha $oldestSha.version + $firstGistCommit.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' + $firstGistCommit.GistId | Should -Be $firstGistCommit.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $gist.history[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistCommit' + $gist.forks[0].PSObject.TypeNames[0] | Should -Be 'GitHub.GistFork' + } - It 'Should fail if we specify Sha _and_ Commits' { - { Get-GitHubGist -Gist $gist.id -Commits -Sha $oldestSha.version } | Should -Throw - } + It 'Should fail if we specify Sha _and_ Commits' { + { Get-GitHubGist -Gist $gist.id -Commits -Sha $oldestSha.version } | Should -Throw + } - It 'Should fail if we specify Sha _and_ Forks' { - { Get-GitHubGist -Gist $gist.id -Forks -Sha $oldestSha.version } | Should -Throw - } + It 'Should fail if we specify Sha _and_ Forks' { + { Get-GitHubGist -Gist $gist.id -Forks -Sha $oldestSha.version } | Should -Throw + } + It 'Should be the expected gist commit with the gist on the pipeline' { $firstGistCommit = $gist | Get-GitHubGist -Sha $oldestSha.version - It 'Should be the expected gist commit with the gist on the pipeline' { - $firstGistCommit.created_at | Should -Be $oldestSha.committed_at - } + $firstGistCommit.created_at | Should -Be $oldestSha.committed_at + } + It 'Should be the expected gist commit with the gist commit on the pipeline' { + $firstGistCommit = $gist | Get-GitHubGist -Sha $oldestSha.version $firstGistCommit = $firstGistCommit | Get-GitHubGist - It 'Should be the expected gist commit with the gist commit on the pipeline' { - $firstGistCommit.created_at | Should -Be $oldestSha.committed_at - } + $firstGistCommit.created_at | Should -Be $oldestSha.committed_at } + } - Context 'Forks' { + Context 'Forks' { + BeforeAll { $id = '0831f3fbd83ac4d46451' # octocat/git-author-rewrite.sh $gist = Get-GitHubGist -Gist $id $forks = Get-GitHubGist -Gist $gist.id -Forks + } - It 'Should have multiple forks' { - $forks.Count | Should -BeGreaterThan 1 - } + It 'Should have multiple forks' { + $forks.Count | Should -BeGreaterThan 1 + } - It 'Should have the expected type and additional properties' { - foreach ($fork in $forks) - { - $fork.PSObject.TypeNames[0] | Should -Be 'GitHub.GistFork' - $fork.GistId | Should -Be $fork.id - $fork.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + foreach ($fork in $forks) + { + $fork.PSObject.TypeNames[0] | Should -Be 'GitHub.GistFork' + $fork.GistId | Should -Be $fork.id + $fork.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should have multiple forks when gist is on the pipeline' { $forks = $gist | Get-GitHubGist -Forks - It 'Should have multiple forks when gist is on the pipeline' { - $forks.Count | Should -BeGreaterThan 1 - } + $forks.Count | Should -BeGreaterThan 1 } + } - Context 'All gists for a specific user' { + Context 'All gists for a specific user' { + BeforeAll { $username = 'octocat' $gists = Get-GitHubGist -UserName $username + } - It 'Should have multiple gists' { - $gists.Count | Should -BeGreaterThan 1 - } + It 'Should have multiple gists' { + $gists.Count | Should -BeGreaterThan 1 + } - It 'Should have the expected type and additional properties' { - foreach ($gist in $gists) - { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.GistSummary' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + foreach ($gist in $gists) + { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.GistSummary' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should have fewer results with using the since parameter' { $since = $gists.updated_At | Sort-Object | Select-Object -Last 1 $sinceGists = Get-GitHubGist -UserName $username -Since $since - It 'Should have fewer results with using the since parameter' { - $sinceGists.Count | Should -BeGreaterThan 0 - $sinceGists.Count | Should -BeLessThan $gists.Count - } + $sinceGists.Count | Should -BeGreaterThan 0 + $sinceGists.Count | Should -BeLessThan $gists.Count } + } - Context 'All gists for the current authenticated user' { + Context 'All gists for the current authenticated user' { + BeforeAll { $gist = New-GitHubGist -Filename 'sample.txt' -Content 'Sample text' $gists = @(Get-GitHubGist) - It 'Should at least one gist including the one just created' { - $gists.Count | Should -BeGreaterOrEqual 1 - $gists.id | Should -Contain $gist.id - } + } - It 'Should have the expected type and additional properties' { - foreach ($gist in $gists) - { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.GistSummary' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } - } + It 'Should at least one gist including the one just created' { + $gists.Count | Should -BeGreaterOrEqual 1 + $gists.id | Should -Contain $gist.id + } - It 'Should be removed' { - { $gist | Remove-GitHubGist -Force } | Should -Not -Throw + It 'Should have the expected type and additional properties' { + foreach ($gist in $gists) + { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.GistSummary' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } - Context 'All gists for the current authenticated user, but not authenticated' { - # This would just be testing that an exception is thrown. - # There's no easy way to cover unauthenticated sessions in the UT's, - # so we'll just accept the lower code coverage here. + It 'Should be removed' { + { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } + } - Context 'All starred gists for the current authenticated user' { + Context 'All gists for the current authenticated user, but not authenticated' { + # This would just be testing that an exception is thrown. + # There's no easy way to cover unauthenticated sessions in the UT's, + # so we'll just accept the lower code coverage here. + } + + Context 'All starred gists for the current authenticated user' { + BeforeAll { $id = '0831f3fbd83ac4d46451' # octocat/git-author-rewrite.sh Add-GitHubGistStar -Gist $id $gists = @(Get-GitHubGist -Starred) - It 'Should include the one we just starred' { - $gists.Count | Should -BeGreaterOrEqual 1 - $gists.id | Should -Contain $id - } + } - Remove-GitHubGistStar -Gist $id + It 'Should include the one we just starred' { + $gists.Count | Should -BeGreaterOrEqual 1 + $gists.id | Should -Contain $id } - Context 'All starred gists for the current authenticated user, but not authenticated' { - # This would just be testing that an exception is thrown. - # There's no easy way to cover unauthenticated sessions in the UT's, - # so we'll just accept the lower code coverage here. + AfterAll { + Remove-GitHubGistStar -Gist $id } + } + + Context 'All starred gists for the current authenticated user, but not authenticated' { + # This would just be testing that an exception is thrown. + # There's no easy way to cover unauthenticated sessions in the UT's, + # so we'll just accept the lower code coverage here. + } + + Context 'All public gists' { + # This would require 100 queries, taking over 2 minutes. + # Given the limited additional value that we'd get from this additional test relative + # to the time it would take to execute, we'll just accept the lower code coverage here. + } +} + +Describe 'Get-GitHubGist/Download' { + BeforeAll { + # To get access to New-TemporaryDirectory + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Helpers.ps1') + $tempPath = New-TemporaryDirectory + } - Context 'All public gists' { - # This would require 100 queries, taking over 2 minutes. - # Given the limited additional value that we'd get from this additional test relative - # to the time it would take to execute, we'll just accept the lower code coverage here. + AfterAll { + if (Get-Variable -Name tempPath -ErrorAction SilentlyContinue) + { + Remove-Item -Path $tempPath -Recurse -ErrorAction SilentlyContinue -Force } } - Describe 'Get-GitHubGist/Download' { + Context 'Download gist content' { BeforeAll { - # To get access to New-TemporaryDirectory - $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent - . (Join-Path -Path $moduleRootPath -ChildPath 'Helpers.ps1') - $tempPath = New-TemporaryDirectory + $tempFile = New-TemporaryFile + $fileA = "$($tempFile.FullName).ps1" + Move-Item -Path $tempFile -Destination $fileA + $fileAName = (Get-Item -Path $fileA).Name + $fileAContent = 'fileA content' + Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 + + $tempFile = New-TemporaryFile + $fileB = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $fileB + $fileBName = (Get-Item -Path $fileB).Name + $fileBContent = 'fileB content' + Out-File -FilePath $fileB -InputObject $fileBContent -Encoding utf8 + + $tempFile = New-LargeFile -SizeMB 1 + $twoMegFile = "$($tempFile.FullName).bin" + Move-Item -Path $tempFile -Destination $twoMegFile + $twoMegFileName = (Get-Item -Path $twoMegFile).Name + + $gist = @($fileA, $fileB, $twoMegFile) | New-GitHubGist } AfterAll { - if (Get-Variable -Name tempPath -ErrorAction SilentlyContinue) - { - Remove-Item -Path $tempPath -Recurse -ErrorAction SilentlyContinue -Force - } + $gist | Remove-GitHubGist -Force + @($fileA, $fileB, $twoMegFile) | + Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null } - Context 'Download gist content' { - BeforeAll { - $tempFile = New-TemporaryFile - $fileA = "$($tempFile.FullName).ps1" - Move-Item -Path $tempFile -Destination $fileA - $fileAName = (Get-Item -Path $fileA).Name - $fileAContent = 'fileA content' - Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 - - $tempFile = New-TemporaryFile - $fileB = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $fileB - $fileBName = (Get-Item -Path $fileB).Name - $fileBContent = 'fileB content' - Out-File -FilePath $fileB -InputObject $fileBContent -Encoding utf8 - - $tempFile = New-LargeFile -SizeMB 1 - $twoMegFile = "$($tempFile.FullName).bin" - Move-Item -Path $tempFile -Destination $twoMegFile - $twoMegFileName = (Get-Item -Path $twoMegFile).Name - - $gist = @($fileA, $fileB, $twoMegFile) | New-GitHubGist - } - - AfterAll { - $gist | Remove-GitHubGist -Force - @($fileA, $fileB, $twoMegFile) | - Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null - } - - It 'Should have no files at the download path' { - @(Get-ChildItem -Path $tempPath).Count | Should -Be 0 - } + It 'Should have no files at the download path' { + @(Get-ChildItem -Path $tempPath).Count | Should -Be 0 + } + It 'Should download all of the files' { Get-GitHubGist -Gist $gist.id -Path $tempPath - It 'Should download all of the files' { - @(Get-ChildItem -Path $tempPath).Count | Should -Be 3 - [System.IO.File]::ReadAllText($fileA).Trim() | - Should -Be ([System.IO.File]::ReadAllText((Join-Path -Path $tempPath -ChildPath $fileAName)).Trim()) - [System.IO.File]::ReadAllText($fileB).Trim() | - Should -Be ([System.IO.File]::ReadAllText((Join-Path -Path $tempPath -ChildPath $fileBName)).Trim()) + @(Get-ChildItem -Path $tempPath).Count | Should -Be 3 + [System.IO.File]::ReadAllText($fileA).Trim() | + Should -Be ([System.IO.File]::ReadAllText((Join-Path -Path $tempPath -ChildPath $fileAName)).Trim()) + [System.IO.File]::ReadAllText($fileB).Trim() | + Should -Be ([System.IO.File]::ReadAllText((Join-Path -Path $tempPath -ChildPath $fileBName)).Trim()) (Get-FileHash -Path $twoMegFile).Hash | - Should -Be (Get-FileHash -Path (Join-Path -Path $tempPath -ChildPath $twoMegFileName)).Hash - } + Should -Be (Get-FileHash -Path (Join-Path -Path $tempPath -ChildPath $twoMegFileName)).Hash + } + It 'Should download all of the files with the gist on the pipeline and -Force' { $gist | Get-GitHubGist -Path $tempPath -Force - It 'Should download all of the files with the gist on the pipeline and -Force' { - @(Get-ChildItem -Path $tempPath).Count | Should -Be 3 - [System.IO.File]::ReadAllText($fileA).Trim() | - Should -Be ([System.IO.File]::ReadAllText((Join-Path -Path $tempPath -ChildPath $fileAName)).Trim()) - [System.IO.File]::ReadAllText($fileB).Trim() | - Should -Be ([System.IO.File]::ReadAllText((Join-Path -Path $tempPath -ChildPath $fileBName)).Trim()) + @(Get-ChildItem -Path $tempPath).Count | Should -Be 3 + [System.IO.File]::ReadAllText($fileA).Trim() | + Should -Be ([System.IO.File]::ReadAllText((Join-Path -Path $tempPath -ChildPath $fileAName)).Trim()) + [System.IO.File]::ReadAllText($fileB).Trim() | + Should -Be ([System.IO.File]::ReadAllText((Join-Path -Path $tempPath -ChildPath $fileBName)).Trim()) (Get-FileHash -Path $twoMegFile).Hash | - Should -Be (Get-FileHash -Path (Join-Path -Path $tempPath -ChildPath $twoMegFileName)).Hash - } + Should -Be (Get-FileHash -Path (Join-Path -Path $tempPath -ChildPath $twoMegFileName)).Hash } + } - Context 'More than 300 files' { - BeforeAll { - $files = @() - 1..301 | ForEach-Object { - $tempFile = New-TemporaryFile - $file = "$($tempFile.FullName)-$_.ps1" - Move-Item -Path $tempFile -Destination $file - $fileContent = "file-$_ content" - Out-File -FilePath $file -InputObject $fileContent -Encoding utf8 - $files += $file - } - } - - AfterAll { - $files | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + Context 'More than 300 files' { + BeforeAll { + $files = @() + 1..301 | ForEach-Object { + $tempFile = New-TemporaryFile + $file = "$($tempFile.FullName)-$_.ps1" + Move-Item -Path $tempFile -Destination $file + $fileContent = "file-$_ content" + Out-File -FilePath $file -InputObject $fileContent -Encoding utf8 + $files += $file } + } - # May want to consider skipping this test. - # It works just fine, but takes 26 second to execute. - # (May not be worth it for the moderate improvement to code coverage.) - It 'Should throw an exception because there are too many files' { - $gist = $files | New-GitHubGist - { $gist | Get-GitHubGist -Path $tempPath -Force } | Should -Throw - $gist | Remove-GitHubGist -Force - } + AfterAll { + $files | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + } + # May want to consider skipping this test. + # It works just fine, but takes 26 second to execute. + # (May not be worth it for the moderate improvement to code coverage.) + It 'Should throw an exception because there are too many files' { + $gist = $files | New-GitHubGist + { $gist | Get-GitHubGist -Path $tempPath -Force } | Should -Throw + $gist | Remove-GitHubGist -Force } - Context 'Download gist content' { - BeforeAll { - $tempFile = New-LargeFile -SizeMB 10 - $tenMegFile = "$($tempFile.FullName).bin" - Move-Item -Path $tempFile -Destination $tenMegFile - $tenMegFileName = (Get-Item -Path $tenMegFile).Name - } + } - AfterAll { - @($tenMegFile) | - Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null - } + Context 'Download gist content' { + BeforeAll { + $tempFile = New-LargeFile -SizeMB 10 + $tenMegFile = "$($tempFile.FullName).bin" + Move-Item -Path $tempFile -Destination $tenMegFile + $tenMegFileName = (Get-Item -Path $tenMegFile).Name + } - # May want to consider skipping this test. - # It works just fine, but takes 26 second to execute. - # (May not be worth it for the moderate improvement to code coverage.) - It 'Should throw an exception because the file is too large to download' { - $gist = $tenMegFile | New-GitHubGist - { $gist | Get-GitHubGist -Path $tempPath -Force } | Should -Throw - $gist | Remove-GitHubGist -Force - } + AfterAll { + @($tenMegFile) | + Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + } + + # May want to consider skipping this test. + # It works just fine, but takes 26 second to execute. + # (May not be worth it for the moderate improvement to code coverage.) + It 'Should throw an exception because the file is too large to download' { + $gist = $tenMegFile | New-GitHubGist + { $gist | Get-GitHubGist -Path $tempPath -Force } | Should -Throw + $gist | Remove-GitHubGist -Force } } +} - Describe 'Remove-GitHubGist' { - Context 'With parameters' { +Describe 'Remove-GitHubGist' { + Context 'With parameters' { + BeforeAll { $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' - It 'Should be there' { - { Get-GitHubGist -Gist $gist.id } | Should -Not -Throw - } + } - It 'Should remove the gist successfully' { - { Remove-GitHubGist -Gist $gist.id -Force } | Should -Not -Throw - } + It 'Should be there' { + { Get-GitHubGist -Gist $gist.id } | Should -Not -Throw + } - It 'Should be removed' { - { Get-GitHubGist -Gist $gist.id } | Should -Throw - } + It 'Should remove the gist successfully' { + { Remove-GitHubGist -Gist $gist.id -Force } | Should -Not -Throw } - Context 'With the gist on the pipeline' { + It 'Should be removed' { + { Get-GitHubGist -Gist $gist.id } | Should -Throw + } + } + + Context 'With the gist on the pipeline' { + BeforeAll { $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' - It 'Should be there' { - { $gist | Get-GitHubGist } | Should -Not -Throw - } + } - It 'Should remove the gist successfully' { - { $gist | Remove-GitHubGist -Force } | Should -Not -Throw - } + It 'Should be there' { + { $gist | Get-GitHubGist } | Should -Not -Throw + } - It 'Should be removed' { - { $gist | Get-GitHubGist } | Should -Throw - } + It 'Should remove the gist successfully' { + { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } + + It 'Should be removed' { + { $gist | Get-GitHubGist } | Should -Throw + } + } +} + +Describe 'Copy-GitHubGist' { + BeforeAll { + $originalGist = Get-GitHubGist -Gist '1169852' # octocat/test.cs } - Describe 'Copy-GitHubGist' { + Context 'By parameters' { BeforeAll { - $originalGist = Get-GitHubGist -Gist '1169852' # octocat/test.cs + $gist = Copy-GitHubGist -Gist $originalGist.id -PassThru } - Context 'By parameters' { - $gist = Copy-GitHubGist -Gist $originalGist.id -PassThru - It 'Should have been forked' { - $gist.files.Count | Should -Be $originalGist.files.Count - foreach ($file in $gist.files) - { - $originalFile = $originalGist.files | - Where-Object { $_.filename -eq $file.filename } - $file.filename | Should -Be $originalFile.filename - $file.size | Should -Be $originalFile.size - } + It 'Should have been forked' { + $gist.files.Count | Should -Be $originalGist.files.Count + foreach ($file in $gist.files) + { + $originalFile = $originalGist.files | + Where-Object { $_.filename -eq $file.filename } + $file.filename | Should -Be $originalFile.filename + $file.size | Should -Be $originalFile.size } + } - It 'Should have the expected additional type and properties' { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.GistSummary' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected additional type and properties' { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.GistSummary' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should be removed' { - { Remove-GitHubGist -Gist $gist.id -Force } | Should -Not -Throw - } + It 'Should be removed' { + { Remove-GitHubGist -Gist $gist.id -Force } | Should -Not -Throw } + } - Context 'Gist on the pipeline' { + Context 'Gist on the pipeline' { + BeforeAll { $gist = $originalGist | Copy-GitHubGist -PassThru - It 'Should have been forked' { - $gist.files.Count | Should -Be $originalGist.files.Count - foreach ($file in $gist.files) - { - $originalFile = $originalGist.files | - Where-Object { $_.filename -eq $file.filename } - $file.filename | Should -Be $originalFile.filename - $file.size | Should -Be $originalFile.size - } - } - - It 'Should have the expected additional type and properties' { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.GistSummary' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + } - It 'Should be removed' { - { $gist | Remove-GitHubGist -Force } | Should -Not -Throw + It 'Should have been forked' { + $gist.files.Count | Should -Be $originalGist.files.Count + foreach ($file in $gist.files) + { + $originalFile = $originalGist.files | + Where-Object { $_.filename -eq $file.filename } + $file.filename | Should -Be $originalFile.filename + $file.size | Should -Be $originalFile.size } } - } - Describe 'Add/Remove/Set/Test-GitHubGistStar' { - BeforeAll { - $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' + It 'Should have the expected additional type and properties' { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.GistSummary' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } - AfterAll { - $gist | Remove-GitHubGist -Force + It 'Should be removed' { + { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } + } +} - Context 'With parameters' { +Describe 'Add/Remove/Set/Test-GitHubGistStar' { + BeforeAll { + $gist = New-GitHubGist -FileName 'sample.txt' -Content 'Sample text' + } + + AfterAll { + $gist | Remove-GitHubGist -Force + } + + Context 'With parameters' { + It 'Should not be starred yet' { $starred = Test-GitHubGistStar -Gist $gist.id - It 'Should not be starred yet' { - $starred | Should -BeFalse - } + $starred | Should -BeFalse + } + It 'Should now be starred' { Add-GitHubGistStar -Gist $gist.id $starred = Test-GitHubGistStar -Gist $gist.id - It 'Should now be starred' { - $starred | Should -BeTrue - } + $starred | Should -BeTrue + } + It 'Should no longer be starred' { Remove-GitHubGistStar -Gist $gist.id $starred = Test-GitHubGistStar -Gist $gist.id - It 'Should no longer be starred' { - $starred | Should -BeFalse - } + $starred | Should -BeFalse + } + It 'Should now be starred' { Set-GitHubGistStar -Gist $gist.id -Star $starred = Test-GitHubGistStar -Gist $gist.id - It 'Should now be starred' { - $starred | Should -BeTrue - } + $starred | Should -BeTrue + } + It 'Should no longer be starred' { Set-GitHubGistStar -Gist $gist.id $starred = Test-GitHubGistStar -Gist $gist.id - It 'Should no longer be starred' { - $starred | Should -BeFalse - } + $starred | Should -BeFalse } + } - Context 'With the gist on the pipeline' { + Context 'With the gist on the pipeline' { + It 'Should not be starred yet' { $starred = $gist | Test-GitHubGistStar - It 'Should not be starred yet' { - $starred | Should -BeFalse - } + $starred | Should -BeFalse + } + It 'Should now be starred' { $gist | Add-GitHubGistStar $starred = $gist | Test-GitHubGistStar - It 'Should now be starred' { - $starred | Should -BeTrue - } + $starred | Should -BeTrue + } + It 'Should no longer be starred' { $gist | Remove-GitHubGistStar $starred = $gist | Test-GitHubGistStar - It 'Should no longer be starred' { - $starred | Should -BeFalse - } + $starred | Should -BeFalse + } + It 'Should now be starred' { $gist | Set-GitHubGistStar -Star $starred = $gist | Test-GitHubGistStar - It 'Should now be starred' { - $starred | Should -BeTrue - } + $starred | Should -BeTrue + } + It 'Should no longer be starred' { $gist | Set-GitHubGistStar $starred = $gist | Test-GitHubGistStar - It 'Should no longer be starred' { - $starred | Should -BeFalse - } + $starred | Should -BeFalse } } +} + +Describe 'New-GitHubGist' { + Context 'By content' { + BeforeAll { + $content = 'This is my content' + $filename = 'sample.txt' + $description = 'my description' + } - Describe 'New-GitHubGist' { - Context 'By content' { + Context 'Add public Gist' { BeforeAll { - $content = 'This is my content' - $filename = 'sample.txt' - $description = 'my description' + $gist = New-GitHubGist -FileName $filename -Content $content -Public } - $gist = New-GitHubGist -FileName $filename -Content $content -Public It 'Should have the expected result' { $gist.public | Should -BeTrue $gist.description | Should -BeNullOrEmpty @@ -606,8 +640,13 @@ try It 'Should be removed' { { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } + } + + Context 'Add Private Gist' { + BeforeAll { + $gist = New-GitHubGist -FileName $filename -Content $content -Description $description -Public:$false + } - $gist = New-GitHubGist -FileName $filename -Content $content -Description $description -Public:$false It 'Should have the expected result' { $gist.public | Should -BeFalse $gist.description | Should -Be $description @@ -628,31 +667,36 @@ try { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } } + } - Context 'By files' { - BeforeAll { - $tempFile = New-TemporaryFile - $fileA = "$($tempFile.FullName).ps1" - Move-Item -Path $tempFile -Destination $fileA - $fileAName = (Get-Item -Path $fileA).Name - $fileAContent = 'fileA content' - Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 + Context 'By files' { + BeforeAll { + $tempFile = New-TemporaryFile + $fileA = "$($tempFile.FullName).ps1" + Move-Item -Path $tempFile -Destination $fileA + $fileAName = (Get-Item -Path $fileA).Name + $fileAContent = 'fileA content' + Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 - $tempFile = New-TemporaryFile - $fileB = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $fileB - $fileBName = (Get-Item -Path $fileB).Name - $fileBContent = 'fileB content' - Out-File -FilePath $fileB -InputObject $fileBContent -Encoding utf8 + $tempFile = New-TemporaryFile + $fileB = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $fileB + $fileBName = (Get-Item -Path $fileB).Name + $fileBContent = 'fileB content' + Out-File -FilePath $fileB -InputObject $fileBContent -Encoding utf8 - $description = 'my description' - } + $description = 'my description' + } + + AfterAll { + @($fileA, $fileB) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + } - AfterAll { - @($fileA, $fileB) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + Context 'Add Public Gist' { + BeforeAll { + $gist = New-GitHubGist -File @($fileA, $fileB) -Public } - $gist = New-GitHubGist -File @($fileA, $fileB) -Public It 'Should have the expected result' { $gist.public | Should -BeTrue $gist.description | Should -BeNullOrEmpty @@ -670,8 +714,13 @@ try It 'Should be removed' { { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } + } + + Context 'Add Private Gist' { + BeforeAll { + $gist = New-GitHubGist -File @($fileA, $fileB) -Description $description -Public:$false + } - $gist = New-GitHubGist -File @($fileA, $fileB) -Description $description -Public:$false It 'Should have the expected result' { $gist.public | Should -BeFalse $gist.description | Should -Be $description @@ -683,82 +732,87 @@ try It 'Should be removed' { { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } + } + It 'Should have the expected result with the files on the pipeline' { $gist = @($fileA, $fileB) | New-GitHubGist -Description $description -Public:$false - It 'Should have the expected result with the files on the pipeline' { - $gist.public | Should -BeFalse - $gist.description | Should -Be $description + $gist.public | Should -BeFalse + $gist.description | Should -Be $description ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 - $gist.files.$fileAName.content.Trim() | Should -Be $fileAContent - $gist.files.$fileBName.content.Trim() | Should -Be $fileBContent - } + $gist.files.$fileAName.content.Trim() | Should -Be $fileAContent + $gist.files.$fileBName.content.Trim() | Should -Be $fileBContent } } +} - Describe 'Set-GitHubGist' { - BeforeAll { - $fileAName = 'foo.txt' - $fileAContent = 'foo content' - $fileAUpdatedContent = 'foo updated content' - $fileANewName = 'gamma.txt' - - $fileBName = 'bar.txt' - $fileBContent = 'bar content' - $fileBUpdatedContent = 'bar updated content' - - $fileCName = 'alpha.txt' - $fileCContent = 'alpha content' - $fileCUpdatedContent = 'alpha updated content' - $fileCNewName = 'gamma.txt' +Describe 'Set-GitHubGist' { + BeforeAll { + $fileAName = 'foo.txt' + $fileAContent = 'foo content' + $fileAUpdatedContent = 'foo updated content' + $fileANewName = 'gamma.txt' + + $fileBName = 'bar.txt' + $fileBContent = 'bar content' + $fileBUpdatedContent = 'bar updated content' + + $fileCName = 'alpha.txt' + $fileCContent = 'alpha content' + $fileCUpdatedContent = 'alpha updated content' + $fileCNewName = 'gamma.txt' + + $tempFile = New-TemporaryFile + $fileD = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $fileD + $fileDName = (Get-Item -Path $fileD).Name + $fileDContent = 'fileD content' + Out-File -FilePath $fileD -InputObject $fileDContent -Encoding utf8 + $fileDUpdatedContent = 'fileD updated content' + + $description = 'my description' + $updatedDescription = 'updated description' + } - $tempFile = New-TemporaryFile - $fileD = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $fileD - $fileDName = (Get-Item -Path $fileD).Name - $fileDContent = 'fileD content' - Out-File -FilePath $fileD -InputObject $fileDContent -Encoding utf8 - $fileDUpdatedContent = 'fileD updated content' + AfterAll { + @($fileD) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + } - $description = 'my description' - $updatedDescription = 'updated description' + Context 'With parameters' { + BeforeAll { + $gist = New-GitHubGist -FileName $fileAName -Content $fileAContent -Description $description + $gist = Set-GitHubGistFile -Gist $gist.id -FileName $fileBName -Content $fileBContent -PassThru } AfterAll { - @($fileD) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + $gist | Remove-GitHubGist -Force } - Context 'With parameters' { - BeforeAll { - $gist = New-GitHubGist -FileName $fileAName -Content $fileAContent -Description $description - } - - AfterAll { - $gist | Remove-GitHubGist -Force - } - - $gist = Set-GitHubGistFile -Gist $gist.id -FileName $fileBName -Content $fileBContent -PassThru - It 'Should be in the expected, original state' { - $gist.description | Should -Be $description + It 'Should be in the expected, original state' { + $gist.description | Should -Be $description ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 - $gist.files.$fileAName.content | Should -Be $fileAContent - $gist.files.$fileBName.content | Should -Be $fileBContent - } + $gist.files.$fileAName.content | Should -Be $fileAContent + $gist.files.$fileBName.content | Should -Be $fileBContent + } - $setParams = @{ - Gist = $gist.id - Description = $updatedDescription - Delete = @($fileBName) - Update = @{ - $fileAName = @{ - fileName = $fileANewName - content = $fileAUpdatedContent + Context 'Update Gist' { + BeforeAll { + $setParams = @{ + Gist = $gist.id + Description = $updatedDescription + Delete = @($fileBName) + Update = @{ + $fileAName = @{ + fileName = $fileANewName + content = $fileAUpdatedContent + } + $fileCName = @{ content = $fileCContent } + $fileDName = @{ filePath = $fileD } } - $fileCName = @{ content = $fileCContent } - $fileDName = @{ filePath = $fileD } } + + $gist = Set-GitHubGist @setParams -Force -PassThru } - $gist = Set-GitHubGist @setParams -Force -PassThru It 'Should have been properly updated' { $gist.description | Should -Be $updatedDescription ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 3 @@ -775,52 +829,56 @@ try $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } - $setParams = @{ - Gist = $gist.id - Update = @{ - $fileDName = @{ - content = 'updated content' - filePath = $fileD - } - } - } It 'Should throw if updating a file with both a filePath and content' { + $setParams = @{ + Gist = $gist.id + Update = @{ + $fileDName = @{ + content = 'updated content' + filePath = $fileD + } + } + } { $gist = Set-GitHubGist @setParams } | Should -Throw } } + } - Context 'With the gist on the pipeline' { - BeforeAll { - $gist = New-GitHubGist -FileName $fileAName -Content $fileAContent -Description $description - } + Context 'With the gist on the pipeline' { + BeforeAll { + $gist = New-GitHubGist -FileName $fileAName -Content $fileAContent -Description $description + $gist = Set-GitHubGistFile -Gist $gist.id -FileName $fileBName -Content $fileBContent -PassThru + } - AfterAll { - $gist | Remove-GitHubGist -Force - } + AfterAll { + $gist | Remove-GitHubGist -Force + } - $gist = Set-GitHubGistFile -Gist $gist.id -FileName $fileBName -Content $fileBContent -PassThru - It 'Should be in the expected, original state' { - $gist.description | Should -Be $description + It 'Should be in the expected, original state' { + $gist.description | Should -Be $description ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 - $gist.files.$fileAName.content | Should -Be $fileAContent - $gist.files.$fileBName.content | Should -Be $fileBContent - } + $gist.files.$fileAName.content | Should -Be $fileAContent + $gist.files.$fileBName.content | Should -Be $fileBContent + } - $setParams = @{ - Description = $updatedDescription - Delete = @($fileBName) - Update = @{ - $fileAName = @{ - fileName = $fileANewName - content = $fileAUpdatedContent + Context 'Update Gist' { + BeforeAll { + $setParams = @{ + Description = $updatedDescription + Delete = @($fileBName) + Update = @{ + $fileAName = @{ + fileName = $fileANewName + content = $fileAUpdatedContent + } + $fileCName = @{ content = $fileCContent } + $fileDName = @{ filePath = $fileD } } - $fileCName = @{ content = $fileCContent } - $fileDName = @{ filePath = $fileD } } + $gist = $gist | Set-GitHubGist @setParams -Confirm:$false -PassThru } - $gist = $gist | Set-GitHubGist @setParams -Confirm:$false -PassThru It 'Should have been properly updated' { $gist.description | Should -Be $updatedDescription ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 3 @@ -836,7 +894,9 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should throw if updating a file with both a filePath and content' { $setParams = @{ Update = @{ $fileDName = @{ @@ -846,42 +906,48 @@ try } } - It 'Should throw if updating a file with both a filePath and content' { - { $gist = $gist | Set-GitHubGist @setParams } | Should -Throw - } + { $gist = $gist | Set-GitHubGist @setParams } | Should -Throw } } +} - Describe 'Set-GitHubGistFile' { - BeforeAll { - $origFileName = 'foo.txt' - $origContent = 'original content' - $updatedOrigContent = 'updated content' +Describe 'Set-GitHubGistFile' { + BeforeAll { + $origFileName = 'foo.txt' + $origContent = 'original content' + $updatedOrigContent = 'updated content' - $newFileName = 'bar.txt' - $newContent = 'new content' + $newFileName = 'bar.txt' + $newContent = 'new content' + + $gist = New-GitHubGist -FileName $origFileName -Content $origContent + } - $gist = New-GitHubGist -FileName $origFileName -Content $origContent + AfterAll { + $gist | Remove-GitHubGist -Force + } + + Context 'By content with parameters' { + BeforeAll { + $gist = Set-GitHubGistFile -Gist $gist.id -FileName $origFileName -Content $updatedOrigContent -PassThru } - AfterAll { - $gist | Remove-GitHubGist -Force + It 'Should have the expected result' { + $gist.files.$origFileName.content | Should -Be $updatedOrigContent + $gist.files.$newFileName | Should -BeNullOrEmpty } - Context 'By content with parameters' { - $gist = Set-GitHubGistFile -Gist $gist.id -FileName $origFileName -Content $updatedOrigContent -PassThru - It 'Should have the expected result' { - $gist.files.$origFileName.content | Should -Be $updatedOrigContent - $gist.files.$newFileName | Should -BeNullOrEmpty - } + It 'Should have the expected type and additional properties' { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should have the expected type and additional properties' { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + Context 'Update Gist' { + BeforeAll { + $gist = Set-GitHubGistFile -Gist $gist.id -FileName $newFileName -Content $newContent -PassThru } - $gist = Set-GitHubGistFile -Gist $gist.id -FileName $newFileName -Content $newContent -PassThru It 'Should have the expected result' { $gist.files.$origFileName.content | Should -Be $updatedOrigContent $gist.files.$newFileName.content | Should -Be $newContent @@ -892,27 +958,35 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should remove the new file' { $gist = Set-GitHubGistFile -Gist $gist.id -FileName $origFileName -Content $origContent -PassThru - It 'Should remove the new file' { - { $gist | Remove-GitHubGistFile -FileName $newFileName -Force } | Should -Not -Throw - } + { $gist | Remove-GitHubGistFile -FileName $newFileName -Force } | Should -Not -Throw } + } - Context 'By content with the gist on the pipeline' { + Context 'By content with the gist on the pipeline' { + BeforeAll { $gist = $gist | Set-GitHubGistFile -FileName $origFileName -Content $updatedOrigContent -PassThru - It 'Should have the expected result' { - $gist.files.$origFileName.content | Should -Be $updatedOrigContent - $gist.files.$newFileName | Should -BeNullOrEmpty - } + } - It 'Should have the expected type and additional properties' { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should have the expected result' { + $gist.files.$origFileName.content | Should -Be $updatedOrigContent + $gist.files.$newFileName | Should -BeNullOrEmpty + } + + It 'Should have the expected type and additional properties' { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + Context 'Update Gist' { + BeforeAll { + $gist = $gist | Set-GitHubGistFile -FileName $newFileName -Content $newContent -PassThru } - $gist = $gist | Set-GitHubGistFile -FileName $newFileName -Content $newContent -PassThru It 'Should have the expected result' { $gist.files.$origFileName.content | Should -Be $updatedOrigContent $gist.files.$newFileName.content | Should -Be $newContent @@ -923,43 +997,48 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should remove the new file' { $gist = Set-GitHubGistFile -Gist $gist.id -FileName $origFileName -Content $origContent -PassThru - It 'Should remove the new file' { - { $gist | Remove-GitHubGistFile -FileName $newFileName -Force } | Should -Not -Throw - } + { $gist | Remove-GitHubGistFile -FileName $newFileName -Force } | Should -Not -Throw } + } - Context 'By files with parameters' { - BeforeAll { - $tempFile = New-TemporaryFile - $fileA = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $fileA - $fileAName = (Get-Item -Path $fileA).Name - $fileAContent = 'fileA content' - Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 - $fileAUpdatedContent = 'fileA content updated' - } + Context 'By files with parameters' { + BeforeAll { + $tempFile = New-TemporaryFile + $fileA = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $fileA + $fileAName = (Get-Item -Path $fileA).Name + $fileAContent = 'fileA content' + Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 + $fileAUpdatedContent = 'fileA content updated' + $gist = Set-GitHubGistFile -Gist $gist.id -File $fileA -PassThru + } - AfterAll { - @($fileA) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null - } + AfterAll { + @($fileA) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + } - $gist = Set-GitHubGistFile -Gist $gist.id -File $fileA -PassThru - It 'Should have the expected result' { + It 'Should have the expected result' { ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 - $gist.files.$origFileName.content | Should -Be $origContent - $gist.files.$fileAName.content.Trim() | Should -Be $fileAContent - } + $gist.files.$origFileName.content | Should -Be $origContent + $gist.files.$fileAName.content.Trim() | Should -Be $fileAContent + } - It 'Should have the expected type and additional properties' { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should have the expected type and additional properties' { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + Context 'Update Gist' { + BeforeAll { + Out-File -FilePath $fileA -InputObject $fileAUpdatedContent -Encoding utf8 + $gist = Set-GitHubGistFile -Gist $gist.id -File $fileA -PassThru } - Out-File -FilePath $fileA -InputObject $fileAUpdatedContent -Encoding utf8 - $gist = Set-GitHubGistFile -Gist $gist.id -File $fileA -PassThru It 'Should have the expected result' { ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 $gist.files.$origFileName.content | Should -Be $origContent @@ -971,43 +1050,48 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should remove the new file' { $gist = Set-GitHubGistFile -Gist $gist.id -FileName $origFileName -Content $origContent -PassThru - It 'Should remove the new file' { - { $gist | Remove-GitHubGistFile -FileName $fileAName -Force } | Should -Not -Throw - } + { $gist | Remove-GitHubGistFile -FileName $fileAName -Force } | Should -Not -Throw } + } - Context 'By files with the gist on the pipeline' { - BeforeAll { - $tempFile = New-TemporaryFile - $fileA = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $fileA - $fileAName = (Get-Item -Path $fileA).Name - $fileAContent = 'fileA content' - Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 - $fileAUpdatedContent = 'fileA content updated' - } + Context 'By files with the gist on the pipeline' { + BeforeAll { + $tempFile = New-TemporaryFile + $fileA = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $fileA + $fileAName = (Get-Item -Path $fileA).Name + $fileAContent = 'fileA content' + Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 + $fileAUpdatedContent = 'fileA content updated' + $gist = $gist | Set-GitHubGistFile -File $fileA -PassThru + } - AfterAll { - @($fileA) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null - } + AfterAll { + @($fileA) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + } - $gist = $gist | Set-GitHubGistFile -File $fileA -PassThru - It 'Should have the expected result' { + It 'Should have the expected result' { ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 - $gist.files.$origFileName.content | Should -Be $origContent - $gist.files.$fileAName.content.Trim() | Should -Be $fileAContent - } + $gist.files.$origFileName.content | Should -Be $origContent + $gist.files.$fileAName.content.Trim() | Should -Be $fileAContent + } - It 'Should have the expected type and additional properties' { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should have the expected type and additional properties' { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + Context 'Update Gist' { + BeforeAll { + Out-File -FilePath $fileA -InputObject $fileAUpdatedContent -Encoding utf8 + $gist = $gist | Set-GitHubGistFile -File $fileA -PassThru } - Out-File -FilePath $fileA -InputObject $fileAUpdatedContent -Encoding utf8 - $gist = $gist | Set-GitHubGistFile -File $fileA -PassThru It 'Should have the expected result' { ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 $gist.files.$origFileName.content | Should -Be $origContent @@ -1019,43 +1103,48 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should remove the new file' { $gist = Set-GitHubGistFile -Gist $gist.id -FileName $origFileName -Content $origContent -PassThru - It 'Should remove the new file' { - { $gist | Remove-GitHubGistFile -FileName $fileAName -Force } | Should -Not -Throw - } + { $gist | Remove-GitHubGistFile -FileName $fileAName -Force } | Should -Not -Throw } + } - Context 'By files with the file on the pipeline' { - BeforeAll { - $tempFile = New-TemporaryFile - $fileA = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $fileA - $fileAName = (Get-Item -Path $fileA).Name - $fileAContent = 'fileA content' - Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 - $fileAUpdatedContent = 'fileA content updated' - } + Context 'By files with the file on the pipeline' { + BeforeAll { + $tempFile = New-TemporaryFile + $fileA = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $fileA + $fileAName = (Get-Item -Path $fileA).Name + $fileAContent = 'fileA content' + Out-File -FilePath $fileA -InputObject $fileAContent -Encoding utf8 + $fileAUpdatedContent = 'fileA content updated' + $gist = $fileA | Set-GitHubGistFile -Gist $gist.id -PassThru + } - AfterAll { - @($fileA) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null - } + AfterAll { + @($fileA) | Remove-Item -Force -ErrorAction SilentlyContinue | Out-Null + } - $gist = $fileA | Set-GitHubGistFile -Gist $gist.id -PassThru - It 'Should have the expected result' { + It 'Should have the expected result' { ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 - $gist.files.$origFileName.content | Should -Be $origContent - $gist.files.$fileAName.content.Trim() | Should -Be $fileAContent - } + $gist.files.$origFileName.content | Should -Be $origContent + $gist.files.$fileAName.content.Trim() | Should -Be $fileAContent + } - It 'Should have the expected type and additional properties' { - $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' - $gist.GistId | Should -Be $gist.id - $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should have the expected type and additional properties' { + $gist.PSObject.TypeNames[0] | Should -Be 'GitHub.Gist' + $gist.GistId | Should -Be $gist.id + $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + Context 'Update Gist' { + BeforeAll { + Out-File -FilePath $fileA -InputObject $fileAUpdatedContent -Encoding utf8 + $gist = $fileA | Set-GitHubGistFile -Gist $gist.id -PassThru } - Out-File -FilePath $fileA -InputObject $fileAUpdatedContent -Encoding utf8 - $gist = $fileA | Set-GitHubGistFile -Gist $gist.id -PassThru It 'Should have the expected result' { ($gist.files | Get-Member -Type NoteProperty).Count | Should -Be 2 $gist.files.$origFileName.content | Should -Be $origContent @@ -1067,29 +1156,37 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should remove the new file' { $gist = Set-GitHubGistFile -Gist $gist.id -FileName $origFileName -Content $origContent -PassThru - It 'Should remove the new file' { - { $gist | Remove-GitHubGistFile -FileName $fileAName -Force } | Should -Not -Throw - } + { $gist | Remove-GitHubGistFile -FileName $fileAName -Force } | Should -Not -Throw } } +} + +Describe 'Rename-GitHubGistFile' { + BeforeAll { + $originalName = 'foo.txt' + $newName = 'bar.txt' + $content = 'sample content' + } - Describe 'Rename-GitHubGistFile' { + Context 'With parameters' { BeforeAll { - $originalName = 'foo.txt' - $newName = 'bar.txt' - $content = 'sample content' + $gist = New-GitHubGist -FileName $originalName -Content $content } - Context 'With parameters' { - $gist = New-GitHubGist -FileName $originalName -Content $content - It 'Should have the expected file' { - $gist.files.$originalName.content | Should -Be $content - $gist.files.$newName | Should -BeNullOrEmpty + It 'Should have the expected file' { + $gist.files.$originalName.content | Should -Be $content + $gist.files.$newName | Should -BeNullOrEmpty + } + + Context 'Rename Gist' { + BeforeAll { + $gist = Rename-GitHubGistFile -Gist $gist.id -FileName $originalName -NewName $newName -PassThru } - $gist = Rename-GitHubGistFile -Gist $gist.id -FileName $originalName -NewName $newName -PassThru It 'Should have been renamed' { $gist.files.$originalName | Should -BeNullOrEmpty $gist.files.$newName.content | Should -Be $content @@ -1100,20 +1197,28 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - It 'Should successfully remove the gist' { - { $gist | Remove-GitHubGist -Force } | Should -Not -Throw - } + It 'Should successfully remove the gist' { + { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } + } - Context 'With the gist on the pipeline' { + Context 'With the gist on the pipeline' { + BeforeAll { $gist = New-GitHubGist -FileName $originalName -Content $content - It 'Should have the expected file' { - $gist.files.$originalName.content | Should -Be $content - $gist.files.$newName | Should -BeNullOrEmpty + } + + It 'Should have the expected file' { + $gist.files.$originalName.content | Should -Be $content + $gist.files.$newName | Should -BeNullOrEmpty + } + + Context 'Rename Gist' { + BeforeAll { + $gist = $gist | Rename-GitHubGistFile -FileName $originalName -NewName $newName -PassThru } - $gist = $gist | Rename-GitHubGistFile -FileName $originalName -NewName $newName -PassThru It 'Should have been renamed' { $gist.files.$originalName | Should -BeNullOrEmpty $gist.files.$newName.content | Should -Be $content @@ -1124,26 +1229,34 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - It 'Should successfully remove the gist' { - { $gist | Remove-GitHubGist -Force } | Should -Not -Throw - } + It 'Should successfully remove the gist' { + { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } } +} + +Describe 'Remove-GitHubGistFile' { + BeforeAll { + $fileName = 'sample.txt' + $content = 'sample' + } - Describe 'Remove-GitHubGistFile' { + Context 'With parameters' { BeforeAll { - $fileName = 'sample.txt' - $content = 'sample' + $gist = New-GitHubGist -FileName $fileName -Content $content } - Context 'With parameters' { - $gist = New-GitHubGist -FileName $fileName -Content $content - It 'Should have the expected file' { - $gist.files.$fileName | Should -Not -BeNullOrEmpty + It 'Should have the expected file' { + $gist.files.$fileName | Should -Not -BeNullOrEmpty + } + + Context 'Remove Gist File' { + BeforeAll { + $gist = Remove-GitHubGistFile -Gist $gist.id -FileName $fileName -Force -PassThru } - $gist = Remove-GitHubGistFile -Gist $gist.id -FileName $fileName -Force -PassThru It 'Should have been removed' { $gist.files.$fileName | Should -BeNullOrEmpty } @@ -1153,19 +1266,27 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - It 'Should successfully remove the gist' { - { $gist | Remove-GitHubGist -Force } | Should -Not -Throw - } + It 'Should successfully remove the gist' { + { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } + } - Context 'With the gist on the pipeline' { + Context 'With the gist on the pipeline' { + BeforeAll { $gist = New-GitHubGist -FileName $fileName -Content $content - It 'Should have the expected file' { - $gist.files.$fileName | Should -Not -BeNullOrEmpty + } + + It 'Should have the expected file' { + $gist.files.$fileName | Should -Not -BeNullOrEmpty + } + + Context 'Remove Gist File' { + BeforeAll { + $gist = $gist | Remove-GitHubGistFile -FileName $fileName -Confirm:$false -PassThru } - $gist = $gist | Remove-GitHubGistFile -FileName $fileName -Confirm:$false -PassThru It 'Should have been removed' { $gist.files.$fileName | Should -BeNullOrEmpty } @@ -1175,15 +1296,15 @@ try $gist.GistId | Should -Be $gist.id $gist.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - It 'Should successfully remove the gist' { - { $gist | Remove-GitHubGist -Force } | Should -Not -Throw - } + It 'Should successfully remove the gist' { + { $gist | Remove-GitHubGist -Force } | Should -Not -Throw } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubGraphQl.Tests.ps1 b/Tests/GitHubGraphQl.Tests.ps1 index 0c94719b..31c5fe4a 100644 --- a/Tests/GitHubGraphQl.Tests.ps1 +++ b/Tests/GitHubGraphQl.Tests.ps1 @@ -8,74 +8,108 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} -try -{ - Describe 'GitHubCore/Invoke-GHGraphQl' { - BeforeAll { - $Description = 'description' - $AccessToken = '' - $TelemetryEventName = $null - $TelemetryProperties = @{} - $TelemetryExceptionBucket = $null +Describe 'GitHubCore/Invoke-GHGraphQl' { + BeforeAll { + $Description = 'description' + $AccessToken = '' + $TelemetryEventName = $null + $TelemetryProperties = @{} + $TelemetryExceptionBucket = $null - Mock -CommandName Invoke-UpdateCheck -ModuleName $script:moduleName + Mock -CommandName Invoke-UpdateCheck -ModuleName $script:moduleName + } + + Context 'When a valid query is specified' { + BeforeAll { + $testBody = '{ "query": "query login { viewer { login } }" }' } - Context 'When a valid query is specified' { - BeforeAll { - $testBody = '{ "query": "query login { viewer { login } }" }' + BeforeEach { + $invokeGHGraphQLParms = @{ + Body = $testBody } + $result = Invoke-GHGraphQl @invokeGHGraphQLParms + } - It 'Should return the expected result' { - $invokeGHGraphQLParms = @{ - Body = $testBody - } - $result = Invoke-GHGraphQl @invokeGHGraphQLParms + It 'Should return the expected result' { + + $result.data.viewer.login | Should -Be $script:ownerName + } - $result.data.viewer.login | Should -Be $script:ownerName + It 'Should call the expected mocks' { + Assert-MockCalled -CommandName Invoke-UpdateCheck ` + -ModuleName $script:moduleName ` + -Exactly -Times 1 + } + } + + Context 'When there is a Web/HTTP Request exception in Invoke-WebRequest' { + BeforeAll { + $testHostName = 'invalidhostname' + $testBody = 'testBody' + + if ($PSVersionTable.PSEdition -eq 'Core') + { + # The exception message varies per platform. We could special-case it, but the exact message + # may change over time and the module itself doesn't care about the specific message. + # We'll just do a best-case match. + # Windows: "No such host is known. ($($testHostName):443)" + # Mac: "nodename nor servname provided, or not known ($($testHostName):443)" + # Linux: "Resource temporarily unavailable ($($testHostName):443)" + $exceptionMessage = "*$testHostName*" + $categoryInfo = 'InvalidOperation' + $targetName = "*$testHostName*" + } + else + { + $exceptionMessage = "The remote name could not be resolved: '$testHostName'" + $categoryInfo = 'NotSpecified' + $targetName = $testBody } - It 'Should call the expected mocks' { - Assert-MockCalled -CommandName Invoke-UpdateCheck ` - -ModuleName $script:moduleName ` - -Exactly -Times 1 + Mock -CommandName Get-GitHubConfiguration -ModuleName $script:moduleName ` + -ParameterFilter { $Name -eq 'ApiHostName' } ` + -MockWith { 'invalidhostname' } + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | + Should -Throw + + $Error[0].Exception.Message | Should -BeLike $exceptionMessage + $Error[0].CategoryInfo.Category | Should -Be $categoryInfo + $Error[0].CategoryInfo.TargetName | Should -BeLike $targetName + $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' } + } - Context 'When there is a Web/HTTP Request exception in Invoke-WebRequest' { + Context 'When there is a Web/HTTP Response exception in Invoke-WebRequest' { + Context 'When there is invalid JSON in the request body' { BeforeAll { - $testHostName = 'invalidhostname' - $testBody = 'testBody' + $testBody = 'InvalidJson' if ($PSVersionTable.PSEdition -eq 'Core') { - # The exception message varies per platform. We could special-case it, but the exact message - # may change over time and the module itself doesn't care about the specific message. - # We'll just do a best-case match. - # Windows: "No such host is known. ($($testHostName):443)" - # Mac: "nodename nor servname provided, or not known ($($testHostName):443)" - # Linux: "Resource temporarily unavailable ($($testHostName):443)" - $exceptionMessage = "*$testHostName*" - $categoryInfo = 'InvalidOperation' - $targetName = "*$testHostName*" + $exceptionMessage1 = '*Response status code does not indicate success: 400 (Bad Request)*' } else { - $exceptionMessage = "The remote name could not be resolved: '$testHostName'" - $categoryInfo = 'NotSpecified' - $targetName = $testBody + $exceptionMessage1 = '*The remote server returned an error: (400) Bad Request*' } - Mock -CommandName Get-GitHubConfiguration -ModuleName $script:moduleName ` - -ParameterFilter { $Name -eq 'ApiHostName' } ` - -MockWith { 'invalidhostname' } + $exceptionMessage2 = '*Problems parsing JSON | https://docs.github.com/graphql*' } It 'Should throw the correct exception' { @@ -83,91 +117,33 @@ try Body = $testBody } { Invoke-GHGraphQl @invokeGHGraphQlParms } | - Should -Throw + Should -Throw - $Error[0].Exception.Message | Should -BeLike $exceptionMessage - $Error[0].CategoryInfo.Category | Should -Be $categoryInfo - $Error[0].CategoryInfo.TargetName | Should -BeLike $targetName + $Error[0].Exception.Message | Should -BeLike $exceptionMessage1 + $Error[0].Exception.Message | Should -BeLike $exceptionMessage2 + $Error[0].Exception.Message | Should -BeLike '*RequestId:*' + $Error[0].CategoryInfo.Category | Should -Be 'InvalidOperation' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' } } - Context 'When there is a Web/HTTP Response exception in Invoke-WebRequest' { - Context 'When there is invalid JSON in the request body' { - BeforeAll { - $testBody = 'InvalidJson' - - if ($PSVersionTable.PSEdition -eq 'Core') - { - $exceptionMessage1 = '*Response status code does not indicate success: 400 (Bad Request)*' - } - else - { - $exceptionMessage1 = '*The remote server returned an error: (400) Bad Request*' - } - - $exceptionMessage2 = '*Problems parsing JSON | https://docs.github.com/graphql*' - } - - It 'Should throw the correct exception' { - $invokeGHGraphQLParms = @{ - Body = $testBody - } - { Invoke-GHGraphQl @invokeGHGraphQlParms } | - Should -Throw - - $Error[0].Exception.Message | Should -BeLike $exceptionMessage1 - $Error[0].Exception.Message | Should -BeLike $exceptionMessage2 - $Error[0].Exception.Message | Should -BeLike '*RequestId:*' - $Error[0].CategoryInfo.Category | Should -Be 'InvalidOperation' - $Error[0].CategoryInfo.TargetName | Should -Be $testBody - $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' - } - } - - Context 'When the query user is not authenticated' { - BeforeAll { - $testBody = '{ "query": "query login { viewer { login } }" }' - - if ($PSVersionTable.PSEdition -eq 'Core') - { - $exceptionMessage1 = '*Response status code does not indicate success: 401 (Unauthorized)*' - } - else - { - $exceptionMessage1 = '*The remote server returned an error: (401) Unauthorized*' - } - - $exceptionMessage2 = '*This endpoint requires you to be authenticated.*' + Context 'When the query user is not authenticated' { + BeforeAll { + $testBody = '{ "query": "query login { viewer { login } }" }' - Mock -CommandName Get-AccessToken -ModuleName $script:moduleName + if ($PSVersionTable.PSEdition -eq 'Core') + { + $exceptionMessage1 = '*Response status code does not indicate success: 401 (Unauthorized)*' } - - It 'Should throw the correct exception' { - $invokeGHGraphQLParms = @{ - Body = $testBody - } - { Invoke-GHGraphQl @invokeGHGraphQlParms } | - Should -Throw - - $Error[0].Exception.Message | Should -BeLike $exceptionMessage1 - $Error[0].Exception.Message | Should -BeLike $exceptionMessage2 - $Error[0].Exception.Message | Should -BeLike '*RequestId:*' - $Error[0].CategoryInfo.Category | Should -Be 'InvalidOperation' - $Error[0].CategoryInfo.TargetName | Should -Be $testBody - $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' + else + { + $exceptionMessage1 = '*The remote server returned an error: (401) Unauthorized*' } - } - } - Context 'When there is an other exception in Invoke-WebRequest' { - BeforeAll { - $testWebRequestTimeoutSec = 'invalid' - $testBody = 'testBody' + $exceptionMessage2 = '*This endpoint requires you to be authenticated.*' - Mock -CommandName Get-GitHubConfiguration -ModuleName $script:moduleName ` - -ParameterFilter { $Name -eq 'WebRequestTimeoutSec' } ` - -MockWith { 'invalid' } + Mock -CommandName Get-AccessToken -ModuleName $script:moduleName } It 'Should throw the correct exception' { @@ -175,59 +151,85 @@ try Body = $testBody } { Invoke-GHGraphQl @invokeGHGraphQlParms } | - Should -Throw "Cannot convert value ""$testWebRequestTimeoutSec""" + Should -Throw - $Error[0].CategoryInfo.Category | Should -Be 'InvalidArgument' + $Error[0].Exception.Message | Should -BeLike $exceptionMessage1 + $Error[0].Exception.Message | Should -BeLike $exceptionMessage2 + $Error[0].Exception.Message | Should -BeLike '*RequestId:*' + $Error[0].CategoryInfo.Category | Should -Be 'InvalidOperation' $Error[0].CategoryInfo.TargetName | Should -Be $testBody - $Error[0].FullyQualifiedErrorId | Should -BeLike 'CannotConvertArgumentNoMessage*' + $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' } } + } - Context 'When the GraphQl JSON Query is Invalid' { - BeforeAll { - $invalidQuery = 'InvalidQuery' - $testBody = "{ ""query"":""$invalidQuery"" }" - } + Context 'When there is an other exception in Invoke-WebRequest' { + BeforeAll { + $testWebRequestTimeoutSec = 'invalid' + $testBody = 'testBody' - It 'Should throw the correct exception' { - $invokeGHGraphQLParms = @{ - Body = $testBody - } - { Invoke-GHGraphQl @invokeGHGraphQlParms } | Should -Throw + Mock -CommandName Get-GitHubConfiguration -ModuleName $script:moduleName ` + -ParameterFilter { $Name -eq 'WebRequestTimeoutSec' } ` + -MockWith { 'invalid' } + } - $Error[0].Exception.Message | Should -BeLike "*Parse error on ""$invalidQuery""*" - $Error[0].Exception.Message | Should -BeLike '*RequestId:*' - $Error[0].CategoryInfo.Category | Should -Be 'NotSpecified' - $Error[0].CategoryInfo.TargetName | Should -Be $testBody - $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | + Should -Throw + + $Error[0].CategoryInfo.Category | Should -Be 'InvalidArgument' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody + $Error[0].FullyQualifiedErrorId | Should -BeLike 'CannotConvertArgumentNoMessage*' } + } - Context 'When the GraphQl JSON query returns an error of ''NOT_FOUND''' { - BeforeAll { - $testOwner = 'microsoft' - $testRepo = 'nonexisting-repo' - $testQuery = "query repo { repository(name: \""$testRepo\"", owner: \""$testOwner\"") { id } }" - $testBody = "{ ""query"": ""$testQuery"" }" + Context 'When the GraphQl JSON Query is Invalid' { + BeforeAll { + $invalidQuery = 'InvalidQuery' + $testBody = "{ ""query"":""$invalidQuery"" }" + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | Should -Throw - It 'Should throw the correct exception' { - $invokeGHGraphQLParms = @{ - Body = $testBody - } - { Invoke-GHGraphQl @invokeGHGraphQlParms } | Should -Throw + $Error[0].Exception.Message | Should -BeLike "*Parse error on ""$invalidQuery""*" + $Error[0].Exception.Message | Should -BeLike '*RequestId:*' + $Error[0].CategoryInfo.Category | Should -Be 'NotSpecified' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody + $Error[0].FullyQualifiedErrorId | Should -BeLike '*Invoke-GHGraphQl' + } + } - $Error[0].Exception.Message | Should -BeLike "*Could not resolve to a Repository with the name '$testOwner/$testRepo'*" - $Error[0].Exception.Message | Should -BeLike '*RequestId:*' - $Error[0].CategoryInfo.Category | Should -Be 'ObjectNotFound' - $Error[0].CategoryInfo.TargetName | Should -Be $testBody - $Error[0].FullyQualifiedErrorId | Should -Be 'NOT_FOUND,Invoke-GHGraphQl' + Context 'When the GraphQl JSON query returns an error of ''NOT_FOUND''' { + BeforeAll { + $testOwner = 'microsoft' + $testRepo = 'nonexisting-repo' + $testQuery = "query repo { repository(name: \""$testRepo\"", owner: \""$testOwner\"") { id } }" + $testBody = "{ ""query"": ""$testQuery"" }" + } + + It 'Should throw the correct exception' { + $invokeGHGraphQLParms = @{ + Body = $testBody } + { Invoke-GHGraphQl @invokeGHGraphQlParms } | Should -Throw + + $Error[0].Exception.Message | Should -BeLike "*Could not resolve to a Repository with the name '$testOwner/$testRepo'*" + $Error[0].Exception.Message | Should -BeLike '*RequestId:*' + $Error[0].CategoryInfo.Category | Should -Be 'ObjectNotFound' + $Error[0].CategoryInfo.TargetName | Should -Be $testBody + $Error[0].FullyQualifiedErrorId | Should -Be 'NOT_FOUND,Invoke-GHGraphQl' } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubIssueComments.tests.ps1 b/Tests/GitHubIssueComments.tests.ps1 index 4230d67a..89fb60fd 100644 --- a/Tests/GitHubIssueComments.tests.ps1 +++ b/Tests/GitHubIssueComments.tests.ps1 @@ -8,15 +8,14 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() # This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readonly, hidden variables. @{ defaultIssueTitle = "Test Title" @@ -25,46 +24,54 @@ try }.GetEnumerator() | ForEach-Object { Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value } +} + +Describe 'Creating, modifying and deleting comments' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $issue = $repo | New-GitHubIssue -Title $defaultIssueTitle + } - Describe 'Creating, modifying and deleting comments' { + AfterAll { + $repo | Remove-GitHubRepository -Confirm:$false + } + + Context 'With parameters' { BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $issue = $repo | New-GitHubIssue -Title $defaultIssueTitle + $comment = New-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Body $defaultCommentBody + $result = Get-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $comment.id + $commentId = $result.id } - AfterAll { - $repo | Remove-GitHubRepository -Confirm:$false + It 'Should have the expected body text' { + $comment.body | Should -Be $defaultCommentBody } - Context 'With parameters' { - $comment = New-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Body $defaultCommentBody - It 'Should have the expected body text' { - $comment.body | Should -Be $defaultCommentBody - } + It 'Should have the expected type and additional properties' { + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' + $comment.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' + $comment.RepositoryUrl | Should -Be $repo.RepositoryUrl + $comment.CommentId | Should -Be $comment.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' - $comment.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' - $comment.RepositoryUrl | Should -Be $repo.RepositoryUrl - $comment.CommentId | Should -Be $comment.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should be the expected comment' { + $result.id | Should -Be $comment.id + } - $result = Get-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $comment.id - It 'Should be the expected comment' { - $result.id | Should -Be $comment.id - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' + $result.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.CommentId | Should -Be $result.id + $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' - $result.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.CommentId | Should -Be $result.id - $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + Context 'Update Comment' { + BeforeAll { + $updated = Set-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId -Body $defaultEditedCommentBody -PassThru } - $commentId = $result.id - $updated = Set-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId -Body $defaultEditedCommentBody -PassThru It 'Should have modified the expected comment' { $updated.id | Should -Be $commentId } @@ -80,42 +87,55 @@ try $updated.CommentId | Should -Be $updated.id $updated.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + + Context 'Remove Comment' { + BeforeAll { + Remove-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId -Force + } - Remove-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId -Force It 'Should have been removed' { { Get-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId } | Should -Throw } } + } - Context 'With the repo on the pipeline' { + Context 'With the repo on the pipeline' { + BeforeAll { $comment = $repo | New-GitHubIssueComment -Issue $issue.number -Body $defaultCommentBody - It 'Should have the expected body text' { - $comment.body | Should -Be $defaultCommentBody - } + $result = $repo | Get-GitHubIssueComment -Comment $comment.id + $commentId = $result.id + } - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' - $comment.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' - $comment.RepositoryUrl | Should -Be $repo.RepositoryUrl - $comment.CommentId | Should -Be $comment.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected body text' { + $comment.body | Should -Be $defaultCommentBody + } - $result = $repo | Get-GitHubIssueComment -Comment $comment.id - It 'Should be the expected comment' { - $result.id | Should -Be $comment.id - } + It 'Should have the expected type and additional properties' { + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' + $comment.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' + $comment.RepositoryUrl | Should -Be $repo.RepositoryUrl + $comment.CommentId | Should -Be $comment.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' - $result.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.CommentId | Should -Be $result.id - $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should be the expected comment' { + $result.id | Should -Be $comment.id + } + + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' + $result.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.CommentId | Should -Be $result.id + $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + Context 'Update Comment' { + BeforeAll { + $updated = $repo | Set-GitHubIssueComment -Comment $commentId -Body $defaultEditedCommentBody -PassThru } - $commentId = $result.id - $updated = $repo | Set-GitHubIssueComment -Comment $commentId -Body $defaultEditedCommentBody -PassThru It 'Should have modified the expected comment' { $updated.id | Should -Be $commentId } @@ -131,42 +151,55 @@ try $updated.CommentId | Should -Be $updated.id $updated.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + + Context 'Remove Comment' { + BeforeAll { + $repo | Remove-GitHubIssueComment -Comment $commentId -Force + } - $repo | Remove-GitHubIssueComment -Comment $commentId -Force It 'Should have been removed' { { $repo | Get-GitHubIssueComment -Comment $commentId } | Should -Throw } } + } - Context 'With the issue on the pipeline' { + Context 'With the issue on the pipeline' { + BeforeAll { $comment = $issue | New-GitHubIssueComment -Body $defaultCommentBody - It 'Should have the expected body text' { - $comment.body | Should -Be $defaultCommentBody - } + $result = Get-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $comment.id + $commentId = $result.id + } - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' - $comment.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' - $comment.RepositoryUrl | Should -Be $repo.RepositoryUrl - $comment.CommentId | Should -Be $comment.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected body text' { + $comment.body | Should -Be $defaultCommentBody + } - $result = Get-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $comment.id - It 'Should be the expected comment' { - $result.id | Should -Be $comment.id - } + It 'Should have the expected type and additional properties' { + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' + $comment.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' + $comment.RepositoryUrl | Should -Be $repo.RepositoryUrl + $comment.CommentId | Should -Be $comment.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' - $result.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.CommentId | Should -Be $result.id - $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should be the expected comment' { + $result.id | Should -Be $comment.id + } + + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' + $result.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.CommentId | Should -Be $result.id + $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + Context 'Update comment' { + BeforeAll { + $updated = Set-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId -Body $defaultEditedCommentBody -PassThru } - $commentId = $result.id - $updated = Set-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId -Body $defaultEditedCommentBody -PassThru It 'Should have modified the expected comment' { $updated.id | Should -Be $commentId } @@ -182,41 +215,54 @@ try $updated.CommentId | Should -Be $updated.id $updated.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + + Context 'Remove Comment' { + BeforeAll { + Remove-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId -Force + } - Remove-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId -Force It 'Should have been removed' { { Get-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Comment $commentId } | Should -Throw } } + } - Context 'With the comment object on the pipeline' { + Context 'With the comment object on the pipeline' { + BeforeAll { $comment = New-GitHubIssueComment -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number -Body $defaultCommentBody - It 'Should have the expected body text' { - $comment.body | Should -Be $defaultCommentBody - } + $result = $comment | Get-GitHubIssueComment + } - It 'Should have the expected type and additional properties' { - $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' - $comment.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' - $comment.RepositoryUrl | Should -Be $repo.RepositoryUrl - $comment.CommentId | Should -Be $comment.id - $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected body text' { + $comment.body | Should -Be $defaultCommentBody + } - $result = $comment | Get-GitHubIssueComment - It 'Should be the expected comment' { - $result.id | Should -Be $comment.id - } + It 'Should have the expected type and additional properties' { + $comment.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' + $comment.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' + $comment.RepositoryUrl | Should -Be $repo.RepositoryUrl + $comment.CommentId | Should -Be $comment.id + $comment.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' - $result.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.CommentId | Should -Be $result.id - $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should be the expected comment' { + $result.id | Should -Be $comment.id + } + + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.IssueComment' + $result.PSObject.TypeNames[1] | Should -Be 'GitHub.Comment' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.CommentId | Should -Be $result.id + $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + + Context 'Update comment' { + BeforeAll { + $updated = $comment | Set-GitHubIssueComment -Body $defaultEditedCommentBody -PassThru } - $updated = $comment | Set-GitHubIssueComment -Body $defaultEditedCommentBody -PassThru It 'Should have modified the expected comment' { $updated.id | Should -Be $comment.id } @@ -232,16 +278,21 @@ try $updated.CommentId | Should -Be $updated.id $updated.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + + Context 'Remove comment' { + BeforeAll { + $comment | Remove-GitHubIssueComment -Force + } - $comment | Remove-GitHubIssueComment -Force It 'Should have been removed' { { $comment | Get-GitHubIssueComment } | Should -Throw } } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubIssues.tests.ps1 b/Tests/GitHubIssues.tests.ps1 index 34494164..a43a29a1 100644 --- a/Tests/GitHubIssues.tests.ps1 +++ b/Tests/GitHubIssues.tests.ps1 @@ -8,153 +8,163 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} -try -{ - Describe 'Getting issues for a repository' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - } +Describe 'Getting issues for a repository' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false - } + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } - Context 'Getting all issues for a repository with parameters' { + Context 'Getting all issues for a repository with parameters' { + It 'Should return expected number of issues' { $currentIssues = @(Get-GitHubIssue -OwnerName $script:ownerName -RepositoryName $repo.name) $numIssues = 2 1..$numIssues | - ForEach-Object { New-GitHubIssue -OwnerName $script:ownerName -RepositoryName $repo.name -Title ([Guid]::NewGuid().Guid) } | - Out-Null + ForEach-Object { New-GitHubIssue -OwnerName $script:ownerName -RepositoryName $repo.name -Title ([Guid]::NewGuid().Guid) } | + Out-Null $issues = @(Get-GitHubIssue -OwnerName $script:ownerName -RepositoryName $repo.name) - It 'Should return expected number of issues' { - $issues.Count | Should -Be ($numIssues + $currentIssues.Count) - } + $issues.Count | Should -Be ($numIssues + $currentIssues.Count) } + } - Context 'Getting all issues for a repository with the repo on the pipeline' { + Context 'Getting all issues for a repository with the repo on the pipeline' { + It 'Should return expected number of issues' { $currentIssues = @($repo | Get-GitHubIssue) $numIssues = 2 1..$numIssues | - ForEach-Object { $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) } | - Out-Null + ForEach-Object { $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) } | + Out-Null $issues = @($repo | Get-GitHubIssue) - It 'Should return expected number of issues' { - $issues.Count | Should -Be ($numIssues + $currentIssues.Count) - } + $issues.Count | Should -Be ($numIssues + $currentIssues.Count) } + } - Context 'Getting a specific issue with parameters' { + Context 'Getting a specific issue with parameters' { + BeforeAll { $issue = New-GitHubIssue -OwnerName $script:ownerName -RepositoryName $repo.name -Title ([Guid]::NewGuid().Guid) $result = Get-GitHubIssue -OwnerName $script:ownerName -RepositoryName $repo.name -Issue $issue.number - It 'Should be the expected Issue' { - $result.id | Should -Be $issue.id - } + } - It 'Should have the expected property values' { - $result.user.login | Should -Be $script:ownerName - $result.labels | Should -BeNullOrEmpty - $result.milestone | Should -BeNullOrEmpty - $result.assignee | Should -BeNullOrEmpty - $result.assignees | Should -BeNullOrEmpty - $result.closed_by | Should -BeNullOrEmpty - $result.repository | Should -BeNullOrEmpty - } + It 'Should be the expected Issue' { + $result.id | Should -Be $issue.id + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.IssueId | Should -Be $result.id - $result.IssueNumber | Should -Be $result.number - $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected property values' { + $result.user.login | Should -Be $script:ownerName + $result.labels | Should -BeNullOrEmpty + $result.milestone | Should -BeNullOrEmpty + $result.assignee | Should -BeNullOrEmpty + $result.assignees | Should -BeNullOrEmpty + $result.closed_by | Should -BeNullOrEmpty + $result.repository | Should -BeNullOrEmpty + } + + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.IssueId | Should -Be $result.id + $result.IssueNumber | Should -Be $result.number + $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Getting a specific issue with the repo on the pipeline' { + Context 'Getting a specific issue with the repo on the pipeline' { + BeforeAll { $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) $result = $repo | Get-GitHubIssue -Issue $issue.number - It 'Should be the expected Issue' { - $result.id | Should -Be $issue.id - } + } - It 'Should have the expected property values' { - $result.user.login | Should -Be $script:ownerName - $result.labels | Should -BeNullOrEmpty - $result.milestone | Should -BeNullOrEmpty - $result.assignee | Should -BeNullOrEmpty - $result.assignees | Should -BeNullOrEmpty - $result.closed_by | Should -BeNullOrEmpty - $result.repository | Should -BeNullOrEmpty - } + It 'Should be the expected Issue' { + $result.id | Should -Be $issue.id + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.IssueId | Should -Be $result.id - $result.IssueNumber | Should -Be $result.number - $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected property values' { + $result.user.login | Should -Be $script:ownerName + $result.labels | Should -BeNullOrEmpty + $result.milestone | Should -BeNullOrEmpty + $result.assignee | Should -BeNullOrEmpty + $result.assignees | Should -BeNullOrEmpty + $result.closed_by | Should -BeNullOrEmpty + $result.repository | Should -BeNullOrEmpty + } + + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.IssueId | Should -Be $result.id + $result.IssueNumber | Should -Be $result.number + $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Getting a specific issue with the issue on the pipeline' { + Context 'Getting a specific issue with the issue on the pipeline' { + BeforeAll { $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) $result = $issue | Get-GitHubIssue -Issue $issue.number - It 'Should be the expected Issue' { - $result.id | Should -Be $issue.id - } + } - It 'Should have the expected property values' { - $result.user.login | Should -Be $script:ownerName - $result.labels | Should -BeNullOrEmpty - $result.milestone | Should -BeNullOrEmpty - $result.assignee | Should -BeNullOrEmpty - $result.assignees | Should -BeNullOrEmpty - $result.closed_by | Should -BeNullOrEmpty - $result.repository | Should -BeNullOrEmpty - } + It 'Should be the expected Issue' { + $result.id | Should -Be $issue.id + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.IssueId | Should -Be $result.id - $result.IssueNumber | Should -Be $result.number - $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected property values' { + $result.user.login | Should -Be $script:ownerName + $result.labels | Should -BeNullOrEmpty + $result.milestone | Should -BeNullOrEmpty + $result.assignee | Should -BeNullOrEmpty + $result.assignees | Should -BeNullOrEmpty + $result.closed_by | Should -BeNullOrEmpty + $result.repository | Should -BeNullOrEmpty } - Context 'When issues are retrieved with a specific MediaTypes' { + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.IssueId | Should -Be $result.id + $result.IssueNumber | Should -Be $result.number + $result.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + Context 'When issues are retrieved with a specific MediaTypes' { + It 'Should return an issue with body_html' { $newIssue = New-GitHubIssue -OwnerName $script:ownerName -RepositoryName $repo.name -Title ([guid]::NewGuid()) -Body ([Guid]::NewGuid()) $issues = @(Get-GitHubIssue -Uri $repo.svn_url -Issue $newIssue.number -MediaType 'Html') - It 'Should return an issue with body_html' { - $issues[0].body_html | Should -Not -Be $null - } + $issues[0].body_html | Should -Not -Be $null } } +} - Describe 'Date-specific Issue tests' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - } +Describe 'Date-specific Issue tests' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false - } + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } - Context 'Date specific scenarios' { + Context 'Date specific scenarios' { + BeforeAll { $existingIssues = @($repo | Get-GitHubIssue -State All) $newIssues = @() @@ -169,44 +179,46 @@ try $existingOpenIssues = @($existingIssues | Where-Object { $_.state -eq 'open' }) $newOpenIssues = @($newIssues | Where-Object { $_.state -eq 'open' }) $issues = @($repo | Get-GitHubIssue) - It 'Should return only open issues' { - $issues.Count | Should -Be ($newOpenIssues.Count + $existingOpenIssues.Count) - } + } + It 'Should return only open issues' { + $issues.Count | Should -Be ($newOpenIssues.Count + $existingOpenIssues.Count) + } + It 'Should return all issues' { $issues = @($repo | Get-GitHubIssue -State All) - It 'Should return all issues' { - $issues.Count | Should -Be ($newIssues.Count + $existingIssues.Count) - } + $issues.Count | Should -Be ($newIssues.Count + $existingIssues.Count) + } + + It 'Smart object date conversion works for comparing dates' { $createdOnOrAfterDate = Get-Date -Date $newIssues[0].created_at $createdOnOrBeforeDate = Get-Date -Date $newIssues[2].created_at $issues = @(($repo | Get-GitHubIssue) | Where-Object { ($_.created_at -ge $createdOnOrAfterDate) -and ($_.created_at -le $createdOnOrBeforeDate) }) + $issues.Count | Should -Be 2 + } - It 'Smart object date conversion works for comparing dates' { - $issues.Count | Should -Be 2 - } - + It 'Able to filter based on date and state' { $createdDate = Get-Date -Date $newIssues[1].created_at $issues = @(Get-GitHubIssue -Uri $repo.svn_url -State All | Where-Object { ($_.created_at -ge $createdDate) -and ($_.state -eq 'closed') }) - It 'Able to filter based on date and state' { - $issues.Count | Should -Be 1 - } + $issues.Count | Should -Be 1 } } - Describe 'Creating issues' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $milestone = $repo | New-GitHubMilestone -Title ([Guid]::NewGuid().Guid) - } +} +Describe 'Creating issues' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $milestone = $repo | New-GitHubMilestone -Title ([Guid]::NewGuid().Guid) + } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false - } + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } - Context 'Creating an Issue with parameters' { + Context 'Creating an Issue with parameters' { + BeforeAll { $params = @{ 'OwnerName' = $script:ownerName 'RepositoryName' = $repo.name @@ -219,32 +231,34 @@ try } $issue = New-GitHubIssue @params + } - It 'Should have the expected property values' { - $issue.title | Should -Be $params.Title - $issue.body | Should -Be $params.Body - $issue.assignee.login | Should -Be $params.Assignee - $issue.assignees.Count | Should -Be 1 - $issue.assignees[0].login | Should -Be $params.Assignee - $issue.milestone.number | Should -Be $params.Milestone - $issue.labels.Count | Should -Be 1 - $issue.labels[0].name | Should -Contain $params.Label - } + It 'Should have the expected property values' { + $issue.title | Should -Be $params.Title + $issue.body | Should -Be $params.Body + $issue.assignee.login | Should -Be $params.Assignee + $issue.assignees.Count | Should -Be 1 + $issue.assignees[0].login | Should -Be $params.Assignee + $issue.milestone.number | Should -Be $params.Milestone + $issue.labels.Count | Should -Be 1 + $issue.labels[0].name | Should -Contain $params.Label + } - It 'Should have the expected type and additional properties' { - $issue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' - $issue.RepositoryUrl | Should -Be $repo.RepositoryUrl - $issue.IssueId | Should -Be $issue.id - $issue.IssueNumber | Should -Be $issue.number - $issue.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $issue.assignee.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $issue.assignees[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $issue.milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' - $issue.labels[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - } + It 'Should have the expected type and additional properties' { + $issue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' + $issue.RepositoryUrl | Should -Be $repo.RepositoryUrl + $issue.IssueId | Should -Be $issue.id + $issue.IssueNumber | Should -Be $issue.number + $issue.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $issue.assignee.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $issue.assignees[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $issue.milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' + $issue.labels[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Label' } + } - Context 'Creating an Issue with the repo on the pipeline' { + Context 'Creating an Issue with the repo on the pipeline' { + BeforeAll { $params = @{ 'Title' = '-issue title-' 'Body' = '-issue body-' @@ -255,67 +269,75 @@ try } $issue = $repo | New-GitHubIssue @params + } - It 'Should have the expected property values' { - $issue.title | Should -Be $params.Title - $issue.body | Should -Be $params.Body - $issue.assignee.login | Should -Be $params.Assignee - $issue.assignees.Count | Should -Be 1 - $issue.assignees[0].login | Should -Be $params.Assignee - $issue.milestone.number | Should -Be $params.Milestone - $issue.labels.Count | Should -Be 1 - $issue.labels[0].name | Should -Contain $params.Label - } + It 'Should have the expected property values' { + $issue.title | Should -Be $params.Title + $issue.body | Should -Be $params.Body + $issue.assignee.login | Should -Be $params.Assignee + $issue.assignees.Count | Should -Be 1 + $issue.assignees[0].login | Should -Be $params.Assignee + $issue.milestone.number | Should -Be $params.Milestone + $issue.labels.Count | Should -Be 1 + $issue.labels[0].name | Should -Contain $params.Label + } - It 'Should have the expected type and additional properties' { - $issue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' - $issue.RepositoryUrl | Should -Be $repo.RepositoryUrl - $issue.IssueId | Should -Be $issue.id - $issue.IssueNumber | Should -Be $issue.number - $issue.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $issue.assignee.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $issue.assignees[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $issue.milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' - $issue.labels[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - } + It 'Should have the expected type and additional properties' { + $issue.PSObject.TypeNames[0] | Should -Be 'GitHub.Issue' + $issue.RepositoryUrl | Should -Be $repo.RepositoryUrl + $issue.IssueId | Should -Be $issue.id + $issue.IssueNumber | Should -Be $issue.number + $issue.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $issue.assignee.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $issue.assignees[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $issue.milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' + $issue.labels[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Label' } } +} + +Describe 'Updating issues' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $milestone = $repo | New-GitHubMilestone -Title ([Guid]::NewGuid().Guid) + $title = 'issue title' + } - Describe 'Updating issues' { + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } + + Context 'Updating an Issue with parameters' { BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $milestone = $repo | New-GitHubMilestone -Title ([Guid]::NewGuid().Guid) - $title = 'issue title' + $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title $title } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + It 'Should have the expected property values' { + $issue.title | Should -Be $title + $issue.body | Should -BeNullOrEmpty + $issue.assignee.login | Should -BeNullOrEmpty + $issue.assignees | Should -BeNullOrEmpty + $issue.milestone | Should -BeNullOrEmpty + $issue.labels | Should -BeNullOrEmpty } - Context 'Updating an Issue with parameters' { - $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title $title - It 'Should have the expected property values' { - $issue.title | Should -Be $title - $issue.body | Should -BeNullOrEmpty - $issue.assignee.login | Should -BeNullOrEmpty - $issue.assignees | Should -BeNullOrEmpty - $issue.milestone | Should -BeNullOrEmpty - $issue.labels | Should -BeNullOrEmpty - } + Context 'Update issue' { + BeforeAll { + $params = @{ + 'OwnerName' = $script:ownerName + 'RepositoryName' = $repo.name + 'Issue' = $issue.number + 'Title' = '-new title-' + 'Body' = '-new body-' + 'Assignee' = $script:ownerName + 'Milestone' = $milestone.number + 'Label' = 'bug' + 'MediaType' = 'Raw' + } - $params = @{ - 'OwnerName' = $script:ownerName - 'RepositoryName' = $repo.name - 'Issue' = $issue.number - 'Title' = '-new title-' - 'Body' = '-new body-' - 'Assignee' = $script:ownerName - 'Milestone' = $milestone.number - 'Label' = 'bug' - 'MediaType' = 'Raw' + $updated = Set-GitHubIssue @params -PassThru } - $updated = Set-GitHubIssue @params -PassThru It 'Should have the expected property values' { $updated.id | Should -Be $issue.id $updated.number | Should -Be $issue.number @@ -341,29 +363,37 @@ try $updated.labels[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Label' } } + } - Context 'Updating an Issue with the repo on the pipeline' { + Context 'Updating an Issue with the repo on the pipeline' { + BeforeAll { $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title $title - It 'Should have the expected property values' { - $issue.title | Should -Be $title - $issue.body | Should -BeNullOrEmpty - $issue.assignee.login | Should -BeNullOrEmpty - $issue.assignees | Should -BeNullOrEmpty - $issue.milestone | Should -BeNullOrEmpty - $issue.labels | Should -BeNullOrEmpty - } + } - $params = @{ - 'Issue' = $issue.number - 'Title' = '-new title-' - 'Body' = '-new body-' - 'Assignee' = $script:ownerName - 'Milestone' = $milestone.number - 'Label' = 'bug' - 'MediaType' = 'Raw' + It 'Should have the expected property values' { + $issue.title | Should -Be $title + $issue.body | Should -BeNullOrEmpty + $issue.assignee.login | Should -BeNullOrEmpty + $issue.assignees | Should -BeNullOrEmpty + $issue.milestone | Should -BeNullOrEmpty + $issue.labels | Should -BeNullOrEmpty + } + + Context 'Update issue' { + BeforeAll { + $params = @{ + 'Issue' = $issue.number + 'Title' = '-new title-' + 'Body' = '-new body-' + 'Assignee' = $script:ownerName + 'Milestone' = $milestone.number + 'Label' = 'bug' + 'MediaType' = 'Raw' + } + + $updated = $repo | Set-GitHubIssue @params -PassThru } - $updated = $repo | Set-GitHubIssue @params -PassThru It 'Should have the expected property values' { $updated.id | Should -Be $issue.id $updated.number | Should -Be $issue.number @@ -389,28 +419,36 @@ try $updated.labels[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Label' } } + } - Context 'Updating an Issue with the issue on the pipeline' { + Context 'Updating an Issue with the issue on the pipeline' { + BeforeAll { $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title $title - It 'Should have the expected property values' { - $issue.title | Should -Be $title - $issue.body | Should -BeNullOrEmpty - $issue.assignee.login | Should -BeNullOrEmpty - $issue.assignees | Should -BeNullOrEmpty - $issue.milestone | Should -BeNullOrEmpty - $issue.labels | Should -BeNullOrEmpty - } + } - $params = @{ - 'Title' = '-new title-' - 'Body' = '-new body-' - 'Assignee' = $script:ownerName - 'Milestone' = $milestone.number - 'Label' = 'bug' - 'MediaType' = 'Raw' + It 'Should have the expected property values' { + $issue.title | Should -Be $title + $issue.body | Should -BeNullOrEmpty + $issue.assignee.login | Should -BeNullOrEmpty + $issue.assignees | Should -BeNullOrEmpty + $issue.milestone | Should -BeNullOrEmpty + $issue.labels | Should -BeNullOrEmpty + } + + Context 'Update issue' { + BeforeAll { + $params = @{ + 'Title' = '-new title-' + 'Body' = '-new body-' + 'Assignee' = $script:ownerName + 'Milestone' = $milestone.number + 'Label' = 'bug' + 'MediaType' = 'Raw' + } + + $updated = $issue | Set-GitHubIssue @params -PassThru } - $updated = $issue | Set-GitHubIssue @params -PassThru It 'Should have the expected property values' { $updated.id | Should -Be $issue.id $updated.number | Should -Be $issue.number @@ -437,117 +475,134 @@ try } } } +} + +Describe 'Locking and unlocking issues' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - Describe 'Locking and unlocking issues' { + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } + + Context 'Locking and unlocking an Issue with parameters' { BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title ([Guid]::NewGuid().Guid) } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + It 'Should be unlocked' { + $issue.locked | Should -BeFalse + $issue.active_lock_reason | Should -BeNullOrEmpty } - Context 'Locking and unlocking an Issue with parameters' { - $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title ([Guid]::NewGuid().Guid) - It 'Should be unlocked' { - $issue.locked | Should -BeFalse - $issue.active_lock_reason | Should -BeNullOrEmpty - } - + It 'Should be locked' { $reason = 'Resolved' Lock-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number -Reason $reason $updated = Get-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number - It 'Should be locked' { - $updated.id | Should -Be $issue.id - $updated.number | Should -Be $issue.number - $updated.locked | Should -BeTrue - $updated.active_lock_reason | Should -Be $reason - } + $updated.id | Should -Be $issue.id + $updated.number | Should -Be $issue.number + $updated.locked | Should -BeTrue + $updated.active_lock_reason | Should -Be $reason + } + It 'Should be unlocked again' { Unlock-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number $updated = Get-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number - It 'Should be unlocked again' { - $updated.id | Should -Be $issue.id - $updated.number | Should -Be $issue.number - $updated.locked | Should -BeFalse - $updated.active_lock_reason | Should -BeNullOrEmpty - } + $updated.id | Should -Be $issue.id + $updated.number | Should -Be $issue.number + $updated.locked | Should -BeFalse + $updated.active_lock_reason | Should -BeNullOrEmpty } + } - Context 'Locking and unlocking an Issue with the repo on the pipeline' { + Context 'Locking and unlocking an Issue with the repo on the pipeline' { + BeforeAll { $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) - It 'Should be unlocked' { - $issue.locked | Should -BeFalse - $issue.active_lock_reason | Should -BeNullOrEmpty - } + } + + It 'Should be unlocked' { + $issue.locked | Should -BeFalse + $issue.active_lock_reason | Should -BeNullOrEmpty + } + It 'Should be locked' { $reason = 'Resolved' $repo | Lock-GitHubIssue -Issue $issue.number -Reason $reason $updated = $repo | Get-GitHubIssue -Issue $issue.number - It 'Should be locked' { - $updated.id | Should -Be $issue.id - $updated.number | Should -Be $issue.number - $updated.locked | Should -BeTrue - $updated.active_lock_reason | Should -Be $reason - } + $updated.id | Should -Be $issue.id + $updated.number | Should -Be $issue.number + $updated.locked | Should -BeTrue + $updated.active_lock_reason | Should -Be $reason + } + It 'Should be unlocked again' { $repo | Unlock-GitHubIssue -Issue $issue.number $updated = $repo | Get-GitHubIssue -Issue $issue.number - It 'Should be unlocked again' { - $updated.id | Should -Be $issue.id - $updated.number | Should -Be $issue.number - $updated.locked | Should -BeFalse - $updated.active_lock_reason | Should -BeNullOrEmpty - } + $updated.id | Should -Be $issue.id + $updated.number | Should -Be $issue.number + $updated.locked | Should -BeFalse + $updated.active_lock_reason | Should -BeNullOrEmpty } + } - Context 'Locking and unlocking an Issue with the issue on the pipeline' { + Context 'Locking and unlocking an Issue with the issue on the pipeline' { + BeforeAll { $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title ([Guid]::NewGuid().Guid) - It 'Should be unlocked' { - $issue.locked | Should -BeFalse - $issue.active_lock_reason | Should -BeNullOrEmpty - } + } + It 'Should be unlocked' { + $issue.locked | Should -BeFalse + $issue.active_lock_reason | Should -BeNullOrEmpty + } + + It 'Should be locked' { $reason = 'Resolved' $issue | Lock-GitHubIssue -Reason $reason $updated = $issue | Get-GitHubIssue - It 'Should be locked' { - $updated.id | Should -Be $issue.id - $updated.number | Should -Be $issue.number - $updated.locked | Should -BeTrue - $updated.active_lock_reason | Should -Be $reason - } + $updated.id | Should -Be $issue.id + $updated.number | Should -Be $issue.number + $updated.locked | Should -BeTrue + $updated.active_lock_reason | Should -Be $reason + } + It 'Should be unlocked again' { $issue | Unlock-GitHubIssue $updated = $issue | Get-GitHubIssue - It 'Should be unlocked again' { - $updated.id | Should -Be $issue.id - $updated.number | Should -Be $issue.number - $updated.locked | Should -BeFalse - $updated.active_lock_reason | Should -BeNullOrEmpty - } + $updated.id | Should -Be $issue.id + $updated.number | Should -Be $issue.number + $updated.locked | Should -BeFalse + $updated.active_lock_reason | Should -BeNullOrEmpty } } +} + +Describe 'Issue Timeline' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - Describe 'Issue Timeline' { + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } + + Context 'Getting the Issue timeline with parameters' { BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title ([Guid]::NewGuid().Guid) + $timeline = @(Get-GitHubIssueTimeline -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number) } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + It 'Should have no events so far' { + $timeline.Count | Should -Be 0 } - Context 'Getting the Issue timeline with parameters' { - $issue = New-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Title ([Guid]::NewGuid().Guid) - $timeline = @(Get-GitHubIssueTimeline -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number) - It 'Should have no events so far' { - $timeline.Count | Should -Be 0 - } + Context 'Lock issue' { + BeforeAll { + Lock-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number - Lock-GitHubIssue -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number + $timeline = @(Get-GitHubIssueTimeline -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number) + } - $timeline = @(Get-GitHubIssueTimeline -OwnerName $script:OwnerName -RepositoryName $repo.name -Issue $issue.number) It 'Should have an event now' { $timeline.Count | Should -Be 1 $timeline[0].event | Should -Be 'locked' @@ -560,16 +615,24 @@ try $timeline[0].actor.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } + } - Context 'Getting the Issue timeline with the repo on the pipeline' { + Context 'Getting the Issue timeline with the repo on the pipeline' { + BeforeAll { $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) $timeline = @($repo | Get-GitHubIssueTimeline -Issue $issue.number) - It 'Should have no events so far' { - $timeline.Count | Should -Be 0 + } + + It 'Should have no events so far' { + $timeline.Count | Should -Be 0 + } + + Context 'Lock Issue' { + BeforeAll { + $repo | Lock-GitHubIssue -Issue $issue.number + $timeline = @($repo | Get-GitHubIssueTimeline -Issue $issue.number) } - $repo | Lock-GitHubIssue -Issue $issue.number - $timeline = @($repo | Get-GitHubIssueTimeline -Issue $issue.number) It 'Should have an event now' { $timeline.Count | Should -Be 1 $timeline[0].event | Should -Be 'locked' @@ -582,16 +645,24 @@ try $timeline[0].actor.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } + } - Context 'Getting the Issue timeline with the issue on the pipeline' { + Context 'Getting the Issue timeline with the issue on the pipeline' { + BeforeAll { $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) $timeline = @($issue | Get-GitHubIssueTimeline) - It 'Should have no events so far' { - $timeline.Count | Should -Be 0 + } + + It 'Should have no events so far' { + $timeline.Count | Should -Be 0 + } + + Context 'Lock Issue' { + BeforeAll { + $issue | Lock-GitHubIssue + $timeline = @($issue | Get-GitHubIssueTimeline) } - $issue | Lock-GitHubIssue - $timeline = @($issue | Get-GitHubIssueTimeline) It 'Should have an event now' { $timeline.Count | Should -Be 1 $timeline[0].event | Should -Be 'locked' @@ -606,8 +677,8 @@ try } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubLabels.tests.ps1 b/Tests/GitHubLabels.tests.ps1 index 86bc7c76..485fa4f4 100644 --- a/Tests/GitHubLabels.tests.ps1 +++ b/Tests/GitHubLabels.tests.ps1 @@ -8,16 +8,15 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ - $defaultLabels = @( + $defaultLabels = @( @{ 'name' = 'pri:lowest' 'color' = '4285F4' @@ -75,21 +74,26 @@ try 'color' = '145912' } ) +} + +Describe 'Getting labels from a repository' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + Initialize-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $defaultLabels + } + + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Describe 'Getting labels from a repository' { + Context 'Querying all labels' { BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - Initialize-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $defaultLabels + $labels = @(Get-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName) } - AfterAll { - $repo | Remove-GitHubRepository -Force - } Context 'When querying for all labels' { - $labels = @(Get-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName) - It 'Should return expected number of labels' { $labels.Count | Should -Be $defaultLabels.Count } @@ -104,470 +108,508 @@ try } } } + } - Context 'When querying for all labels (via repo on pipeline)' { + Context 'When querying for all labels (via repo on pipeline)' { + BeforeAll { $labels = @($repo | Get-GitHubLabel) + } - It 'Should return expected number of labels' { - $labels.Count | Should -Be $defaultLabels.Count - } + It 'Should return expected number of labels' { + $labels.Count | Should -Be $defaultLabels.Count + } - It 'Should have the expected type and additional properties' { - foreach ($label in $labels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $labels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } + } - Context 'When pipeline properties are disabled' { - BeforeAll { - Set-GitHubConfiguration -DisablePipelineSupport - $labels = @($repo | Get-GitHubLabel) - } + Context 'When pipeline properties are disabled' { + BeforeAll { + Set-GitHubConfiguration -DisablePipelineSupport + $labels = @($repo | Get-GitHubLabel) + } - AfterAll { - Set-GitHubConfiguration -DisablePipelineSupport:$false - } + AfterAll { + Set-GitHubConfiguration -DisablePipelineSupport:$false + } - It 'Should return expected number of labels' { - $labels.Count | Should -Be $defaultLabels.Count - } + It 'Should return expected number of labels' { + $labels.Count | Should -Be $defaultLabels.Count + } - It 'Should have the expected type and additional properties' { - foreach ($label in $labels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -BeNullOrEmpty - $label.LabelId | Should -BeNullOrEmpty - $label.LabelName | Should -BeNullOrEmpty - } + It 'Should have the expected type and additional properties' { + foreach ($label in $labels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -BeNullOrEmpty + $label.LabelId | Should -BeNullOrEmpty + $label.LabelName | Should -BeNullOrEmpty } } + } - Context 'When querying for a specific label' { + Context 'When querying for a specific label' { + BeforeAll { $labelName = 'bug' $label = Get-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $labelName + } - It 'Should return expected label' { - $label.name | Should -Be $labelName - } + It 'Should return expected label' { + $label.name | Should -Be $labelName + } - It 'Should have the expected type and additional properties' { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - Context 'When querying for a specific label (via repo on pipeline)' { + Context 'When querying for a specific label (via repo on pipeline)' { + BeforeAll { $labelName = 'bug' $label = $repo | Get-GitHubLabel -Label $labelName + } - It 'Should return expected label' { - $label.name | Should -Be $labelName - } + It 'Should return expected label' { + $label.name | Should -Be $labelName + } - It 'Should have the expected type and additional properties' { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - # TODO: This test has been disabled until we can figure out how to fix the parameter sets - # for Get-GitHubLabel pipelining to still support Label this way. - # - # Context 'When querying for a specific label (via Label on pipeline)' { - # $labelName = 'bug' - # $label = $labelName | Get-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName + # TODO: This test has been disabled until we can figure out how to fix the parameter sets + # for Get-GitHubLabel pipelining to still support Label this way. + # + # Context 'When querying for a specific label (via Label on pipeline)' { + # BeforeAll { + # $labelName = 'bug' + # $label = $labelName | Get-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName + # } + + # It 'Should return expected label' { + # $label.name | Should -Be $labelName + # } + + # It 'Should have the expected type and additional properties' { + # $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + # $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + # $label.LabelId | Should -Be $label.id + # $label.LabelName | Should -Be $label.name + # } + # } +} - # It 'Should return expected label' { - # $label.name | Should -Be $labelName - # } +Describe 'Creating a new label' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + } - # It 'Should have the expected type and additional properties' { - # $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - # $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - # $label.LabelId | Should -Be $label.id - # $label.LabelName | Should -Be $label.name - # } - # } + AfterAll { + $repo | Remove-GitHubRepository -Force } - Describe 'Creating a new label' { + Context 'On a repo with parameters' { BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - } - - AfterAll { - $repo | Remove-GitHubRepository -Force - } - - Context 'On a repo with parameters' { $labelName = [Guid]::NewGuid().Guid $color = 'AAAAAA' $label = New-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $labelName -Color $color + } - It 'New label should be created' { - $label.name | Should -Be $labelName - $label.color | Should -Be $color - } + It 'New label should be created' { + $label.name | Should -Be $labelName + $label.color | Should -Be $color + } - It 'Should have the expected type and additional properties' { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - Context 'On a repo with and color starts with a #' { + Context 'On a repo with and color starts with a #' { + BeforeAll { $labelName = [Guid]::NewGuid().Guid $color = '#AAAAAA' $label = New-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $labelName -Color $color + } - It 'New label should be created' { - $label.name | Should -Be $labelName - $label.color | Should -Be $color.Substring(1) - $label.description | Should -BeNullOrEmpty - } + It 'New label should be created' { + $label.name | Should -Be $labelName + $label.color | Should -Be $color.Substring(1) + $label.description | Should -BeNullOrEmpty + } - It 'Should have the expected type and additional properties' { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - Context 'On a repo with the repo on the pipeline' { + Context 'On a repo with the repo on the pipeline' { + BeforeAll { $labelName = [Guid]::NewGuid().Guid $color = 'BBBBBB' $description = 'test description' $label = $repo | New-GitHubLabel -Label $labelName -Color $color -Description $description + } - It 'New label should be created' { - $label.name | Should -Be $labelName - $label.color | Should -Be $color - $label.description | Should -Be $description - } + It 'New label should be created' { + $label.name | Should -Be $labelName + $label.color | Should -Be $color + $label.description | Should -Be $description + } - It 'Should have the expected type and additional properties' { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - Context 'On a repo with the name on the pipeline' { + Context 'On a repo with the name on the pipeline' { + BeforeAll { $labelName = [Guid]::NewGuid().Guid $color = 'CCCCCC' $label = $labelName | New-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Color $color + } - It 'New label should be created' { - $label.name | Should -Be $labelName - $label.color | Should -Be $color - } + It 'New label should be created' { + $label.name | Should -Be $labelName + $label.color | Should -Be $color + } - It 'Should have the expected type and additional properties' { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - Context 'On a repo with three names on the pipeline' { + Context 'On a repo with three names on the pipeline' { + BeforeAll { $labelNames = @(([Guid]::NewGuid().Guid), ([Guid]::NewGuid().Guid), ([Guid]::NewGuid().Guid)) $color = 'CCCCCC' $labels = @($labelNames | New-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Color $color) + } - It 'Has the right count of labels' { - $labels.Count | Should -Be $labelNames.Count - } + It 'Has the right count of labels' { + $labels.Count | Should -Be $labelNames.Count + } - It 'Has the right label details' { - foreach ($label in $labels) - { - $labelNames | Should -Contain $label.name - $label.color | Should -Be $color - } + It 'Has the right label details' { + foreach ($label in $labels) + { + $labelNames | Should -Contain $label.name + $label.color | Should -Be $color } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $labels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $labels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } } +} - Describe 'Removing a label' { - BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - } +Describe 'Removing a label' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'Removing a label with parameters' { + Context 'Removing a label with parameters' { + + It 'Should be gone after being removed by parameter' { $label = $repo | New-GitHubLabel -Label 'test' -Color 'CCCCCC' Remove-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $label.name -Force - - It 'Should be gone after being removed by parameter' { - { $label | Get-GitHubLabel } | Should -Throw - } + { $label | Get-GitHubLabel } | Should -Throw } + } - Context 'Removing a label with the repo on the pipeline' { + Context 'Removing a label with the repo on the pipeline' { + + It 'Should be gone after being removed by parameter' { $label = $repo | New-GitHubLabel -Label 'test' -Color 'CCCCCC' $repo | Remove-GitHubLabel -Label $label.name -Confirm:$false - - It 'Should be gone after being removed by parameter' { - { $label | Get-GitHubLabel } | Should -Throw - } + { $label | Get-GitHubLabel } | Should -Throw } + } - Context 'Removing a label with the name on the pipeline' { + Context 'Removing a label with the name on the pipeline' { + + It 'Should be gone after being removed by parameter' { $label = $repo | New-GitHubLabel -Label 'test' -Color 'CCCCCC' $label.name | Remove-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Force - - It 'Should be gone after being removed by parameter' { - { $label | Get-GitHubLabel } | Should -Throw - } + { $label | Get-GitHubLabel } | Should -Throw } + } - Context 'Removing a label with the label object on the pipeline' { + Context 'Removing a label with the label object on the pipeline' { + + It 'Should be gone after being removed by parameter' { $label = $repo | New-GitHubLabel -Label 'test' -Color 'CCCCCC' $label | Remove-GitHubLabel -Force - - It 'Should be gone after being removed by parameter' { - { $label | Get-GitHubLabel } | Should -Throw - } + { $label | Get-GitHubLabel } | Should -Throw } } +} - Describe 'Updating a label' { - BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - } +Describe 'Updating a label' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'Updating label color with parameters' { + Context 'Updating label color with parameters' { + BeforeAll { $label = $repo | New-GitHubLabel -Label ([Guid]::NewGuid().Guid) -Color 'BBBBBB' $newColor = 'AAAAAA' $result = Set-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $label.name -Color $newColor -PassThru + } - It 'Label should have different color' { - $result.name | Should -Be $label.name - $result.color | Should -Be $newColor - $result.description | Should -Be $label.description - } + It 'Label should have different color' { + $result.name | Should -Be $label.name + $result.color | Should -Be $newColor + $result.description | Should -Be $label.description + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.LabelId | Should -Be $result.id - $result.LabelName | Should -Be $result.name - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.LabelId | Should -Be $result.id + $result.LabelName | Should -Be $result.name } + } - Context 'Updating label color (with #) with parameters' { + Context 'Updating label color (with #) with parameters' { + BeforeAll { $label = $repo | New-GitHubLabel -Label ([Guid]::NewGuid().Guid) -Color 'BBBBBB' $newColor = '#AAAAAA' $result = Set-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $label.name -Color $newColor -PassThru + } - It 'Label should have different color' { - $result.name | Should -Be $label.name - $result.color | Should -Be $newColor.Substring(1) - $result.description | Should -Be $label.description - } + It 'Label should have different color' { + $result.name | Should -Be $label.name + $result.color | Should -Be $newColor.Substring(1) + $result.description | Should -Be $label.description + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.LabelId | Should -Be $result.id - $result.LabelName | Should -Be $result.name - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.LabelId | Should -Be $result.id + $result.LabelName | Should -Be $result.name } + } - Context 'Updating label name with parameters' { + Context 'Updating label name with parameters' { + BeforeAll { $label = $repo | New-GitHubLabel -Label ([Guid]::NewGuid().Guid) -Color 'BBBBBB' $newName = [Guid]::NewGuid().Guid $result = Set-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $label.name -NewName $newName -PassThru + } - It 'Label should have different name' { - $result.name | Should -Be $newName - $result.color | Should -Be $label.color - $result.description | Should -Be $label.description - } + It 'Label should have different name' { + $result.name | Should -Be $newName + $result.color | Should -Be $label.color + $result.description | Should -Be $label.description + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.LabelId | Should -Be $result.id - $result.LabelName | Should -Be $result.name - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.LabelId | Should -Be $result.id + $result.LabelName | Should -Be $result.name } + } - Context 'Updating label description with parameters' { + Context 'Updating label description with parameters' { + BeforeAll { $label = $repo | New-GitHubLabel -Label ([Guid]::NewGuid().Guid) -Color 'BBBBBB' -Description 'test description' $newDescription = [Guid]::NewGuid().Guid $result = Set-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $label.name -Description $newDescription -PassThru + } - It 'Label should have different name' { - $result.name | Should -Be $label.name - $result.color | Should -Be $label.color - $result.description | Should -Be $newDescription - } + It 'Label should have different name' { + $result.name | Should -Be $label.name + $result.color | Should -Be $label.color + $result.description | Should -Be $newDescription + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.LabelId | Should -Be $result.id - $result.LabelName | Should -Be $result.name - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.LabelId | Should -Be $result.id + $result.LabelName | Should -Be $result.name } + } - Context 'Updating label name, color and description with parameters' { + Context 'Updating label name, color and description with parameters' { + BeforeAll { $label = $repo | New-GitHubLabel -Label ([Guid]::NewGuid().Guid) -Color 'BBBBBB' -Description 'test description' $newName = [Guid]::NewGuid().Guid $newColor = 'AAAAAA' $newDescription = [Guid]::NewGuid().Guid $result = Set-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $label.name -NewName $newName -Color $newColor -Description $newDescription -PassThru + } - It 'Label should have different everything' { - $result.name | Should -Be $newName - $result.color | Should -Be $newColor - $result.description | Should -Be $newDescription - } + It 'Label should have different everything' { + $result.name | Should -Be $newName + $result.color | Should -Be $newColor + $result.description | Should -Be $newDescription + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.LabelId | Should -Be $result.id - $result.LabelName | Should -Be $result.name - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.LabelId | Should -Be $result.id + $result.LabelName | Should -Be $result.name + } - } + } - Context 'Updating label color with repo on the pipeline' { + Context 'Updating label color with repo on the pipeline' { + BeforeAll { $label = $repo | New-GitHubLabel -Label ([Guid]::NewGuid().Guid) -Color 'BBBBBB' $newColor = 'AAAAAA' $result = $repo | Set-GitHubLabel -Label $label.name -Color $newColor -PassThru + } - It 'Label should have different color' { - $result.name | Should -Be $label.name - $result.color | Should -Be $newColor - $result.description | Should -Be $label.description - } + It 'Label should have different color' { + $result.name | Should -Be $label.name + $result.color | Should -Be $newColor + $result.description | Should -Be $label.description + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.LabelId | Should -Be $result.id - $result.LabelName | Should -Be $result.name - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.LabelId | Should -Be $result.id + $result.LabelName | Should -Be $result.name } + } - Context 'Updating label name with the label on the pipeline' { + Context 'Updating label name with the label on the pipeline' { + BeforeAll { $label = $repo | New-GitHubLabel -Label ([Guid]::NewGuid().Guid) -Color 'BBBBBB' $newName = [Guid]::NewGuid().Guid $result = $label | Set-GitHubLabel -NewName $newName -PassThru + } - It 'Label should have different name' { - $result.name | Should -Be $newName - $result.color | Should -Be $label.color - $result.description | Should -Be $label.description - } + It 'Label should have different name' { + $result.name | Should -Be $newName + $result.color | Should -Be $label.color + $result.description | Should -Be $label.description + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.LabelId | Should -Be $result.id - $result.LabelName | Should -Be $result.name - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.LabelId | Should -Be $result.id + $result.LabelName | Should -Be $result.name } + } - Context 'Updating label name, color and description with the label on the pipeline' { + Context 'Updating label name, color and description with the label on the pipeline' { + BeforeAll { $label = $repo | New-GitHubLabel -Label ([Guid]::NewGuid().Guid) -Color 'BBBBBB' -Description 'test description' $newName = [Guid]::NewGuid().Guid $newColor = 'AAAAAA' $newDescription = [Guid]::NewGuid().Guid $result = $label | Set-GitHubLabel -NewName $newName -Color $newColor -Description $newDescription -PassThru + } - It 'Label should have different everything' { - $result.name | Should -Be $newName - $result.color | Should -Be $newColor - $result.description | Should -Be $newDescription - } + It 'Label should have different everything' { + $result.name | Should -Be $newName + $result.color | Should -Be $newColor + $result.description | Should -Be $newDescription + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.LabelId | Should -Be $result.id - $result.LabelName | Should -Be $result.name - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.LabelId | Should -Be $result.id + $result.LabelName | Should -Be $result.name } } +} - Describe 'Initializing the labels on a repository' { - BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - } +Describe 'Initializing the labels on a repository' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'Applying a default set of labels' { + Context 'Applying a default set of labels' { + BeforeAll { Initialize-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $defaultLabels $labels = @($repo | Get-GitHubLabel) + } - It 'Should return the expected number of labels' { - $labels.Count | Should -Be $defaultLabels.Count - } + It 'Should return the expected number of labels' { + $labels.Count | Should -Be $defaultLabels.Count + } - It 'Should have the right set of labels' { - foreach ($item in $defaultLabels) - { - $label = $labels | Where-Object { $_.name -eq $item.name } - $item.name | Should -Be $label.name - $item.color | Should -Be $label.color - } + It 'Should have the right set of labels' { + foreach ($item in $defaultLabels) + { + $label = $labels | Where-Object { $_.name -eq $item.name } + $item.name | Should -Be $label.name + $item.color | Should -Be $label.color } } + } - Context 'Applying an overlapping set of labels' { + Context 'Applying an overlapping set of labels' { + BeforeAll { $newLabels = @( @{ 'name' = $defaultLabels[0].name; 'color' = 'aaaaaa' }, @{ 'name' = $defaultLabels[1].name; 'color' = 'bbbbbb' } @@ -579,345 +621,356 @@ try $originalLabels = @($repo | Get-GitHubLabel) $null = $repo | Initialize-GitHubLabel -Label $newLabels $labels = @($repo | Get-GitHubLabel) + } - It 'Should return the expected number of labels' { - $labels.Count | Should -Be $newLabels.Count - } + It 'Should return the expected number of labels' { + $labels.Count | Should -Be $newLabels.Count + } - It 'Should have the right set of labels' { - foreach ($item in $newLabels) - { - $label = $labels | Where-Object { $_.name -eq $item.name } - $item.name | Should -Be $label.name - $item.color | Should -Be $label.color - } + It 'Should have the right set of labels' { + foreach ($item in $newLabels) + { + $label = $labels | Where-Object { $_.name -eq $item.name } + $item.name | Should -Be $label.name + $item.color | Should -Be $label.color } + } - It 'Should have retained the ID''s of the pre-existing labels' { - for ($i = 0; $i -le 2; $i++) - { - $originalLabel = $originalLabels | Where-Object { $_.name -eq $newLabels[$i].name } - $label = $labels | Where-Object { $_.name -eq $newLabels[$i].name } - $label.id | Should -Be $originalLabel.id - } + It 'Should have retained the ID''s of the pre-existing labels' { + for ($i = 0; $i -le 2; $i++) + { + $originalLabel = $originalLabels | Where-Object { $_.name -eq $newLabels[$i].name } + $label = $labels | Where-Object { $_.name -eq $newLabels[$i].name } + $label.id | Should -Be $originalLabel.id + } - for ($i = 3; $i -le 4; $i++) - { - $originalLabel = $originalLabels | Where-Object { $_.name -eq $newLabels[$i].name } - $label = $labels | Where-Object { $_.name -eq $newLabels[$i].name } - $originalLabel | Should -BeNullOrEmpty - $label | Should -Not -BeNullOrEmpty - } + for ($i = 3; $i -le 4; $i++) + { + $originalLabel = $originalLabels | Where-Object { $_.name -eq $newLabels[$i].name } + $label = $labels | Where-Object { $_.name -eq $newLabels[$i].name } + $originalLabel | Should -BeNullOrEmpty + $label | Should -Not -BeNullOrEmpty } } } +} - Describe 'Adding labels to an issue' { - BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - $repo | Initialize-GitHubLabel -Label $defaultLabels - } +Describe 'Adding labels to an issue' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + $repo | Initialize-GitHubLabel -Label $defaultLabels + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'Adding labels to an issue' { + Context 'Adding labels to an issue' { + BeforeAll { $expectedLabels = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[3].name) $issue = $repo | New-GitHubIssue -Title 'test issue' $result = @(Add-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue $issue.number -LabelName $expectedLabels -PassThru) + $issueLabels = Get-GitHubLabel -OwnerName $ownerName -RepositoryName $repositoryName -Issue $issue.number + } - It 'Should return the number of labels that were just added' { - $result.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added' { + $result.Count | Should -Be $expectedLabels.Count + } - It 'Should be the right set of labels' { - foreach ($label in $expectedLabels) - { - $result.name | Should -Contain $label - } + It 'Should be the right set of labels' { + foreach ($label in $expectedLabels) + { + $result.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - $issueLabels = Get-GitHubLabel -OwnerName $ownerName -RepositoryName $repositoryName -Issue $issue.number - - It 'Should return the number of labels that were just added from querying the issue again' { - $issueLabels.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added from querying the issue again' { + $issueLabels.Count | Should -Be $expectedLabels.Count + } - It 'Should have the expected type and additional properties' { - foreach ($label in $issueLabels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $issueLabels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } + } - Context 'Adding labels to an issue with the repo on the pipeline' { + Context 'Adding labels to an issue with the repo on the pipeline' { + BeforeAll { $expectedLabels = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[3].name) $issue = $repo | New-GitHubIssue -Title 'test issue' $result = @($repo | Add-GitHubIssueLabel -Issue $issue.number -LabelName $expectedLabels -PassThru) + $issueLabels = $repo | Get-GitHubLabel -Issue $issue.number + } - It 'Should return the number of labels that were just added' { - $result.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added' { + $result.Count | Should -Be $expectedLabels.Count + } - It 'Should be the right set of labels' { - foreach ($label in $expectedLabels) - { - $result.name | Should -Contain $label - } + It 'Should be the right set of labels' { + foreach ($label in $expectedLabels) + { + $result.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - $issueLabels = $repo | Get-GitHubLabel -Issue $issue.number - - It 'Should return the number of labels that were just added from querying the issue again' { - $issueLabels.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added from querying the issue again' { + $issueLabels.Count | Should -Be $expectedLabels.Count + } - It 'Should have the expected type and additional properties' { - foreach ($label in $issueLabels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $issueLabels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } + } - Context 'Adding labels to an issue with the issue on the pipeline' { + Context 'Adding labels to an issue with the issue on the pipeline' { + BeforeAll { $expectedLabels = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[3].name) $issue = $repo | New-GitHubIssue -Title 'test issue' $result = @($issue | Add-GitHubIssueLabel -LabelName $expectedLabels -PassThru) + $issueLabels = $issue | Get-GitHubLabel + } - It 'Should return the number of labels that were just added' { - $result.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added' { + $result.Count | Should -Be $expectedLabels.Count + } - It 'Should be the right set of labels' { - foreach ($label in $expectedLabels) - { - $result.name | Should -Contain $label - } + It 'Should be the right set of labels' { + foreach ($label in $expectedLabels) + { + $result.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - $issueLabels = $issue | Get-GitHubLabel - - It 'Should return the number of labels that were just added from querying the issue again' { - $issueLabels.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added from querying the issue again' { + $issueLabels.Count | Should -Be $expectedLabels.Count + } - It 'Should have the expected type and additional properties' { - foreach ($label in $issueLabels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $issueLabels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } + } - Context 'Adding labels to an issue with the label names on the pipeline' { + Context 'Adding labels to an issue with the label names on the pipeline' { + BeforeAll { $expectedLabels = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[3].name) $issue = $repo | New-GitHubIssue -Title 'test issue' $result = @($expectedLabels | Add-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue $issue.number -PassThru) + $issueLabels = $issue | Get-GitHubLabel + } - It 'Should return the number of labels that were just added' { - $result.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added' { + $result.Count | Should -Be $expectedLabels.Count + } - It 'Should be the right set of labels' { - foreach ($label in $expectedLabels) - { - $result.name | Should -Contain $label - } + It 'Should be the right set of labels' { + foreach ($label in $expectedLabels) + { + $result.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - $issueLabels = $issue | Get-GitHubLabel - - It 'Should return the number of labels that were just added from querying the issue again' { - $issueLabels.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added from querying the issue again' { + $issueLabels.Count | Should -Be $expectedLabels.Count + } - It 'Should have the expected type and additional properties' { - foreach ($label in $issueLabels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $issueLabels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } + } - Context 'Adding labels to an issue with the label object on the pipeline' { + Context 'Adding labels to an issue with the label object on the pipeline' { + BeforeAll { $expectedLabels = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[3].name) $issue = $repo | New-GitHubIssue -Title 'test issue' $labels = @($expectedLabels | ForEach-Object { Get-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $_ } ) $result = @($labels | Add-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue $issue.number -PassThru) + $issueLabels = $issue | Get-GitHubLabel + } - It 'Should return the number of labels that were just added' { - $result.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added' { + $result.Count | Should -Be $expectedLabels.Count + } - It 'Should be the right set of labels' { - foreach ($label in $expectedLabels) - { - $result.name | Should -Contain $label - } + It 'Should be the right set of labels' { + foreach ($label in $expectedLabels) + { + $result.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } - $issueLabels = $issue | Get-GitHubLabel - - It 'Should return the number of labels that were just added from querying the issue again' { - $issueLabels.Count | Should -Be $expectedLabels.Count - } + It 'Should return the number of labels that were just added from querying the issue again' { + $issueLabels.Count | Should -Be $expectedLabels.Count + } - It 'Should have the expected type and additional properties' { - foreach ($label in $issueLabels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $issueLabels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } } +} - Describe 'Creating a new Issue with labels' { - BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - $repo | Initialize-GitHubLabel -Label $defaultLabels - } +Describe 'Creating a new Issue with labels' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + $repo | Initialize-GitHubLabel -Label $defaultLabels + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'When creating a new issue using parameters' { + Context 'When creating a new issue using parameters' { + BeforeAll { $issueName = [Guid]::NewGuid().Guid $issueLabels = @($defaultLabels[0].name, $defaultLabels[1].name) $issue = New-GitHubIssue -OwnerName $script:ownerName -RepositoryName $repositoryName -Title $issueName -Label $issueLabels + } - It 'Should return the number of labels that were just added' { - $issue.labels.Count | Should -Be $issueLabels.Count - } + It 'Should return the number of labels that were just added' { + $issue.labels.Count | Should -Be $issueLabels.Count + } - It 'Should be the right set of labels' { - foreach ($label in $issueLabels) - { - $issue.labels.name | Should -Contain $label - } + It 'Should be the right set of labels' { + foreach ($label in $issueLabels) + { + $issue.labels.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $issue.labels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $issue.labels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } + } - Context 'When creating a new issue using the repo on the pipeline' { + Context 'When creating a new issue using the repo on the pipeline' { + BeforeAll { $issueName = [Guid]::NewGuid().Guid $issueLabels = @($defaultLabels[0].name, $defaultLabels[1].name) $issue = $repo | New-GitHubIssue -Title $issueName -Label $issueLabels + } - It 'Should return the number of labels that were just added' { - $issue.labels.Count | Should -Be $issueLabels.Count - } + It 'Should return the number of labels that were just added' { + $issue.labels.Count | Should -Be $issueLabels.Count + } - It 'Should be the right set of labels' { - foreach ($label in $issueLabels) - { - $issue.labels.name | Should -Contain $label - } + It 'Should be the right set of labels' { + foreach ($label in $issueLabels) + { + $issue.labels.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $issue.labels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $issue.labels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } } +} - Describe 'Removing labels on an issue' { - BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - $repo | Initialize-GitHubLabel -Label $defaultLabels - } +Describe 'Removing labels on an issue' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + $repo | Initialize-GitHubLabel -Label $defaultLabels + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'For removing an individual issue with parameters' { + Context 'For removing an individual issue with parameters' { + BeforeAll { $issueName = [Guid]::NewGuid().Guid $issue = $repo | New-GitHubIssue -Title $issueName @@ -925,22 +978,25 @@ try $issue | Add-GitHubIssueLabel -LabelName $labelsToAdd -PassThru $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have the expected number of labels' { - $issueLabels.Count | Should -Be $labelsToAdd.Count - } + } + + It 'Should have the expected number of labels' { + $issueLabels.Count | Should -Be $labelsToAdd.Count + } + It 'Should have removed all labels from the issue' { # Doing this manually instead of in a loop to try out different combinations of -Confirm:$false and -Force Remove-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $labelsToAdd[0] -Issue $issue.number -Confirm:$false Remove-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $labelsToAdd[1] -Issue $issue.number -Force Remove-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Label $labelsToAdd[2] -Issue $issue.number -Confirm:$false -Force $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have removed all labels from the issue' { - $issueLabels.Count | Should -Be 0 - } + $issueLabels.Count | Should -Be 0 } + } - Context 'For removing an individual issue using the repo on the pipeline' { + Context 'For removing an individual issue using the repo on the pipeline' { + BeforeAll { $issueName = [Guid]::NewGuid().Guid $issue = $repo | New-GitHubIssue -Title $issueName @@ -948,21 +1004,24 @@ try $issue | Add-GitHubIssueLabel -LabelName $labelsToAdd -PassThru $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have the expected number of labels' { - $issueLabels.Count | Should -Be $labelsToAdd.Count - } + } + + It 'Should have the expected number of labels' { + $issueLabels.Count | Should -Be $labelsToAdd.Count + } + It 'Should have removed the expected label from the issue' { $labelToRemove = $labelsToAdd[0] $repo | Remove-GitHubIssueLabel -Label $labelToRemove -Issue $issue.number -Confirm:$false $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have removed the expected label from the issue' { - $issueLabels.Count | Should -Be ($labelsToAdd.Count - 1) - $issueLabels.name | Should -Not -Contain $labelToRemove - } + $issueLabels.Count | Should -Be ($labelsToAdd.Count - 1) + $issueLabels.name | Should -Not -Contain $labelToRemove } + } - Context 'For removing an individual issue using the issue on the pipeline' { + Context 'For removing an individual issue using the issue on the pipeline' { + BeforeAll { $issueName = [Guid]::NewGuid().Guid $issue = $repo | New-GitHubIssue -Title $issueName @@ -970,46 +1029,50 @@ try $issue | Add-GitHubIssueLabel -LabelName $labelsToAdd -PassThru $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have the expected number of labels' { - $issueLabels.Count | Should -Be $labelsToAdd.Count - } + } + + It 'Should have the expected number of labels' { + $issueLabels.Count | Should -Be $labelsToAdd.Count + } + It 'Should have removed the expected label from the issue' { $labelToRemove = $labelsToAdd[1] $issue | Remove-GitHubIssueLabel -Label $labelToRemove -Confirm:$false $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have removed the expected label from the issue' { - $issueLabels.Count | Should -Be ($labelsToAdd.Count - 1) - $issueLabels.name | Should -Not -Contain $labelToRemove - } + $issueLabels.Count | Should -Be ($labelsToAdd.Count - 1) + $issueLabels.name | Should -Not -Contain $labelToRemove } + } - # TODO: This has been disabled for now, as ValueFromPipeline has been disabled until we - # sort out some complication issues with the ParameterSets - # - # Context 'For removing an individual issue using the label name on the pipeline' { - # $issueName = [Guid]::NewGuid().Guid - # $issue = $repo | New-GitHubIssue -Title $issueName - - # $labelsToAdd = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[2].name, $defaultLabels[3].name) - # $issue | Add-GitHubIssueLabel -LabelName $labelsToAdd -PassThru - - # $issueLabels = @($issue | Get-GitHubLabel) - # It 'Should have the expected number of labels' { - # $issueLabels.Count | Should -Be $labelsToAdd.Count - # } - - # $labelToRemove = $labelsToAdd[2] - # $labelToRemove | Remove-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue $issue.number -Confirm:$false - - # $issueLabels = @($issue | Get-GitHubLabel) - # It 'Should have removed the expected label from the issue' { - # $issueLabels.Count | Should -Be ($labelsToAdd.Count - 1) - # $issueLabels.name | Should -Not -Contain $labelToRemove - # } - # } - - Context 'For removing an individual issue using the label object on the pipeline' { + # TODO: This has been disabled for now, as ValueFromPipeline has been disabled until we + # sort out some complication issues with the ParameterSets + # + # Context 'For removing an individual issue using the label name on the pipeline' { + # BeforeAll { + # $issueName = [Guid]::NewGuid().Guid + # $issue = $repo | New-GitHubIssue -Title $issueName + + # $labelsToAdd = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[2].name, $defaultLabels[3].name) + # $issue | Add-GitHubIssueLabel -LabelName $labelsToAdd -PassThru + + # $issueLabels = @($issue | Get-GitHubLabel)} + # It 'Should have the expected number of labels' { + # $issueLabels.Count | Should -Be $labelsToAdd.Count + # } + + # It 'Should have removed the expected label from the issue' { + # $labelToRemove = $labelsToAdd[2] + # $labelToRemove | Remove-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue $issue.number -Confirm:$false + + # $issueLabels = @($issue | Get-GitHubLabel) + # $issueLabels.Count | Should -Be ($labelsToAdd.Count - 1) + # $issueLabels.name | Should -Not -Contain $labelToRemove + # } + # } + + Context 'For removing an individual issue using the label object on the pipeline' { + BeforeAll { $issueName = [Guid]::NewGuid().Guid $issue = $repo | New-GitHubIssue -Title $issueName @@ -1017,22 +1080,24 @@ try $issue | Add-GitHubIssueLabel -LabelName $labelsToAdd -PassThru $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have the expected number of labels' { - $issueLabels.Count | Should -Be $labelsToAdd.Count - } + } + It 'Should have the expected number of labels' { + $issueLabels.Count | Should -Be $labelsToAdd.Count + } + It 'Should have removed the expected label from the issue' { $labelToRemove = $labelsToAdd[0] $label = $repo | Get-GitHubLabel -Label $labelToRemove $label | Remove-GitHubIssueLabel -Issue $issue.number -Confirm:$false $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have removed the expected label from the issue' { - $issueLabels.Count | Should -Be ($labelsToAdd.Count - 1) - $issueLabels.name | Should -Not -Contain $labelToRemove - } + $issueLabels.Count | Should -Be ($labelsToAdd.Count - 1) + $issueLabels.name | Should -Not -Contain $labelToRemove } + } - Context 'For removing all issues' { + Context 'For removing all issues' { + BeforeAll { $issueName = [Guid]::NewGuid().Guid $issue = $repo | New-GitHubIssue -Title $issueName @@ -1040,19 +1105,22 @@ try $issue | Add-GitHubIssueLabel -LabelName $labelsToAdd -PassThru $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have the expected number of labels' { - $issueLabels.Count | Should -Be $labelsToAdd.Count - } + } + + It 'Should have the expected number of labels' { + $issueLabels.Count | Should -Be $labelsToAdd.Count + } + It 'Should have removed all labels from the issue' { $issue | Remove-GitHubIssueLabel -Confirm:$false $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have removed all labels from the issue' { - $issueLabels.Count | Should -Be 0 - } + $issueLabels.Count | Should -Be 0 } + } - Context 'For removing all issues using Set-GitHubIssueLabel with the Issue on the pipeline' { + Context 'For removing all issues using Set-GitHubIssueLabel with the Issue on the pipeline' { + BeforeAll { $issueName = [Guid]::NewGuid().Guid $issue = $repo | New-GitHubIssue -Title $issueName @@ -1060,283 +1128,294 @@ try $issue | Add-GitHubIssueLabel -LabelName $labelsToAdd -PassThru $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have the expected number of labels' { - $issueLabels.Count | Should -Be $labelsToAdd.Count - } + } + It 'Should have the expected number of labels' { + $issueLabels.Count | Should -Be $labelsToAdd.Count + } + It 'Should have removed all labels from the issue' { $issue | Set-GitHubIssueLabel -Confirm:$false $issueLabels = @($issue | Get-GitHubLabel) - It 'Should have removed all labels from the issue' { - $issueLabels.Count | Should -Be 0 - } + $issueLabels.Count | Should -Be 0 } } +} - Describe 'Replacing labels on an issue' { - BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - $repo | Initialize-GitHubLabel -Label $defaultLabels - } +Describe 'Replacing labels on an issue' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + $repo | Initialize-GitHubLabel -Label $defaultLabels + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'Change the set of labels with parameters' { + Context 'Change the set of labels with parameters' { + BeforeAll { $labelsToAdd = @($defaultLabels[0].name, $defaultLabels[1].name) $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) -Label $labelsToAdd + $newIssueLabels = @($defaultLabels[0].name, $defaultLabels[5].name) + $result = @(Set-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue $issue.number -Label $newIssueLabels -PassThru) + } - It 'Should have assigned the expected labels' { - $issue.labels.Count | Should -Be $labelsToAdd.Count - foreach ($label in $labelsToAdd) - { - $issue.labels.name | Should -Contain $label - } + It 'Should have assigned the expected labels' { + $issue.labels.Count | Should -Be $labelsToAdd.Count + foreach ($label in $labelsToAdd) + { + $issue.labels.name | Should -Contain $label } + } - $newIssueLabels = @($defaultLabels[0].name, $defaultLabels[5].name) - $result = @(Set-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue $issue.number -Label $newIssueLabels -PassThru) - It 'Should have the expected labels' { - $result.labels.Count | Should -Be $newIssueLabels.Count - foreach ($label in $newIssueLabels) - { - $result.name | Should -Contain $label - } + It 'Should have the expected labels' { + $result.labels.Count | Should -Be $newIssueLabels.Count + foreach ($label in $newIssueLabels) + { + $result.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } + } - Context 'Change the set of labels with the repo on the pipeline' { + Context 'Change the set of labels with the repo on the pipeline' { + BeforeAll { $labelsToAdd = @($defaultLabels[0].name, $defaultLabels[1].name) $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) -Label $labelsToAdd - - It 'Should have assigned the expected labels' { - $issue.labels.Count | Should -Be $labelsToAdd.Count - foreach ($label in $labelsToAdd) - { - $issue.labels.name | Should -Contain $label - } - } - $newIssueLabels = @($defaultLabels[0].name, $defaultLabels[5].name) $result = @($repo | Set-GitHubIssueLabel -Issue $issue.number -Label $newIssueLabels -PassThru) + } - It 'Should have the expected labels' { - $result.labels.Count | Should -Be $newIssueLabels.Count - foreach ($label in $newIssueLabels) - { - $result.name | Should -Contain $label - } + It 'Should have assigned the expected labels' { + $issue.labels.Count | Should -Be $labelsToAdd.Count + foreach ($label in $labelsToAdd) + { + $issue.labels.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected labels' { + $result.labels.Count | Should -Be $newIssueLabels.Count + foreach ($label in $newIssueLabels) + { + $result.name | Should -Contain $label + } + } + + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } + } - Context 'Change the set of labels with the issue on the pipeline' { + Context 'Change the set of labels with the issue on the pipeline' { + BeforeAll { $labelsToAdd = @($defaultLabels[0].name, $defaultLabels[1].name) $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) -Label $labelsToAdd - It 'Should have assigned the expected labels' { - $issue.labels.Count | Should -Be $labelsToAdd.Count - foreach ($label in $labelsToAdd) - { - $issue.labels.name | Should -Contain $label - } - } - $newIssueLabels = @($defaultLabels[0].name, $defaultLabels[5].name) $result = @($issue | Set-GitHubIssueLabel -Label $newIssueLabels -PassThru) + } - It 'Should have the expected labels' { - $result.labels.Count | Should -Be $newIssueLabels.Count - foreach ($label in $newIssueLabels) - { - $result.name | Should -Contain $label - } + It 'Should have assigned the expected labels' { + $issue.labels.Count | Should -Be $labelsToAdd.Count + foreach ($label in $labelsToAdd) + { + $issue.labels.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected labels' { + $result.labels.Count | Should -Be $newIssueLabels.Count + foreach ($label in $newIssueLabels) + { + $result.name | Should -Contain $label } } - Context 'Change the set of labels with parameters with the labels on the pipeline' { - $labelsToAdd = @($defaultLabels[0].name, $defaultLabels[1].name) - $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) -Label $labelsToAdd - - It 'Should have assigned the expected labels' { - $issue.labels.Count | Should -Be $labelsToAdd.Count - foreach ($label in $labelsToAdd) - { - $issue.labels.name | Should -Contain $label - } + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } + } + Context 'Change the set of labels with parameters with the labels on the pipeline' { + BeforeAll { + $labelsToAdd = @($defaultLabels[0].name, $defaultLabels[1].name) + $issue = $repo | New-GitHubIssue -Title ([Guid]::NewGuid().Guid) -Label $labelsToAdd $newIssueLabelNames = @($defaultLabels[0].name, $defaultLabels[5].name) $issueLabels = @($newIssueLabelNames | ForEach-Object { $repo | Get-GitHubLabel -Label $_ }) $result = @($issueLabels | Set-GitHubIssueLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Issue $issue.number -PassThru) + } - It 'Should have the expected labels' { - $result.labels.Count | Should -Be $newIssueLabelNames.Count - foreach ($label in $newIssueLabelNames) - { - $result.name | Should -Contain $label - } + It 'Should have assigned the expected labels' { + $issue.labels.Count | Should -Be $labelsToAdd.Count + foreach ($label in $labelsToAdd) + { + $issue.labels.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $result) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + + It 'Should have the expected labels' { + $result.labels.Count | Should -Be $newIssueLabelNames.Count + foreach ($label in $newIssueLabelNames) + { + $result.name | Should -Contain $label } } - } - Describe 'Labels and Milestones' { - BeforeAll { - $repositoryName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repositoryName - $repo | Initialize-GitHubLabel -Label $defaultLabels + It 'Should have the expected type and additional properties' { + foreach ($label in $result) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name + } + } + } +} - $milestone = $repo | New-GitHubMilestone -Title 'test milestone' +Describe 'Labels and Milestones' { + BeforeAll { + $repositoryName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repositoryName + $repo | Initialize-GitHubLabel -Label $defaultLabels - $issueLabels = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[3].name) - $issue = $milestone | New-GitHubIssue -Title 'test issue' -Label $issueLabels + $milestone = $repo | New-GitHubMilestone -Title 'test milestone' - $issueLabels2 = @($defaultLabels[4].name, $defaultLabels[5].name) - $issue2 = $milestone | New-GitHubIssue -Title 'test issue' -Label $issueLabels2 - } + $issueLabels = @($defaultLabels[0].name, $defaultLabels[1].name, $defaultLabels[3].name) + $issue = $milestone | New-GitHubIssue -Title 'test issue' -Label $issueLabels - AfterAll { - $repo | Remove-GitHubRepository -Force - } + $issueLabels2 = @($defaultLabels[4].name, $defaultLabels[5].name) + $issue2 = $milestone | New-GitHubIssue -Title 'test issue' -Label $issueLabels2 - Context 'Getting labels for issues in a milestone with parameters' { - It 'Should return the number of labels that were just added to the issue' { - $issue.labels.Count | Should -Be $issueLabels.Count - $issue2.labels.Count | Should -Be $issueLabels2.Count - } + $milestoneLabels = Get-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Milestone $milestone.number + } - $milestoneLabels = Get-GitHubLabel -OwnerName $script:ownerName -RepositoryName $repositoryName -Milestone $milestone.number + AfterAll { + $repo | Remove-GitHubRepository -Force + } - It 'Should return the same number of labels in the issue that were assigned to the milestone' { - $milestoneLabels.Count | Should -Be ($issue.labels.Count + $issue2.labels.Count) - } + Context 'Getting labels for issues in a milestone with parameters' { + It 'Should return the number of labels that were just added to the issue' { + $issue.labels.Count | Should -Be $issueLabels.Count + $issue2.labels.Count | Should -Be $issueLabels2.Count + } - It 'Should be the right set of labels' { - $allLabels = $issue.labels.name + $issue2.labels.name - foreach ($label in $allLabels) - { - $milestoneLabels.name | Should -Contain $label - } - } + It 'Should return the same number of labels in the issue that were assigned to the milestone' { + $milestoneLabels.Count | Should -Be ($issue.labels.Count + $issue2.labels.Count) + } - It 'Should have the expected type and additional properties' { - foreach ($label in $milestoneLabels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should be the right set of labels' { + $allLabels = $issue.labels.name + $issue2.labels.name + foreach ($label in $allLabels) + { + $milestoneLabels.name | Should -Contain $label } } - Context 'Getting labels for issues in a milestone with the repo on the pipeline' { - It 'Should return the number of labels that were just added to the issue' { - $issue.labels.Count | Should -Be $issueLabels.Count - $issue2.labels.Count | Should -Be $issueLabels2.Count + It 'Should have the expected type and additional properties' { + foreach ($label in $milestoneLabels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } + } + Context 'Getting labels for issues in a milestone with the repo on the pipeline' { + BeforeAll { $milestoneLabels = $repo | Get-GitHubLabel -Milestone $milestone.number + } - It 'Should return the same number of labels in the issues that were assigned to the milestone' { - $milestoneLabels.Count | Should -Be ($issue.labels.Count + $issue2.labels.Count) - } + It 'Should return the number of labels that were just added to the issue' { + $issue.labels.Count | Should -Be $issueLabels.Count + $issue2.labels.Count | Should -Be $issueLabels2.Count + } - It 'Should be the right set of labels' { - $allLabels = $issue.labels.name + $issue2.labels.name - foreach ($label in $allLabels) - { - $milestoneLabels.name | Should -Contain $label - } - } + It 'Should return the same number of labels in the issues that were assigned to the milestone' { + $milestoneLabels.Count | Should -Be ($issue.labels.Count + $issue2.labels.Count) + } - It 'Should have the expected type and additional properties' { - foreach ($label in $milestoneLabels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should be the right set of labels' { + $allLabels = $issue.labels.name + $issue2.labels.name + foreach ($label in $allLabels) + { + $milestoneLabels.name | Should -Contain $label } } - Context 'Getting labels for issues in a milestone on the pipeline' { - It 'Should return the number of labels that were just added to the issue' { - $issue.labels.Count | Should -Be $issueLabels.Count - $issue2.labels.Count | Should -Be $issueLabels2.Count + It 'Should have the expected type and additional properties' { + foreach ($label in $milestoneLabels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } + } + } + Context 'Getting labels for issues in a milestone on the pipeline' { + BeforeAll { $milestoneLabels = $milestone | Get-GitHubLabel + } - It 'Should return the same number of labels in the issue that is assigned to the milestone' { - $milestoneLabels.Count | Should -Be ($issue.labels.Count + $issue2.labels.Count) - } + It 'Should return the number of labels that were just added to the issue' { + $issue.labels.Count | Should -Be $issueLabels.Count + $issue2.labels.Count | Should -Be $issueLabels2.Count + } - It 'Should be the right set of labels' { - $allLabels = $issue.labels.name + $issue2.labels.name - foreach ($label in $allLabels) - { - $milestoneLabels.name | Should -Contain $label - } + It 'Should return the same number of labels in the issue that is assigned to the milestone' { + $milestoneLabels.Count | Should -Be ($issue.labels.Count + $issue2.labels.Count) + } + + It 'Should be the right set of labels' { + $allLabels = $issue.labels.name + $issue2.labels.name + foreach ($label in $allLabels) + { + $milestoneLabels.name | Should -Contain $label } + } - It 'Should have the expected type and additional properties' { - foreach ($label in $milestoneLabels) - { - $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $label.RepositoryUrl | Should -Be $repo.RepositoryUrl - $label.LabelId | Should -Be $label.id - $label.LabelName | Should -Be $label.name - } + It 'Should have the expected type and additional properties' { + foreach ($label in $milestoneLabels) + { + $label.PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $label.RepositoryUrl | Should -Be $repo.RepositoryUrl + $label.LabelId | Should -Be $label.id + $label.LabelName | Should -Be $label.name } } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubMilestones.tests.ps1 b/Tests/GitHubMilestones.tests.ps1 index cf3a5b33..786272c7 100644 --- a/Tests/GitHubMilestones.tests.ps1 +++ b/Tests/GitHubMilestones.tests.ps1 @@ -8,232 +8,236 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readonly, hidden variables. @{ defaultMilestoneDueOn = (Get-Date).AddYears(1).ToUniversalTime() }.GetEnumerator() | ForEach-Object { Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value } +} +Describe 'Creating a milestone' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + + $commonParams = @{ + 'State' = 'Closed' + 'DueOn' = $script:defaultMilestoneDueOn + 'Description' = 'Milestone description' + } - Describe 'Creating a milestone' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $title = 'Milestone title' + } - $commonParams = @{ - 'State' = 'Closed' - 'DueOn' = $script:defaultMilestoneDueOn - 'Description' = 'Milestone description' - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - $title = 'Milestone title' + Context 'Using the parameter' { + BeforeAll { + $milestone = New-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name -Title $title @commonParams } AfterAll { - $repo | Remove-GitHubRepository -Force + $milestone | Remove-GitHubMilestone -Force } - Context 'Using the parameter' { - BeforeAll { - $milestone = New-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name -Title $title @commonParams - } - - AfterAll { - $milestone | Remove-GitHubMilestone -Force - } - + It 'Should exist' { $returned = Get-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name -Milestone $milestone.MilestoneNumber - It 'Should exist' { - $returned.id | Should -Be $milestone.id - } + $returned.id | Should -Be $milestone.id + } - It 'Should have the correct creation properties' { - $milestone.title | Should -Be $title - $milestone.state | Should -Be $commonParams['State'] - $milestone.description | Should -Be $commonParams['Description'] + It 'Should have the correct creation properties' { + $milestone.title | Should -Be $title + $milestone.state | Should -Be $commonParams['State'] + $milestone.description | Should -Be $commonParams['Description'] - # GitHub drops the time that is attached to 'due_on', so it's only relevant - # to compare the dates against each other. + # GitHub drops the time that is attached to 'due_on', so it's only relevant + # to compare the dates against each other. (Get-Date -Date $milestone.due_on).Date | Should -Be $commonParams['DueOn'].Date - } + } - It 'Should have the expected type and additional properties' { - $milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' - $milestone.RepositoryUrl | Should -Be $repo.RepositoryUrl - $milestone.MilestoneId | Should -Be $milestone.id - $milestone.MilestoneNumber | Should -Be $milestone.number - $milestone.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' + $milestone.RepositoryUrl | Should -Be $repo.RepositoryUrl + $milestone.MilestoneId | Should -Be $milestone.id + $milestone.MilestoneNumber | Should -Be $milestone.number + $milestone.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Using the pipeline for the repo' { - BeforeAll { - $milestone = $repo | New-GitHubMilestone -Title $title @commonParams - } + Context 'Using the pipeline for the repo' { + BeforeAll { + $milestone = $repo | New-GitHubMilestone -Title $title @commonParams + } - AfterAll { - $milestone | Remove-GitHubMilestone -Force - } + AfterAll { + $milestone | Remove-GitHubMilestone -Force + } + It 'Should exist' { $returned = $milestone | Get-GitHubMilestone - It 'Should exist' { - $returned.id | Should -Be $milestone.id - } + $returned.id | Should -Be $milestone.id + } - It 'Should have the correct creation properties' { - $milestone.title | Should -Be $title - $milestone.state | Should -Be $commonParams['State'] - $milestone.description | Should -Be $commonParams['Description'] + It 'Should have the correct creation properties' { + $milestone.title | Should -Be $title + $milestone.state | Should -Be $commonParams['State'] + $milestone.description | Should -Be $commonParams['Description'] - # GitHub drops the time that is attached to 'due_on', so it's only relevant - # to compare the dates against each other. + # GitHub drops the time that is attached to 'due_on', so it's only relevant + # to compare the dates against each other. (Get-Date -Date $milestone.due_on).Date | Should -Be $commonParams['DueOn'].Date - } + } - It 'Should have the expected type and additional properties' { - $milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' - $milestone.RepositoryUrl | Should -Be $repo.RepositoryUrl - $milestone.MilestoneId | Should -Be $milestone.id - $milestone.MilestoneNumber | Should -Be $milestone.number - $milestone.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' + $milestone.RepositoryUrl | Should -Be $repo.RepositoryUrl + $milestone.MilestoneId | Should -Be $milestone.id + $milestone.MilestoneNumber | Should -Be $milestone.number + $milestone.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Using the pipeline for the title' { - BeforeAll { - $milestone = $title | New-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name @commonParams - } + Context 'Using the pipeline for the title' { + BeforeAll { + $milestone = $title | New-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name @commonParams + } - AfterAll { - $milestone | Remove-GitHubMilestone -Force - } + AfterAll { + $milestone | Remove-GitHubMilestone -Force + } + It 'Should exist' { $returned = $repo | Get-GitHubMilestone -Milestone $milestone.MilestoneNumber - It 'Should exist' { - $returned.id | Should -Be $milestone.id - } + $returned.id | Should -Be $milestone.id + } - It 'Should have the correct creation properties' { - $milestone.title | Should -Be $title - $milestone.state | Should -Be $commonParams['State'] - $milestone.description | Should -Be $commonParams['Description'] + It 'Should have the correct creation properties' { + $milestone.title | Should -Be $title + $milestone.state | Should -Be $commonParams['State'] + $milestone.description | Should -Be $commonParams['Description'] - # GitHub drops the time that is attached to 'due_on', so it's only relevant - # to compare the dates against each other. + # GitHub drops the time that is attached to 'due_on', so it's only relevant + # to compare the dates against each other. (Get-Date -Date $milestone.due_on).Date | Should -Be $commonParams['DueOn'].Date - } + } - It 'Should have the expected type and additional properties' { - $milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' - $milestone.RepositoryUrl | Should -Be $repo.RepositoryUrl - $milestone.MilestoneId | Should -Be $milestone.id - $milestone.MilestoneNumber | Should -Be $milestone.number - $milestone.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $milestone.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' + $milestone.RepositoryUrl | Should -Be $repo.RepositoryUrl + $milestone.MilestoneId | Should -Be $milestone.id + $milestone.MilestoneNumber | Should -Be $milestone.number + $milestone.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'That is due at different times of the day' { + Context 'That is due at different times of the day' { + BeforeAll { # We'll be testing to make sure that regardless of the time in the timestamp, we'll get the desired date. $title = 'Milestone title' + } - It "Should have the expected due_on date even if early morning" { - $milestone = $repo | New-GitHubMilestone -Title 'Due early in the morning' -State "Closed" -DueOn $defaultMilestoneDueOn.date.AddHours(1) + It "Should have the expected due_on date even if early morning" { + $milestone = $repo | New-GitHubMilestone -Title 'Due early in the morning' -State "Closed" -DueOn $defaultMilestoneDueOn.date.AddHours(1) - # GitHub drops the time that is attached to 'due_on', so it's only relevant - # to compare the dates against each other. + # GitHub drops the time that is attached to 'due_on', so it's only relevant + # to compare the dates against each other. (Get-Date -Date $milestone.due_on).Date | Should -Be $defaultMilestoneDueOn.Date - } + } - It "Should have the expected due_on date even if late evening" { - $milestone = $repo | New-GitHubMilestone -Title 'Due late in the evening' -State "Closed" -DueOn $defaultMilestoneDueOn.date.AddHours(23) + It "Should have the expected due_on date even if late evening" { + $milestone = $repo | New-GitHubMilestone -Title 'Due late in the evening' -State "Closed" -DueOn $defaultMilestoneDueOn.date.AddHours(23) - # GitHub drops the time that is attached to 'due_on', so it's only relevant - # to compare the dates against each other. + # GitHub drops the time that is attached to 'due_on', so it's only relevant + # to compare the dates against each other. (Get-Date -Date $milestone.due_on).Date | Should -Be $defaultMilestoneDueOn.Date - } } } +} - Describe 'Associating milestones with issues' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $milestone = $repo | New-GitHubMilestone -Title 'Milestone Title' - $issue = $repo | New-GitHubIssue -Title 'Issue Title' - } +Describe 'Associating milestones with issues' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $milestone = $repo | New-GitHubMilestone -Title 'Milestone Title' + $issue = $repo | New-GitHubIssue -Title 'Issue Title' + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'Adding milestone to an issue' { - It 'Should not have any open issues associated with it' { - $issue.milestone | Should -BeNullOrEmpty - $milestone.open_issues | Should -Be 0 - } + Context 'Adding milestone to an issue' { + It 'Should not have any open issues associated with it' { + $issue.milestone | Should -BeNullOrEmpty + $milestone.open_issues | Should -Be 0 + } + It "Should be associated to the milestone now" { $issue = $issue | Set-GitHubIssue -Milestone $milestone.MilestoneNumber -PassThru $milestone = $milestone | Get-GitHubMilestone - It "Should be associated to the milestone now" { - $issue.milestone.number | Should -Be $milestone.MilestoneNumber - $milestone.open_issues | Should -Be 1 - } + $issue.milestone.number | Should -Be $milestone.MilestoneNumber + $milestone.open_issues | Should -Be 1 + } + It 'Should no longer be associated to the milestone' { $issue = $issue | Set-GitHubIssue -Milestone 0 -PassThru $milestone = $milestone | Get-GitHubMilestone - It 'Should no longer be associated to the milestone' { - $issue.milestone | Should -BeNullOrEmpty - $milestone.open_issues | Should -Be 0 - } + $issue.milestone | Should -BeNullOrEmpty + $milestone.open_issues | Should -Be 0 + } + It "Should be associated to the milestone again" { $issue = $issue | Set-GitHubIssue -Milestone $milestone.MilestoneNumber -PassThru $milestone = $milestone | Get-GitHubMilestone - It "Should be associated to the milestone again" { - $issue.milestone.number | Should -Be $milestone.MilestoneNumber - $milestone.open_issues | Should -Be 1 - } + $issue.milestone.number | Should -Be $milestone.MilestoneNumber + $milestone.open_issues | Should -Be 1 + } + It 'Should have removed the association when the milestone was deleted' { $milestone | Remove-GitHubMilestone -Force $issue = Get-GitHubIssue -Uri $repo.svn_url -Issue $issue.number - It 'Should have removed the association when the milestone was deleted' { - $issue.milestone | Should -BeNullOrEmpty - } + $issue.milestone | Should -BeNullOrEmpty } } +} + +Describe 'Getting milestones' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $title = 'Milestone title' + } - Describe 'Getting milestones' { + AfterAll { + $repo | Remove-GitHubRepository -Force + } + + Context 'Getting a specific milestone' { BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $title = 'Milestone title' + $closedMilestone = 'C' | New-GitHubMilestone -Uri $repo.RepositoryUrl -State 'Closed' + $openMilestone = 'O' | New-GitHubMilestone -Uri $repo.RepositoryUrl -State 'Open' } AfterAll { - $repo | Remove-GitHubRepository -Force + $closedMilestone | Remove-GitHubMilestone -Force + $openMilestone | Remove-GitHubMilestone -Force } - Context 'Getting a specific milestone' { + Context 'By parameter' { BeforeAll { - $closedMilestone = 'C' | New-GitHubMilestone -Uri $repo.RepositoryUrl -State 'Closed' - $openMilestone = 'O' | New-GitHubMilestone -Uri $repo.RepositoryUrl -State 'Open' + $milestone = $closedMilestone + $returned = Get-GitHubMilestone -Uri $repo.RepositoryUrl -Milestone $milestone.MilestoneNumber } - - AfterAll { - $closedMilestone | Remove-GitHubMilestone -Force - $openMilestone | Remove-GitHubMilestone -Force - } - - $milestone = $closedMilestone - $returned = Get-GitHubMilestone -Uri $repo.RepositoryUrl -Milestone $milestone.MilestoneNumber It 'Should get the right milestone as a parameter' { $returned.MilestoneId | Should -Be $milestone.MilestoneId } @@ -245,9 +249,14 @@ try $returned.MilestoneNumber | Should -Be $returned.number $returned.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + + Context 'By pipeline' { + BeforeAll { + $milestone = $openMilestone + $returned = $openMilestone | Get-GitHubMilestone + } - $milestone = $openMilestone - $returned = $openMilestone | Get-GitHubMilestone It 'Should get the right milestone via the pipeline' { $returned.MilestoneId | Should -Be $milestone.MilestoneId } @@ -260,164 +269,164 @@ try $returned.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } + } - Context 'Getting multiple milestones' { - BeforeAll { - $today = (Get-Date).ToUniversalTime() - $nextWeek = (Get-Date).AddDays(7).ToUniversalTime() - $numClosedMilestones = 3 - $numOpenMilestones = 4 - $closed = 1..$numClosedMilestones | ForEach-Object { $repo | New-GitHubMilestone -Title "Closed $_" -State 'Closed' -DueOn $today } - $open = 1..$numOpenMilestones | ForEach-Object { $repo | New-GitHubMilestone -Title "Open $_" -State 'Open' -DueOn $nextWeek } - } + Context 'Getting multiple milestones' { + BeforeAll { + $today = (Get-Date).ToUniversalTime() + $nextWeek = (Get-Date).AddDays(7).ToUniversalTime() + $numClosedMilestones = 3 + $numOpenMilestones = 4 + $closed = 1..$numClosedMilestones | ForEach-Object { $repo | New-GitHubMilestone -Title "Closed $_" -State 'Closed' -DueOn $today } + $open = 1..$numOpenMilestones | ForEach-Object { $repo | New-GitHubMilestone -Title "Open $_" -State 'Open' -DueOn $nextWeek } + } - AfterAll { - $closed | Remove-GitHubMilestone -Force - $open | Remove-GitHubMilestone -Force - } + AfterAll { + $closed | Remove-GitHubMilestone -Force + $open | Remove-GitHubMilestone -Force + } - It 'Should have the expected number of milestones' { - $milestones = @(Get-GitHubMilestone -Uri $repo.RepositoryUrl -State 'All') - $milestones.Count | Should -Be ($numClosedMilestones + $numOpenMilestones) - } + It 'Should have the expected number of milestones' { + $milestones = @(Get-GitHubMilestone -Uri $repo.RepositoryUrl -State 'All') + $milestones.Count | Should -Be ($numClosedMilestones + $numOpenMilestones) + } - It 'Should have the expected number of open milestones' { - $milestones = @($repo | Get-GitHubMilestone -State 'Open') - $milestones.Count | Should -Be $numOpenMilestones - } + It 'Should have the expected number of open milestones' { + $milestones = @($repo | Get-GitHubMilestone -State 'Open') + $milestones.Count | Should -Be $numOpenMilestones + } - It 'Should have the expected number of closed milestones' { - $milestones = @(Get-GitHubMilestone -Uri $repo.RepositoryUrl -State 'Closed') - $milestones.Count | Should -Be $numClosedMilestones - } + It 'Should have the expected number of closed milestones' { + $milestones = @(Get-GitHubMilestone -Uri $repo.RepositoryUrl -State 'Closed') + $milestones.Count | Should -Be $numClosedMilestones + } - It 'Should sort them the right way | DueOn, Descending' { - $milestones = @(Get-GitHubMilestone -Uri $repo.RepositoryUrl -State 'All' -Sort 'DueOn' -Direction 'Descending') - $milestones[0].state | Should -Be 'Open' - } + It 'Should sort them the right way | DueOn, Descending' { + $milestones = @(Get-GitHubMilestone -Uri $repo.RepositoryUrl -State 'All' -Sort 'DueOn' -Direction 'Descending') + $milestones[0].state | Should -Be 'Open' + } - It 'Should sort them the right way | DueOn, Ascending' { - $milestones = @(Get-GitHubMilestone -Uri $repo.RepositoryUrl -State 'All' -Sort 'DueOn' -Direction 'Ascending') - $milestones[0].state | Should -Be 'Closed' - } + It 'Should sort them the right way | DueOn, Ascending' { + $milestones = @(Get-GitHubMilestone -Uri $repo.RepositoryUrl -State 'All' -Sort 'DueOn' -Direction 'Ascending') + $milestones[0].state | Should -Be 'Closed' } } +} - Describe 'Editing a milestone' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit +Describe 'Editing a milestone' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $createParams = @{ - 'Title' = 'Created Title' - 'State' = 'Open' - 'Description' = 'Created Description' - 'DueOn' = (Get-Date).ToUniversalTime() - } - - $editParams = @{ - 'Title' = 'Edited Title' - 'State' = 'Closed' - 'Description' = 'Edited Description' - 'DueOn' = (Get-Date).AddDays(7).ToUniversalTime() - 'PassThru' = $true - } + $createParams = @{ + 'Title' = 'Created Title' + 'State' = 'Open' + 'Description' = 'Created Description' + 'DueOn' = (Get-Date).ToUniversalTime() } - AfterAll { - $repo | Remove-GitHubRepository -Force + $editParams = @{ + 'Title' = 'Edited Title' + 'State' = 'Closed' + 'Description' = 'Edited Description' + 'DueOn' = (Get-Date).AddDays(7).ToUniversalTime() + 'PassThru' = $true } + } - Context 'Using the parameter' { - BeforeAll { - $milestone = New-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name @createParams - $edited = Set-GitHubMilestone -Uri $milestone.RepositoryUrl -Milestone $milestone.MilestoneNumber @editParams - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - AfterAll { - $milestone | Remove-GitHubMilestone -Force - } + Context 'Using the parameter' { + BeforeAll { + $milestone = New-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name @createParams + $edited = Set-GitHubMilestone -Uri $milestone.RepositoryUrl -Milestone $milestone.MilestoneNumber @editParams + } - It 'Should be editable via the parameter' { - $edited.id | Should -Be $milestone.id - $edited.title | Should -Be $editParams['Title'] - $edited.state | Should -Be $editParams['State'] - $edited.description | Should -Be $editParams['Description'] + AfterAll { + $milestone | Remove-GitHubMilestone -Force + } - # GitHub drops the time that is attached to 'due_on', so it's only relevant - # to compare the dates against each other. + It 'Should be editable via the parameter' { + $edited.id | Should -Be $milestone.id + $edited.title | Should -Be $editParams['Title'] + $edited.state | Should -Be $editParams['State'] + $edited.description | Should -Be $editParams['Description'] + + # GitHub drops the time that is attached to 'due_on', so it's only relevant + # to compare the dates against each other. (Get-Date -Date $edited.due_on).Date | Should -Be $editParams['DueOn'].Date - } + } - It 'Should have the expected type and additional properties' { - $edited.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' - $edited.RepositoryUrl | Should -Be $repo.RepositoryUrl - $edited.MilestoneId | Should -Be $milestone.id - $edited.MilestoneNumber | Should -Be $milestone.number - $edited.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $edited.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' + $edited.RepositoryUrl | Should -Be $repo.RepositoryUrl + $edited.MilestoneId | Should -Be $milestone.id + $edited.MilestoneNumber | Should -Be $milestone.number + $edited.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Using the pipeline' { - BeforeAll { - $milestone = New-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name @createParams - $edited = $milestone | Set-GitHubMilestone @editParams - } + Context 'Using the pipeline' { + BeforeAll { + $milestone = New-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name @createParams + $edited = $milestone | Set-GitHubMilestone @editParams + } - AfterAll { - $milestone | Remove-GitHubMilestone -Force - } + AfterAll { + $milestone | Remove-GitHubMilestone -Force + } - It 'Should be editable via the pipeline' { - $edited.id | Should -Be $milestone.id - $edited.title | Should -Be $editParams['Title'] - $edited.state | Should -Be $editParams['State'] - $edited.description | Should -Be $editParams['Description'] + It 'Should be editable via the pipeline' { + $edited.id | Should -Be $milestone.id + $edited.title | Should -Be $editParams['Title'] + $edited.state | Should -Be $editParams['State'] + $edited.description | Should -Be $editParams['Description'] - # GitHub drops the time that is attached to 'due_on', so it's only relevant - # to compare the dates against each other. + # GitHub drops the time that is attached to 'due_on', so it's only relevant + # to compare the dates against each other. (Get-Date -Date $edited.due_on).Date | Should -Be $editParams['DueOn'].Date - } + } - It 'Should have the expected type and additional properties' { - $edited.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' - $edited.RepositoryUrl | Should -Be $repo.RepositoryUrl - $edited.MilestoneId | Should -Be $milestone.id - $edited.MilestoneNumber | Should -Be $milestone.number - $edited.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $edited.PSObject.TypeNames[0] | Should -Be 'GitHub.Milestone' + $edited.RepositoryUrl | Should -Be $repo.RepositoryUrl + $edited.MilestoneId | Should -Be $milestone.id + $edited.MilestoneNumber | Should -Be $milestone.number + $edited.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } +} - Describe 'Deleting a milestone' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - } +Describe 'Deleting a milestone' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'Using the parameter' { + Context 'Using the parameter' { + It 'Should be deleted' { $milestone = $repo | New-GitHubMilestone -Title 'Milestone title' -State "Closed" -DueOn $defaultMilestoneDueOn Remove-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name -Milestone $milestone.MilestoneNumber -Force - It 'Should be deleted' { - { Get-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name -Milestone $milestone.MilestoneNumber } | Should -Throw - } + { Get-GitHubMilestone -OwnerName $repo.owner.login -RepositoryName $repo.name -Milestone $milestone.MilestoneNumber } | Should -Throw } + } - Context 'Using the pipeline' { + Context 'Using the pipeline' { + It 'Should be deleted' { $milestone = $repo | New-GitHubMilestone -Title 'Milestone title' -State "Closed" -DueOn $defaultMilestoneDueOn $milestone | Remove-GitHubMilestone -Force - It 'Should be deleted' { - { $milestone | Get-GitHubMilestone } | Should -Throw - } + { $milestone | Get-GitHubMilestone } | Should -Throw } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubMiscellaneous.tests.ps1 b/Tests/GitHubMiscellaneous.tests.ps1 index 9d9e64dd..e8b97e58 100644 --- a/Tests/GitHubMiscellaneous.tests.ps1 +++ b/Tests/GitHubMiscellaneous.tests.ps1 @@ -8,7 +8,7 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() Describe 'Get-GitHubRateLimit' { @@ -208,46 +208,6 @@ Describe 'Get-GitHubCodeOfConduct' { $script:originalConfigFile = $null } - Context 'Can get the code of conduct for a repo with parameters' { - BeforeAll { - $result = Get-GitHubCodeOfConduct -OwnerName 'PowerShell' -RepositoryName 'PowerShell' - } - - It 'Has the expected result' { - $result.key | Should -Be 'other' - } - - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.CodeOfConduct' - $result.CodeOfConductKey | Should -Be $result.key - } - } - - Context 'Will fail if not provided both OwnerName and RepositoryName' { - It 'Should fail if only OwnerName is specified' { - { Get-GitHubCodeOfConduct -OwnerName 'PowerShell' } | Should -Throw - } - - It 'Should fail if only RepositoryName is specified' { - { Get-GitHubCodeOfConduct -RepositoryName 'PowerShell' } | Should -Throw - } - } - - Context 'Can get the code of conduct for a repo with the repo on the pipeline' { - BeforeAll { - $result = Get-GitHubRepository -OwnerName 'PowerShell' -RepositoryName 'PowerShell' | Get-GitHubCodeOfConduct - } - - It 'Has the expected result' { - $result.key | Should -Be 'other' - } - - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.CodeOfConduct' - $result.CodeOfConductKey | Should -Be $result.key - } - } - Context 'Can get all of the codes of conduct' { BeforeAll { $results = @(Get-GitHubCodeOfConduct) diff --git a/Tests/GitHubOrganizations.tests.ps1 b/Tests/GitHubOrganizations.tests.ps1 index 42bc547b..f9254483 100644 --- a/Tests/GitHubOrganizations.tests.ps1 +++ b/Tests/GitHubOrganizations.tests.ps1 @@ -8,47 +8,46 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} -try -{ - # TODO once more capabilities exist in the module's API set +# TODO once more capabilities exist in the module's API set - # TODO: Re-enable these tests once the module has sufficient support getting the Organization - # and repository into the required state for testing, and to recover back to the original state - # at the conclusion of the test. +# TODO: Re-enable these tests once the module has sufficient support getting the Organization +# and repository into the required state for testing, and to recover back to the original state +# at the conclusion of the test. - # Describe 'Obtaining organization members' { - # $members = Get-GitHubOrganizationMember -OrganizationName $script:organizationName +# Describe 'Obtaining organization members' { +# $members = Get-GitHubOrganizationMember -OrganizationName $script:organizationName - # It 'Should return expected number of organization members' { - # @($members).Count | Should -Be 1 - # } - # } +# It 'Should return expected number of organization members' { +# @($members).Count | Should -Be 1 +# } +# } - # Describe 'Obtaining organization teams' { - # $teams = Get-GitHubTeam -OrganizationName $script:organizationName +# Describe 'Obtaining organization teams' { +# $teams = Get-GitHubTeam -OrganizationName $script:organizationName - # It 'Should return expected number of organization teams' { - # @($teams).Count | Should -Be 2 - # } - # } +# It 'Should return expected number of organization teams' { +# @($teams).Count | Should -Be 2 +# } +# } - # Describe 'Obtaining organization team members' { - # $members = Get-GitHubTeamMember -OrganizationName $script:organizationName -TeamName $script:organizationTeamName +# Describe 'Obtaining organization team members' { +# $members = Get-GitHubTeamMember -OrganizationName $script:organizationName -TeamName $script:organizationTeamName - # It 'Should return expected number of organization team members' { - # @($members).Count | Should -Be 1 - # } - # } -} -finally -{ +# It 'Should return expected number of organization team members' { +# @($members).Count | Should -Be 1 +# } +# } + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubProjectCards.tests.ps1 b/Tests/GitHubProjectCards.tests.ps1 index 0e8c5fce..39ed4815 100644 --- a/Tests/GitHubProjectCards.tests.ps1 +++ b/Tests/GitHubProjectCards.tests.ps1 @@ -8,15 +8,29 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +<# + +The Projects tests have been disabled because GitHub has deprecated the ability to create +classic Projects, so these tests will fail when trying to create the project that they test +against. + +There's still value in the rest of the functions as they can still manipulate existing +classic Projects, however we can no longer easily validate that these functions still work +correctly since we have no classic Project to test against. + +For more info, see: https://github.com/microsoft/PowerShellForGitHub/issues/380 + +#> + +BeforeAll { +<# + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readOnly, hidden variables. @{ defaultProject = "TestProject_$([Guid]::NewGuid().Guid)" @@ -40,485 +54,517 @@ try $columntwo = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumnTwo $issue = New-GitHubIssue -Owner $script:ownerName -RepositoryName $repo.name -Title $defaultIssue +#> +} - Describe 'Getting Project Cards' { - BeforeAll { - $card = New-GitHubProjectCard -Column $column.id -Note $defaultCard - $cardArchived = New-GitHubProjectCard -Column $column.id -Note $defaultArchivedCard - Set-GitHubProjectCard -Card $cardArchived.id -Archive - } +Describe 'Getting Project Cards' -Skip { + BeforeAll { + $card = New-GitHubProjectCard -Column $column.id -Note $defaultCard + $cardArchived = New-GitHubProjectCard -Column $column.id -Note $defaultArchivedCard + Set-GitHubProjectCard -Card $cardArchived.id -Archive + } - AfterAll { - $null = Remove-GitHubProjectCard -Card $card.id -Confirm:$false - } + AfterAll { + $null = Remove-GitHubProjectCard -Card $card.id -Confirm:$false + } - Context 'Get cards for a column' { + Context 'Get cards for a column' { + + BeforeAll { $results = @(Get-GitHubProjectCard -Column $column.id) + } - It 'Should get cards' { - $results | Should -Not -BeNullOrEmpty - } + It 'Should get cards' { + $results | Should -Not -BeNullOrEmpty + } - It 'Should only have one card (since it defaults to not archived)' { - $results.Count | Should -Be 1 - } + It 'Should only have one card (since it defaults to not archived)' { + $results.Count | Should -Be 1 + } - It 'Note is correct' { - $results[0].note | Should -Be $defaultCard - } + It 'Note is correct' { + $results[0].note | Should -Be $defaultCard + } - It 'Has the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $results[0].CardId | Should -Be $results[0].id - $results[0].ProjectId | Should -Be $project.id - $results[0].ColumnId | Should -Be $column.id - $results[0].IssueNumber | Should -BeNullOrEmpty - $results[0].RepositoryUrl | Should -BeNullOrEmpty - $results[0].PullRequestNumber | Should -BeNullOrEmpty - $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $results[0].CardId | Should -Be $results[0].id + $results[0].ProjectId | Should -Be $project.id + $results[0].ColumnId | Should -Be $column.id + $results[0].IssueNumber | Should -BeNullOrEmpty + $results[0].RepositoryUrl | Should -BeNullOrEmpty + $results[0].PullRequestNumber | Should -BeNullOrEmpty + $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Get all cards for a column' { + Context 'Get all cards for a column' { + BeforeAll { $results = @(Get-GitHubProjectCard -Column $column.id -State All) + } - It 'Should get all cards' { - $results.Count | Should -Be 2 - } + It 'Should get all cards' { + $results.Count | Should -Be 2 + } - It 'Has the expected type and additional properties' { - foreach ($item in $results) - { - $item.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $item.CardId | Should -Be $item.id - $item.ProjectId | Should -Be $project.id - $item.ColumnId | Should -Be $column.id - $item.IssueNumber | Should -BeNullOrEmpty - $item.RepositoryUrl | Should -BeNullOrEmpty - $item.PullRequestNumber | Should -BeNullOrEmpty - $item.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + foreach ($item in $results) + { + $item.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $item.CardId | Should -Be $item.id + $item.ProjectId | Should -Be $project.id + $item.ColumnId | Should -Be $column.id + $item.IssueNumber | Should -BeNullOrEmpty + $item.RepositoryUrl | Should -BeNullOrEmpty + $item.PullRequestNumber | Should -BeNullOrEmpty + $item.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } + } - Context 'Get archived cards for a column' { + Context 'Get archived cards for a column' { + BeforeAll { $result = Get-GitHubProjectCard -Column $column.id -State Archived - It 'Should get archived card' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Note is correct' { - $result.note | Should -Be $defaultArchivedCard - } + It 'Should get archived card' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should be archived' { - $result.Archived | Should -Be $true - } + It 'Note is correct' { + $result.note | Should -Be $defaultArchivedCard + } - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -BeNullOrEmpty - $result.RepositoryUrl | Should -BeNullOrEmpty - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should be archived' { + $result.Archived | Should -Be $true + } + + It 'Has the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -BeNullOrEmpty + $result.RepositoryUrl | Should -BeNullOrEmpty + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Get non-archived cards for a column (with column on pipeline)' { + Context 'Get non-archived cards for a column (with column on pipeline)' { + BeforeAll { $result = $column | Get-GitHubProjectCard -State NotArchived + } - It 'Should get non-archived card' { - $result | Should -Not -BeNullOrEmpty - } + It 'Should get non-archived card' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should have the right ID' { - $result.id | Should -Be $card.id - } + It 'Should have the right ID' { + $result.id | Should -Be $card.id + } - It 'Should not be archived' { - $result.Archived | Should -Be $false - } + It 'Should not be archived' { + $result.Archived | Should -Be $false + } - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -BeNullOrEmpty - $result.RepositoryUrl | Should -BeNullOrEmpty - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -BeNullOrEmpty + $result.RepositoryUrl | Should -BeNullOrEmpty + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } +} - Describe 'Modify card' { - BeforeAll { - $card = New-GitHubProjectCard -Column $column.id -Note $defaultCard - $cardTwo = New-GitHubProjectCard -Column $column.id -Note $defaultCardTwo - $cardArchived = New-GitHubProjectCard -Column $column.id -Note $defaultArchivedCard - } +Describe 'Modify card' -Skip { + BeforeAll { + $card = New-GitHubProjectCard -Column $column.id -Note $defaultCard + $cardTwo = New-GitHubProjectCard -Column $column.id -Note $defaultCardTwo + $cardArchived = New-GitHubProjectCard -Column $column.id -Note $defaultArchivedCard + } - AfterAll { - $null = Remove-GitHubProjectCard -Card $card.id -Force - } + AfterAll { + $null = Remove-GitHubProjectCard -Card $card.id -Force + } - Context 'Modify card note' { + Context 'Modify card note' { + BeforeAll { Set-GitHubProjectCard -Card $card.id -Note $defaultCardUpdated $result = Get-GitHubProjectCard -Card $card.id + } - It 'Should get card' { - $result | Should -Not -BeNullOrEmpty - } + It 'Should get card' { + $result | Should -Not -BeNullOrEmpty + } - It 'Note has been updated' { - $result.note | Should -Be $defaultCardUpdated - } + It 'Note has been updated' { + $result.note | Should -Be $defaultCardUpdated + } - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -BeNullOrEmpty - $result.RepositoryUrl | Should -BeNullOrEmpty - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -BeNullOrEmpty + $result.RepositoryUrl | Should -BeNullOrEmpty + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Modify card note (via card on pipeline)' { + Context 'Modify card note (via card on pipeline)' { + BeforeAll { + $card | Set-GitHubProjectCard -Note $defaultCard $result = $card | Get-GitHubProjectCard + } - It 'Should have the expected Note value' { - $result.note | Should -Be $defaultCardUpdated - } + It 'Should have the expected Note value' { + $result.note | Should -Be $defaultCardUpdated + } - $card | Set-GitHubProjectCard -Note $defaultCard - $result = $card | Get-GitHubProjectCard - It 'Should have the updated Note' { - $result.note | Should -Be $defaultCard - } + It 'Should have the updated Note' { + $result = $card | Get-GitHubProjectCard + $result.note | Should -Be $defaultCard + } - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -BeNullOrEmpty - $result.RepositoryUrl | Should -BeNullOrEmpty - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + $result = $card | Get-GitHubProjectCard + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -BeNullOrEmpty + $result.RepositoryUrl | Should -BeNullOrEmpty + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Archive a card' { + Context 'Archive a card' { + BeforeAll { Set-GitHubProjectCard -Card $cardArchived.id -Archive $result = Get-GitHubProjectCard -Card $cardArchived.id + } - It 'Should get card' { - $result | Should -Not -BeNullOrEmpty - } + It 'Should get card' { + $result | Should -Not -BeNullOrEmpty + } - It 'Card is archived' { - $result.Archived | Should -Be $true - } + It 'Card is archived' { + $result.Archived | Should -Be $true } + } - Context 'Restore a card' { + Context 'Restore a card' { + BeforeAll { $cardArchived | Set-GitHubProjectCard -Restore $result = Get-GitHubProjectCard -Card $cardArchived.id + } - It 'Should get card' { - $result | Should -Not -BeNullOrEmpty - } + It 'Should get card' { + $result | Should -Not -BeNullOrEmpty + } - It 'Card is not archived' { - $result.Archived | Should -Be $false - } + It 'Card is not archived' { + $result.Archived | Should -Be $false } + } - Context 'Move card position within column' { + Context 'Move card position within column' { + BeforeAll { $null = Move-GitHubProjectCard -Card $cardTwo.id -Top $results = @(Get-GitHubProjectCard -Column $column.id) + } - It 'Card is now top' { - $results[0].note | Should -Be $defaultCardTwo - } + It 'Card is now top' { + $results[0].note | Should -Be $defaultCardTwo + } - It 'Has the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $results[0].CardId | Should -Be $results[0].id - $results[0].ProjectId | Should -Be $project.id - $results[0].ColumnId | Should -Be $column.id - $results[0].IssueNumber | Should -BeNullOrEmpty - $results[0].RepositoryUrl | Should -BeNullOrEmpty - $results[0].PullRequestNumber | Should -BeNullOrEmpty - $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $results[0].CardId | Should -Be $results[0].id + $results[0].ProjectId | Should -Be $project.id + $results[0].ColumnId | Should -Be $column.id + $results[0].IssueNumber | Should -BeNullOrEmpty + $results[0].RepositoryUrl | Should -BeNullOrEmpty + $results[0].PullRequestNumber | Should -BeNullOrEmpty + $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Move card using after parameter' { + Context 'Move card using after parameter' { + BeforeAll { $null = Move-GitHubProjectCard -Card $cardTwo.id -After $card.id $results = @(Get-GitHubProjectCard -Column $column.id) + } - It 'Card now exists in new column' { - $results[1].note | Should -Be $defaultCardTwo - } + It 'Card now exists in new column' { + $results[1].note | Should -Be $defaultCardTwo + } - It 'Has the expected type and additional properties' { - $results[1].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $results[1].CardId | Should -Be $results[1].id - $results[1].ProjectId | Should -Be $project.id - $results[1].ColumnId | Should -Be $column.id - $results[1].IssueNumber | Should -BeNullOrEmpty - $results[1].RepositoryUrl | Should -BeNullOrEmpty - $results[1].PullRequestNumber | Should -BeNullOrEmpty - $results[1].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + $results[1].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $results[1].CardId | Should -Be $results[1].id + $results[1].ProjectId | Should -Be $project.id + $results[1].ColumnId | Should -Be $column.id + $results[1].IssueNumber | Should -BeNullOrEmpty + $results[1].RepositoryUrl | Should -BeNullOrEmpty + $results[1].PullRequestNumber | Should -BeNullOrEmpty + $results[1].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Move card using before parameter (card on pipeline)' { + Context 'Move card using before parameter (card on pipeline)' { + BeforeAll { $null = $cardTwo | Move-GitHubProjectCard -After $card.id $results = @($column | Get-GitHubProjectCard) + } - It 'Card now exists in new column' { - $results[1].note | Should -Be $defaultCardTwo - } + It 'Card now exists in new column' { + $results[1].note | Should -Be $defaultCardTwo + } - It 'Has the expected type and additional properties' { - $results[1].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $results[1].CardId | Should -Be $results[1].id - $results[1].ProjectId | Should -Be $project.id - $results[1].ColumnId | Should -Be $column.id - $results[1].IssueNumber | Should -BeNullOrEmpty - $results[1].RepositoryUrl | Should -BeNullOrEmpty - $results[1].PullRequestNumber | Should -BeNullOrEmpty - $results[1].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + $results[1].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $results[1].CardId | Should -Be $results[1].id + $results[1].ProjectId | Should -Be $project.id + $results[1].ColumnId | Should -Be $column.id + $results[1].IssueNumber | Should -BeNullOrEmpty + $results[1].RepositoryUrl | Should -BeNullOrEmpty + $results[1].PullRequestNumber | Should -BeNullOrEmpty + $results[1].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Move card to another column' { + Context 'Move card to another column' { + BeforeAll { $null = Move-GitHubProjectCard -Card $cardTwo.id -Top -ColumnId $columnTwo.id $results = @(Get-GitHubProjectCard -Column $columnTwo.id) + } - It 'Card now exists in new column' { - $results[0].note | Should -Be $defaultCardTwo - } + It 'Card now exists in new column' { + $results[0].note | Should -Be $defaultCardTwo + } - It 'Has the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $results[0].CardId | Should -Be $results[0].id - $results[0].ProjectId | Should -Be $project.id - $results[0].ColumnId | Should -Be $columnTwo.id - $results[0].IssueNumber | Should -BeNullOrEmpty - $results[0].RepositoryUrl | Should -BeNullOrEmpty - $results[0].PullRequestNumber | Should -BeNullOrEmpty - $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Has the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $results[0].CardId | Should -Be $results[0].id + $results[0].ProjectId | Should -Be $project.id + $results[0].ColumnId | Should -Be $columnTwo.id + $results[0].IssueNumber | Should -BeNullOrEmpty + $results[0].RepositoryUrl | Should -BeNullOrEmpty + $results[0].PullRequestNumber | Should -BeNullOrEmpty + $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Move card to another column (with column on pipeline)' { + Context 'Move card to another column (with column on pipeline)' { + BeforeAll { $null = ($column | Move-GitHubProjectCard -Card $cardTwo.id -Top) $result = $cardTwo | Get-GitHubProjectCard + } - It 'Card now exists in new column' { - $result.ColumnId | Should -Be $column.ColumnId - } - - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -BeNullOrEmpty - $result.RepositoryUrl | Should -BeNullOrEmpty - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Card now exists in new column' { + $result.ColumnId | Should -Be $column.ColumnId } - Context 'Move command throws appropriate error' { - It 'Appropriate error is thrown' { - { Move-GitHubProjectCard -Card $cardTwo.id -Top -Bottom } | Should -Throw 'You must use one (and only one) of the parameters Top, Bottom or After.' - } + It 'Has the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -BeNullOrEmpty + $result.RepositoryUrl | Should -BeNullOrEmpty + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } - Describe 'Create Project Cards' { - Context 'Create project card with note' { - BeforeAll { - $card = @{id = 0} - } + Context 'Move command throws appropriate error' { + It 'Appropriate error is thrown' { + { Move-GitHubProjectCard -Card $cardTwo.id -Top -Bottom } | Should -Throw 'You must use one (and only one) of the parameters Top, Bottom or After.' + } + } +} - AfterAll { - $null = Remove-GitHubProjectCard -Card $card.id -Confirm:$false - Remove-Variable -Name card - } +Describe 'Create Project Cards' -Skip { + Context 'Create project card with note' { + BeforeAll { + $card = @{id = 0 } $card.id = (New-GitHubProjectCard -Column $column.id -Note $defaultCard).id $result = Get-GitHubProjectCard -Card $card.id + } - It 'Card exists' { - $result | Should -Not -BeNullOrEmpty - } + AfterAll { + $null = Remove-GitHubProjectCard -Card $card.id -Confirm:$false + Remove-Variable -Name card + } - It 'Note is correct' { - $result.note | Should -Be $defaultCard - } + It 'Card exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -BeNullOrEmpty - $result.RepositoryUrl | Should -BeNullOrEmpty - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Note is correct' { + $result.note | Should -Be $defaultCard } - Context 'Create project card with note (with column object via pipeline)' { - BeforeAll { - $card = @{id = 0} - } + It 'Has the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -BeNullOrEmpty + $result.RepositoryUrl | Should -BeNullOrEmpty + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProjectCard -Card $card.id -Confirm:$false - Remove-Variable -Name card - } + Context 'Create project card with note (with column object via pipeline)' { + BeforeAll { + $card = @{id = 0 } $newCard = $column | New-GitHubProjectCard -Note $defaultCard $card.id = $newCard.id $result = $newCard | Get-GitHubProjectCard + } - It 'Card exists' { - $result | Should -Not -BeNullOrEmpty - } + AfterAll { + $null = Remove-GitHubProjectCard -Card $card.id -Confirm:$false + Remove-Variable -Name card + } - It 'Note is correct' { - $result.note | Should -Be $defaultCard - } + It 'Card exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -BeNullOrEmpty - $result.RepositoryUrl | Should -BeNullOrEmpty - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Note is correct' { + $result.note | Should -Be $defaultCard } - Context 'Create project card from issue' { - BeforeAll { - $card = @{id = 0} - } + It 'Has the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -BeNullOrEmpty + $result.RepositoryUrl | Should -BeNullOrEmpty + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProjectCard -Card $card.id -Force - Remove-Variable -Name card - } + Context 'Create project card from issue' { + BeforeAll { + $card = @{id = 0 } $card.id = (New-GitHubProjectCard -Column $column.id -IssueId $issue.id).id $result = Get-GitHubProjectCard -Card $card.id + } - It 'Card exists' { - $result | Should -Not -BeNullOrEmpty - } + AfterAll { + $null = Remove-GitHubProjectCard -Card $card.id -Force + Remove-Variable -Name card + } - It 'Content url is for an issue' { - $result.content_url | Should -Match 'issues' - } + It 'Card exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -Be $issue.number - $result.RepositoryUrl | Should -Be $issue.RepositoryUrl - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Content url is for an issue' { + $result.content_url | Should -Match 'issues' } - Context 'Create project card from issue (with issue object on pipeline)' { - BeforeAll { - $card = @{id = 0} - } + It 'Has the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -Be $issue.number + $result.RepositoryUrl | Should -Be $issue.RepositoryUrl + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProjectCard -Card $card.id -Force - Remove-Variable -Name card - } + Context 'Create project card from issue (with issue object on pipeline)' { + BeforeAll { + $card = @{id = 0 } $newCard = $issue | New-GitHubProjectCard -Column $column.id $card.id = $newCard.id $result = $newCard | Get-GitHubProjectCard + } - It 'Card exists' { - $result | Should -Not -BeNullOrEmpty - } + AfterAll { + $null = Remove-GitHubProjectCard -Card $card.id -Force + Remove-Variable -Name card + } - It 'Content url is for an issue' { - $result.content_url | Should -Match 'issues' - } + It 'Card exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Has the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' - $result.CardId | Should -Be $result.id - $result.ProjectId | Should -Be $project.id - $result.ColumnId | Should -Be $column.id - $result.IssueNumber | Should -Be $issue.number - $result.RepositoryUrl | Should -Be $issue.RepositoryUrl - $result.PullRequestNumber | Should -BeNullOrEmpty - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Content url is for an issue' { + $result.content_url | Should -Match 'issues' } - # TODO: Create a test that verifies cards created based on a pull request + It 'Has the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectCard' + $result.CardId | Should -Be $result.id + $result.ProjectId | Should -Be $project.id + $result.ColumnId | Should -Be $column.id + $result.IssueNumber | Should -Be $issue.number + $result.RepositoryUrl | Should -Be $issue.RepositoryUrl + $result.PullRequestNumber | Should -BeNullOrEmpty + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } } - Describe 'Remove card' { - Context 'Remove card' { - BeforeAll { - $card = New-GitHubProjectCard -Column $column.id -Note $defaultCard - } + # TODO: Create a test that verifies cards created based on a pull request +} +Describe 'Remove card' -Skip { + Context 'Remove card' { + BeforeAll { + $card = New-GitHubProjectCard -Column $column.id -Note $defaultCard $null = Remove-GitHubProjectCard -Card $card.id -Confirm:$false - It 'Project card should be removed' { - {Get-GitHubProjectCard -Card $card.id} | Should -Throw - } } - Context 'Remove card (via pipeline)' { - BeforeAll { - $card = $column | New-GitHubProjectCard -Note $defaultCard - } + It 'Project card should be removed' { + { Get-GitHubProjectCard -Card $card.id } | Should -Throw + } + } + Context 'Remove card (via pipeline)' { + BeforeAll { + $card = $column | New-GitHubProjectCard -Note $defaultCard $null = $card | Remove-GitHubProjectCard -Force - It 'Project card should be removed' { - {$card | Get-GitHubProjectCard} | Should -Throw - } + } + + It 'Project card should be removed' { + { $card | Get-GitHubProjectCard } | Should -Throw } } +} +AfterAll { +<# Remove-GitHubProject -Project $project.id -Confirm:$false -} -finally -{ + if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state Restore-GitHubConfiguration -Path $script:originalConfigFile $script:originalConfigFile = $null } -} \ No newline at end of file +#> +} diff --git a/Tests/GitHubProjectColumns.tests.ps1 b/Tests/GitHubProjectColumns.tests.ps1 index 8fd6309f..107fdb68 100644 --- a/Tests/GitHubProjectColumns.tests.ps1 +++ b/Tests/GitHubProjectColumns.tests.ps1 @@ -8,15 +8,29 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +<# + +The Projects tests have been disabled because GitHub has deprecated the ability to create +classic Projects, so these tests will fail when trying to create the project that they test +against. + +There's still value in the rest of the functions as they can still manipulate existing +classic Projects, however we can no longer easily validate that these functions still work +correctly since we have no classic Project to test against. + +For more info, see: https://github.com/microsoft/PowerShellForGitHub/issues/380 + +#> + +BeforeAll { +<# + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readOnly, hidden variables. @{ defaultProject = "TestProject_$([Guid]::NewGuid().Guid)" @@ -28,286 +42,305 @@ try } $project = New-GitHubProject -UserProject -ProjectName $defaultProject +#> +} - Describe 'Getting Project Columns' { +Describe 'Getting Project Columns' -Skip { + BeforeAll { + $column = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn + } + + AfterAll { + $null = Remove-GitHubProjectColumn -Column $column.id -Confirm:$false + } + + Context 'Get columns for a project' { BeforeAll { - $column = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn + $results = @(Get-GitHubProjectColumn -Project $project.id) } - AfterAll { - $null = Remove-GitHubProjectColumn -Column $column.id -Confirm:$false + It 'Should get column' { + $results | Should -Not -BeNullOrEmpty } - Context 'Get columns for a project' { - $results = @(Get-GitHubProjectColumn -Project $project.id) - It 'Should get column' { - $results | Should -Not -BeNullOrEmpty - } - - It 'Should only have one column' { - $results.Count | Should -Be 1 - } + It 'Should only have one column' { + $results.Count | Should -Be 1 + } - It 'Name is correct' { - $results[0].name | Should -Be $defaultColumn - } + It 'Name is correct' { + $results[0].name | Should -Be $defaultColumn + } - It 'Should have the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $results[0].ColumnId | Should -Be $results[0].id - $results[0].ColumnName | Should -Be $results[0].name - $results[0].ProjectId | Should -Be $project.id - } + It 'Should have the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $results[0].ColumnId | Should -Be $results[0].id + $results[0].ColumnName | Should -Be $results[0].name + $results[0].ProjectId | Should -Be $project.id } + } - Context 'Get columns for a project (via pipeline)' { + Context 'Get columns for a project (via pipeline)' { + BeforeAll { $results = @($project | Get-GitHubProjectColumn) - It 'Should get column' { - $results | Should -Not -BeNullOrEmpty - } + } - It 'Should only have one column' { - $results.Count | Should -Be 1 - } + It 'Should get column' { + $results | Should -Not -BeNullOrEmpty + } - It 'Name is correct' { - $results[0].name | Should -Be $defaultColumn - } + It 'Should only have one column' { + $results.Count | Should -Be 1 + } - It 'Should have the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $results[0].ColumnId | Should -Be $results[0].id - $results[0].ColumnName | Should -Be $results[0].name - $results[0].ProjectId | Should -Be $project.id - } + It 'Name is correct' { + $results[0].name | Should -Be $defaultColumn } - Context 'Get specific column' { + It 'Should have the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $results[0].ColumnId | Should -Be $results[0].id + $results[0].ColumnName | Should -Be $results[0].name + $results[0].ProjectId | Should -Be $project.id + } + } + + Context 'Get specific column' { + BeforeAll { $result = Get-GitHubProjectColumn -Column $column.id + } - It 'Should be the right column' { - $result.id | Should -Be $column.id - } + It 'Should be the right column' { + $result.id | Should -Be $column.id + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $result.ColumnId | Should -Be $result.id - $result.ColumnName | Should -Be $result.name - $result.ProjectId | Should -Be $project.id - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $result.ColumnId | Should -Be $result.id + $result.ColumnName | Should -Be $result.name + $result.ProjectId | Should -Be $project.id } + } - Context 'Get specific column (via pipeline)' { + Context 'Get specific column (via pipeline)' { + BeforeAll { $result = $column | Get-GitHubProjectColumn + } - It 'Should be the right column' { - $result.id | Should -Be $column.id - } + It 'Should be the right column' { + $result.id | Should -Be $column.id + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $result.ColumnId | Should -Be $result.id - $result.ColumnName | Should -Be $result.name - $result.ProjectId | Should -Be $project.id - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $result.ColumnId | Should -Be $result.id + $result.ColumnName | Should -Be $result.name + $result.ProjectId | Should -Be $project.id } } +} - Describe 'Modify Project Column' { - BeforeAll { - $column = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn - $columntwo = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumnTwo - } +Describe 'Modify Project Column' -Skip { + BeforeAll { + $column = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn + $columntwo = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumnTwo + } - AfterAll { - $null = Remove-GitHubProjectColumn -Column $column.id -Confirm:$false - $null = Remove-GitHubProjectColumn -Column $columntwo.id -Confirm:$false - } + AfterAll { + $null = Remove-GitHubProjectColumn -Column $column.id -Confirm:$false + $null = Remove-GitHubProjectColumn -Column $columntwo.id -Confirm:$false + } - Context 'Modify column name' { + Context 'Modify column name' { + BeforeAll { Set-GitHubProjectColumn -Column $column.id -ColumnName $defaultColumnUpdate $result = Get-GitHubProjectColumn -Column $column.id + } - It 'Should get column' { - $result | Should -Not -BeNullOrEmpty - } + It 'Should get column' { + $result | Should -Not -BeNullOrEmpty + } - It 'Name has been updated' { - $result.name | Should -Be $defaultColumnUpdate - } + It 'Name has been updated' { + $result.name | Should -Be $defaultColumnUpdate + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $result.ColumnId | Should -Be $result.id - $result.ColumnName | Should -Be $result.name - $result.ProjectId | Should -Be $project.id - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $result.ColumnId | Should -Be $result.id + $result.ColumnName | Should -Be $result.name + $result.ProjectId | Should -Be $project.id } + } - Context 'Move column to first position' { + Context 'Move column to first position' { + BeforeAll { $null = Move-GitHubProjectColumn -Column $columntwo.id -First $results = @(Get-GitHubProjectColumn -Project $project.id) + } - It 'Should still have more than one column in the project' { - $results.Count | Should -Be 2 - } + It 'Should still have more than one column in the project' { + $results.Count | Should -Be 2 + } - It 'Column is now in the first position' { - $results[0].name | Should -Be $defaultColumnTwo - } + It 'Column is now in the first position' { + $results[0].name | Should -Be $defaultColumnTwo + } - It 'Should have the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $results[0].ColumnId | Should -Be $results[0].id - $results[0].ColumnName | Should -Be $results[0].name - $results[0].ProjectId | Should -Be $project.id - } + It 'Should have the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $results[0].ColumnId | Should -Be $results[0].id + $results[0].ColumnName | Should -Be $results[0].name + $results[0].ProjectId | Should -Be $project.id } + } - Context 'Move column using after parameter' { + Context 'Move column using after parameter' { + BeforeAll { $null = Move-GitHubProjectColumn -Column $columntwo.id -After $column.id $results = @(Get-GitHubProjectColumn -Project $project.id) + } - It 'Column is now not in the first position' { - $results[1].name | Should -Be $defaultColumnTwo - } - - It 'Should have the expected type and additional properties' { - $results[1].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $results[1].ColumnId | Should -Be $columntwo.ColumnId - $results[1].ColumnName | Should -Be $columntwo.ColumnName - $results[1].ProjectId | Should -Be $project.id - } + It 'Column is now not in the first position' { + $results[1].name | Should -Be $defaultColumnTwo } - Context 'Move command throws appropriate error' { - It 'Expected error returned' { - { Move-GitHubProjectColumn -Column $column.id -First -Last } | Should -Throw 'You must use one (and only one) of the parameters First, Last or After.' - } + It 'Should have the expected type and additional properties' { + $results[1].PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $results[1].ColumnId | Should -Be $columntwo.ColumnId + $results[1].ColumnName | Should -Be $columntwo.ColumnName + $results[1].ProjectId | Should -Be $project.id } } - Describe 'Create Project Column' { - Context 'Create project column' { - BeforeAll { - $column = @{id = 0} - } + Context 'Move command throws appropriate error' { + It 'Expected error returned' { + { Move-GitHubProjectColumn -Column $column.id -First -Last } | Should -Throw 'You must use one (and only one) of the parameters First, Last or After.' + } + } +} - AfterAll { - $null = Remove-GitHubProjectColumn -Column $column.id -Force - Remove-Variable -Name column - } +Describe 'Create Project Column' -Skip { + Context 'Create project column' { + BeforeAll { + $column = @{id = 0 } $column.id = (New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn).id $result = Get-GitHubProjectColumn -Column $column.id + } - It 'Column exists' { - $result | Should -Not -BeNullOrEmpty - } + AfterAll { + $null = Remove-GitHubProjectColumn -Column $column.id -Force + Remove-Variable -Name column + } - It 'Name is correct' { - $result.name | Should -Be $defaultColumn - } + It 'Column exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $result.ColumnId | Should -Be $result.id - $result.ColumnName | Should -Be $result.name - $result.ProjectId | Should -Be $project.id - } + It 'Name is correct' { + $result.name | Should -Be $defaultColumn } - Context 'Create project column (object via pipeline)' { - BeforeAll { - $column = @{id = 0} - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $result.ColumnId | Should -Be $result.id + $result.ColumnName | Should -Be $result.name + $result.ProjectId | Should -Be $project.id + } + } - AfterAll { - $null = Remove-GitHubProjectColumn -Column $column.id -Force - Remove-Variable -Name column - } + Context 'Create project column (object via pipeline)' { + BeforeAll { + $column = @{id = 0 } $column.id = ($project | New-GitHubProjectColumn -ColumnName $defaultColumn).id $result = Get-GitHubProjectColumn -Column $column.id + } - It 'Column exists' { - $result | Should -Not -BeNullOrEmpty - } + AfterAll { + $null = Remove-GitHubProjectColumn -Column $column.id -Force + Remove-Variable -Name column + } - It 'Name is correct' { - $result.name | Should -Be $defaultColumn - } + It 'Column exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $result.ColumnId | Should -Be $result.id - $result.ColumnName | Should -Be $result.name - $result.ProjectId | Should -Be $project.id - } + It 'Name is correct' { + $result.name | Should -Be $defaultColumn } - Context 'Create project column (name via pipeline)' { - BeforeAll { - $column = @{id = 0} - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $result.ColumnId | Should -Be $result.id + $result.ColumnName | Should -Be $result.name + $result.ProjectId | Should -Be $project.id + } + } - AfterAll { - $null = Remove-GitHubProjectColumn -Column $column.id -Force - Remove-Variable -Name column - } + Context 'Create project column (name via pipeline)' { + BeforeAll { + $column = @{id = 0 } $column.id = ($defaultColumn | New-GitHubProjectColumn -Project $project.id).id $result = Get-GitHubProjectColumn -Column $column.id + } + + AfterAll { + $null = Remove-GitHubProjectColumn -Column $column.id -Force + Remove-Variable -Name column + } - It 'Column exists' { - $result | Should -Not -BeNullOrEmpty - } + It 'Column exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Name is correct' { - $result.name | Should -Be $defaultColumn - } + It 'Name is correct' { + $result.name | Should -Be $defaultColumn + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' - $result.ColumnId | Should -Be $result.id - $result.ColumnName | Should -Be $result.name - $result.ProjectId | Should -Be $project.id - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.ProjectColumn' + $result.ColumnId | Should -Be $result.id + $result.ColumnName | Should -Be $result.name + $result.ProjectId | Should -Be $project.id } } +} - Describe 'Remove project column' { - Context 'Remove project column' { - BeforeAll { - $column = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn - } - +Describe 'Remove project column' -Skip { + Context 'Remove project column' { + BeforeAll { + $column = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn $null = Remove-GitHubProjectColumn -Column $column.id -Confirm:$false - It 'Project column should be removed' { - {Get-GitHubProjectColumn -Column $column.id} | Should -Throw - } } - Context 'Remove project column (via pipeline)' { - BeforeAll { - $column = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn - } + It 'Project column should be removed' { + { Get-GitHubProjectColumn -Column $column.id } | Should -Throw + } + } + Context 'Remove project column (via pipeline)' { + BeforeAll { + $column = New-GitHubProjectColumn -Project $project.id -ColumnName $defaultColumn $column | Remove-GitHubProjectColumn -Force - It 'Project column should be removed' { - {$column | Get-GitHubProjectColumn} | Should -Throw - } + } + + It 'Project column should be removed' { + { $column | Get-GitHubProjectColumn } | Should -Throw } } +} +AfterAll { +<# Remove-GitHubProject -Project $project.id -Confirm:$false -} -finally -{ + if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state Restore-GitHubConfiguration -Path $script:originalConfigFile $script:originalConfigFile = $null } -} \ No newline at end of file +#> +} diff --git a/Tests/GitHubProjects.tests.ps1 b/Tests/GitHubProjects.tests.ps1 index 5ec71bc6..c6b9dfcb 100644 --- a/Tests/GitHubProjects.tests.ps1 +++ b/Tests/GitHubProjects.tests.ps1 @@ -8,15 +8,29 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +<# + +The Projects tests have been disabled because GitHub has deprecated the ability to create +classic Projects, so these tests will fail when trying to create the project that they test +against. + +There's still value in the rest of the functions as they can still manipulate existing +classic Projects, however we can no longer easily validate that these functions still work +correctly since we have no classic Project to test against. + +For more info, see: https://github.com/microsoft/PowerShellForGitHub/issues/380 + +#> + +BeforeAll { +<# + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readOnly, hidden variables. @{ defaultUserProject = "TestProject_$([Guid]::NewGuid().Guid)" @@ -38,589 +52,609 @@ try } $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit +#> +} - Describe 'Getting Project' { - Context 'Get User projects' { - BeforeAll { - $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc - } - - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } +Describe 'Getting Project' -Skip { + Context 'Get User projects' { + BeforeAll { + $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc $results = @(Get-GitHubProject -UserName $script:ownerName | Where-Object Name -eq $defaultUserProject) - It 'Should get project' { - $results | Should -Not -BeNullOrEmpty - } + } - It 'Should only get a single project' { - $results.Count | Should -Be 1 - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Name is correct' { - $results[0].name | Should -Be $defaultUserProject - } + It 'Should get project' { + $results | Should -Not -BeNullOrEmpty + } - It 'Description is correct' { - $results[0].body | Should -Be $defaultUserProjectDesc - } + It 'Should only get a single project' { + $results.Count | Should -Be 1 + } - It 'Should have the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $results[0].RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects - $results[0].ProjectId | Should -Be $results[0].id - } + It 'Name is correct' { + $results[0].name | Should -Be $defaultUserProject } - Context 'Get Organization projects' { - BeforeAll { - $project = New-GitHubProject -OrganizationName $script:organizationName -ProjectName $defaultOrgProject -Description $defaultOrgProjectDesc - } + It 'Description is correct' { + $results[0].body | Should -Be $defaultUserProjectDesc + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + It 'Should have the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $results[0].RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects + $results[0].ProjectId | Should -Be $results[0].id + } + } + + Context 'Get Organization projects' { + BeforeAll { + $project = New-GitHubProject -OrganizationName $script:organizationName -ProjectName $defaultOrgProject -Description $defaultOrgProjectDesc $results = @(Get-GitHubProject -OrganizationName $script:organizationName | Where-Object Name -eq $defaultOrgProject) - It 'Should get project' { - $results | Should -Not -BeNullOrEmpty - } + } - It 'Should only get a single project' { - $results.Count | Should -Be 1 - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Name is correct' { - $results[0].name | Should -Be $defaultOrgProject - } + It 'Should get project' { + $results | Should -Not -BeNullOrEmpty + } - It 'Description is correct' { - $results[0].body | Should -Be $defaultOrgProjectDesc - } + It 'Should only get a single project' { + $results.Count | Should -Be 1 + } - It 'Should have the expected type and additional properties' { - $elements = Split-GitHubUri -Uri $results[0].html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Name is correct' { + $results[0].name | Should -Be $defaultOrgProject + } - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $results[0].RepositoryUrl | Should -Be $repositoryUrl - $results[0].ProjectId | Should -Be $results[0].id - } + It 'Description is correct' { + $results[0].body | Should -Be $defaultOrgProjectDesc } - Context 'Get Repo projects' { - BeforeAll { - $project = New-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc - } + It 'Should have the expected type and additional properties' { + $elements = Split-GitHubUri -Uri $results[0].html_url + $repositoryUrl = Join-GitHubUri @elements - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $results[0].RepositoryUrl | Should -Be $repositoryUrl + $results[0].ProjectId | Should -Be $results[0].id + } + } + + Context 'Get Repo projects' { + BeforeAll { + $project = New-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc $results = @(Get-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name | Where-Object Name -eq $defaultRepoProject) - It 'Should get project' { - $results | Should -Not -BeNullOrEmpty - } + } - It 'Should only get a single project' { - $results.Count | Should -Be 1 - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Name is correct' { - $results[0].name | Should -Be $defaultRepoProject - } + It 'Should get project' { + $results | Should -Not -BeNullOrEmpty + } - It 'Description is correct' { - $results[0].body | Should -Be $defaultRepoProjectDesc - } + It 'Should only get a single project' { + $results.Count | Should -Be 1 + } - It 'Should have the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $results[0].RepositoryUrl | Should -Be $repo.RepositoryUrl - $results[0].ProjectId | Should -Be $results[0].id - $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Name is correct' { + $results[0].name | Should -Be $defaultRepoProject } - Context 'Get a closed Repo project (via pipeline)' { - BeforeAll { - $project = $repo | New-GitHubProject -ProjectName $defaultProjectClosed -Description $defaultProjectClosedDesc - Set-GitHubProject -Project $project.id -State Closed - } + It 'Description is correct' { + $results[0].body | Should -Be $defaultRepoProjectDesc + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + It 'Should have the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $results[0].RepositoryUrl | Should -Be $repo.RepositoryUrl + $results[0].ProjectId | Should -Be $results[0].id + $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + Context 'Get a closed Repo project (via pipeline)' { + BeforeAll { + $project = $repo | New-GitHubProject -ProjectName $defaultProjectClosed -Description $defaultProjectClosedDesc + Set-GitHubProject -Project $project.id -State Closed $results = @($repo | Get-GitHubProject -State 'Closed') - It 'Should get project' { - $results | Should -Not -BeNullOrEmpty - } + } + + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Should only get a single project' { - $results.Count | Should -Be 1 - } + It 'Should get project' { + $results | Should -Not -BeNullOrEmpty + } - It 'Name is correct' { - $results[0].name | Should -Be $defaultProjectClosed - } + It 'Should only get a single project' { + $results.Count | Should -Be 1 + } - It 'Description is correct' { - $results[0].body | Should -Be $defaultProjectClosedDesc - } + It 'Name is correct' { + $results[0].name | Should -Be $defaultProjectClosed + } - It 'State is correct' { - $results[0].state | Should -Be "Closed" - } + It 'Description is correct' { + $results[0].body | Should -Be $defaultProjectClosedDesc + } - It 'Should have the expected type and additional properties' { - $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $results[0].RepositoryUrl | Should -Be $repo.RepositoryUrl - $results[0].ProjectId | Should -Be $results[0].id - $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'State is correct' { + $results[0].state | Should -Be "Closed" } - Context 'Get a specific project (by parameter)' { - BeforeAll { - $project = New-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc - } + It 'Should have the expected type and additional properties' { + $results[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $results[0].RepositoryUrl | Should -Be $repo.RepositoryUrl + $results[0].ProjectId | Should -Be $results[0].id + $results[0].creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + Context 'Get a specific project (by parameter)' { + BeforeAll { + $project = New-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc $result = Get-GitHubProject -Project $project.id - It 'Should get project' { - $result | Should -Not -BeNullOrEmpty - } + } + + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Name is correct' { - $result.name | Should -Be $defaultRepoProject - } + It 'Should get project' { + $result | Should -Not -BeNullOrEmpty + } - It 'Description is correct' { - $result.body | Should -Be $defaultRepoProjectDesc - } + It 'Name is correct' { + $result.name | Should -Be $defaultRepoProject + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.ProjectId | Should -Be $project.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Description is correct' { + $result.body | Should -Be $defaultRepoProjectDesc } - Context 'Get a specific project (by pipeline object)' { - BeforeAll { - $project = $repo | New-GitHubProject -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.ProjectId | Should -Be $project.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $project | Remove-GitHubProject -Force - } + Context 'Get a specific project (by pipeline object)' { + BeforeAll { + $project = $repo | New-GitHubProject -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc $result = $project | Get-GitHubProject - It 'Should get the right project' { - $result.id | Should -Be $project.id - } + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.ProjectId | Should -Be $project.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + AfterAll { + $project | Remove-GitHubProject -Force } - Context 'Get a specific project (with ID via pipeline)' { - BeforeAll { - $project = $repo | New-GitHubProject -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc - } + It 'Should get the right project' { + $result.id | Should -Be $project.id + } + + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.ProjectId | Should -Be $project.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $project | Remove-GitHubProject -Force - } + Context 'Get a specific project (with ID via pipeline)' { + BeforeAll { + $project = $repo | New-GitHubProject -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc $result = $project.id | Get-GitHubProject - It 'Should get the right project' { - $result.id | Should -Be $project.id - } + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.ProjectId | Should -Be $project.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + AfterAll { + $project | Remove-GitHubProject -Force } - } - Describe 'Modify Project' { - Context 'Modify User projects' { - BeforeAll { - $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc - } + It 'Should get the right project' { + $result.id | Should -Be $project.id + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.ProjectId | Should -Be $project.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } +} + +Describe 'Modify Project' -Skip { + Context 'Modify User projects' { + BeforeAll { + $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc Set-GitHubProject -Project $project.id -Description $modifiedUserProjectDesc $result = Get-GitHubProject -Project $project.id - It 'Should get project' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Name is correct' { - $result.name | Should -Be $defaultUserProject - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Description should be updated' { - $result.body | Should -Be $modifiedUserProjectDesc - } + It 'Should get project' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Name is correct' { + $result.name | Should -Be $defaultUserProject } - Context 'Modify User projects (via ID in pipeline)' { - BeforeAll { - $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc - } + It 'Description should be updated' { + $result.body | Should -Be $modifiedUserProjectDesc + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + Context 'Modify User projects (via ID in pipeline)' { + BeforeAll { + $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc $project.id | Set-GitHubProject -Description $modifiedUserProjectDesc $result = Get-GitHubProject -Project $project.id - It 'Should get project' { - $result | Should -Not -BeNullOrEmpty - } + } + + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Name is correct' { - $result.name | Should -Be $defaultUserProject - } + It 'Should get project' { + $result | Should -Not -BeNullOrEmpty + } - It 'Description should be updated' { - $result.body | Should -Be $modifiedUserProjectDesc - } + It 'Name is correct' { + $result.name | Should -Be $defaultUserProject + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Description should be updated' { + $result.body | Should -Be $modifiedUserProjectDesc } - Context 'Modify User projects (via object in pipeline)' { - BeforeAll { - $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + Context 'Modify User projects (via object in pipeline)' { + BeforeAll { + $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc $project | Set-GitHubProject -Description $modifiedUserProjectDesc $result = Get-GitHubProject -Project $project.id - It 'Should get project' { - $result | Should -Not -BeNullOrEmpty - } + } + + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Name is correct' { - $result.name | Should -Be $defaultUserProject - } + It 'Should get project' { + $result | Should -Not -BeNullOrEmpty + } - It 'Description should be updated' { - $result.body | Should -Be $modifiedUserProjectDesc - } + It 'Name is correct' { + $result.name | Should -Be $defaultUserProject + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Description should be updated' { + $result.body | Should -Be $modifiedUserProjectDesc } - Context 'Modify Organization projects' { - BeforeAll { - $project = New-GitHubProject -OrganizationName $script:organizationName -ProjectName $defaultOrgProject -Description $defaultOrgProjectDesc - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + Context 'Modify Organization projects' { + BeforeAll { + $project = New-GitHubProject -OrganizationName $script:organizationName -ProjectName $defaultOrgProject -Description $defaultOrgProjectDesc Set-GitHubProject -Project $project.id -Description $modifiedOrgProjectDesc -Private:$false -OrganizationPermission Admin $result = Get-GitHubProject -Project $project.id - It 'Should get project' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Name is correct' { - $result.name | Should -Be $defaultOrgProject - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Description should be updated' { - $result.body | Should -Be $modifiedOrgProjectDesc - } + It 'Should get project' { + $result | Should -Not -BeNullOrEmpty + } - It 'Visibility should be updated to public' { - $result.private | Should -Be $false - } + It 'Name is correct' { + $result.name | Should -Be $defaultOrgProject + } - It 'Organization permission should be updated to admin' { - $result.organization_permission | Should -Be 'admin' - } + It 'Description should be updated' { + $result.body | Should -Be $modifiedOrgProjectDesc + } - It 'Should have the expected type and additional properties' { - $elements = Split-GitHubUri -Uri $result.html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Visibility should be updated to public' { + $result.private | Should -Be $false + } - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -Be $repositoryUrl - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Organization permission should be updated to admin' { + $result.organization_permission | Should -Be 'admin' } - Context 'Modify Repo projects' { - BeforeAll { - $project = New-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc - } + It 'Should have the expected type and additional properties' { + $elements = Split-GitHubUri -Uri $result.html_url + $repositoryUrl = Join-GitHubUri @elements + + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -Be $repositoryUrl + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - } + Context 'Modify Repo projects' { + BeforeAll { + $project = New-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc Set-GitHubProject -Project $project.id -Description $modifiedRepoProjectDesc $result = Get-GitHubProject -Project $project.id - It 'Should get project' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Name is correct' { - $result.name | Should -Be $defaultRepoProject - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + } - It 'Description should be updated' { - $result.body | Should -Be $modifiedRepoProjectDesc - } + It 'Should get project' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Name is correct' { + $result.name | Should -Be $defaultRepoProject + } + + It 'Description should be updated' { + $result.body | Should -Be $modifiedRepoProjectDesc } - } - Describe 'Create Project' { - Context 'Create User projects' { - BeforeAll { - $project = @{id = 0} - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } +} - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - Remove-Variable project - } +Describe 'Create Project' -Skip { + Context 'Create User projects' { + BeforeAll { + $project = @{id = 0 } $project.id = (New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc).id $result = Get-GitHubProject -Project $project.id - It 'Project exists' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Name is correct' { - $result.name | Should -Be $defaultUserProject - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + Remove-Variable project + } - It 'Description should be updated' { - $result.body | Should -Be $defaultUserProjectDesc - } + It 'Project exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Name is correct' { + $result.name | Should -Be $defaultUserProject } - Context 'Create User project (title on pipeline)' { - BeforeAll { - $project = @{id = 0} - } + It 'Description should be updated' { + $result.body | Should -Be $defaultUserProjectDesc + } + + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - Remove-Variable project - } + Context 'Create User project (title on pipeline)' { + BeforeAll { + $project = @{id = 0 } $project.id = ($defaultUserProject | New-GitHubProject -UserProject -Description $defaultUserProjectDesc).id $result = Get-GitHubProject -Project $project.id - It 'Project exists' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Name is correct' { - $result.name | Should -Be $defaultUserProject - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + Remove-Variable project + } - It 'Description should be updated' { - $result.body | Should -Be $defaultUserProjectDesc - } + It 'Project exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Name is correct' { + $result.name | Should -Be $defaultUserProject } - Context 'Create Organization projects' { - BeforeAll { - $project = @{id = 0} - } + It 'Description should be updated' { + $result.body | Should -Be $defaultUserProjectDesc + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - Remove-Variable project - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -BeNullOrEmpty # no RepositoryUrl for user projects + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + Context 'Create Organization projects' { + BeforeAll { + $project = @{id = 0 } $project.id = (New-GitHubProject -OrganizationName $script:organizationName -ProjectName $defaultOrgProject -Description $defaultOrgProjectDesc).id $result = Get-GitHubProject -Project $project.id - It 'Project exists' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Name is correct' { - $result.name | Should -Be $defaultOrgProject - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + Remove-Variable project + } - It 'Description should be updated' { - $result.body | Should -Be $defaultOrgProjectDesc - } + It 'Project exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Should have the expected type and additional properties' { - $elements = Split-GitHubUri -Uri $result.html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Name is correct' { + $result.name | Should -Be $defaultOrgProject + } - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -Be $repositoryUrl - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Description should be updated' { + $result.body | Should -Be $defaultOrgProjectDesc } - Context 'Create Repo projects' { - BeforeAll { - $project = @{id = 0} - } + It 'Should have the expected type and additional properties' { + $elements = Split-GitHubUri -Uri $result.html_url + $repositoryUrl = Join-GitHubUri @elements + + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -Be $repositoryUrl + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - Remove-Variable project - } + Context 'Create Repo projects' { + BeforeAll { + $project = @{id = 0 } $project.id = (New-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc).id $result = Get-GitHubProject -Project $project.id - It 'Project Exists' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Name is correct' { - $result.name | Should -Be $defaultRepoProject - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + Remove-Variable project + } + + It 'Project Exists' { + $result | Should -Not -BeNullOrEmpty + } - It 'Description should be updated' { - $result.body | Should -Be $defaultRepoProjectDesc - } + It 'Name is correct' { + $result.name | Should -Be $defaultRepoProject + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Description should be updated' { + $result.body | Should -Be $defaultRepoProjectDesc } - Context 'Create Repo project (via pipeline)' { - BeforeAll { - $project = @{id = 0} - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } - AfterAll { - $null = Remove-GitHubProject -Project $project.id -Confirm:$false - Remove-Variable project - } + Context 'Create Repo project (via pipeline)' { + BeforeAll { + $project = @{id = 0 } $project.id = ($repo | New-GitHubProject -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc).id $result = Get-GitHubProject -Project $project.id - It 'Project Exists' { - $result | Should -Not -BeNullOrEmpty - } + } - It 'Name is correct' { - $result.name | Should -Be $defaultRepoProject - } + AfterAll { + $null = Remove-GitHubProject -Project $project.id -Confirm:$false + Remove-Variable project + } - It 'Description should be updated' { - $result.body | Should -Be $defaultRepoProjectDesc - } + It 'Project Exists' { + $result | Should -Not -BeNullOrEmpty + } + + It 'Name is correct' { + $result.name | Should -Be $defaultRepoProject + } + + It 'Description should be updated' { + $result.body | Should -Be $defaultRepoProjectDesc + } - It 'Should have the expected type and additional properties' { - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.ProjectId | Should -Be $result.id - $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.Project' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.ProjectId | Should -Be $result.id + $result.creator.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } +} - Describe 'Remove Project' { - Context 'Remove User projects' { +Describe 'Remove Project' -Skip { + Context 'Remove User projects' { + It 'Project should be removed' { $project = New-GitHubProject -UserProject -ProjectName $defaultUserProject -Description $defaultUserProjectDesc $null = Remove-GitHubProject -Project $project.id -Force - It 'Project should be removed' { - {Get-GitHubProject -Project $project.id} | Should -Throw - } + { Get-GitHubProject -Project $project.id } | Should -Throw } + } - Context 'Remove Organization projects' { + Context 'Remove Organization projects' { + It 'Project should be removed' { $project = New-GitHubProject -OrganizationName $script:organizationName -ProjectName $defaultOrgProject -Description $defaultOrgProjectDesc $null = Remove-GitHubProject -Project $project.id -Force - It 'Project should be removed' { - {Get-GitHubProject -Project $project.id} | Should -Throw - } + { Get-GitHubProject -Project $project.id } | Should -Throw } + } - Context 'Remove Repo projects' { + Context 'Remove Repo projects' { + + It 'Project should be removed' { $project = New-GitHubProject -OwnerName $script:ownerName -RepositoryName $repo.name -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc $null = Remove-GitHubProject -Project $project.id -Confirm:$false # Despite using StateChangeDelaySeconds during tests, we still appear to need more time # for projects to be removed before testing that they were properly deleted. Start-Sleep -Seconds 5 - - It 'Project should be removed' { - {Get-GitHubProject -Project $project.id} | Should -Throw - } + { Get-GitHubProject -Project $project.id } | Should -Throw } + } - Context 'Remove Repo project via pipeline' { + Context 'Remove Repo project via pipeline' { + It 'Project should be removed' { $project = $repo | New-GitHubProject -ProjectName $defaultRepoProject -Description $defaultRepoProjectDesc $project | Remove-GitHubProject -Force @@ -628,20 +662,20 @@ try # for projects to be removed before testing that they were properly deleted. Start-Sleep -Seconds 5 - It 'Project should be removed' { - {$project | Get-GitHubProject} | Should -Throw - } + { $project | Get-GitHubProject } | Should -Throw } } +} +AfterAll { +<# Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false -} -finally -{ + if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state Restore-GitHubConfiguration -Path $script:originalConfigFile $script:originalConfigFile = $null } +#> } diff --git a/Tests/GitHubPullRequests.tests.ps1 b/Tests/GitHubPullRequests.tests.ps1 index 8df52250..c1cf5b54 100644 --- a/Tests/GitHubPullRequests.tests.ps1 +++ b/Tests/GitHubPullRequests.tests.ps1 @@ -8,77 +8,80 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} -try -{ - Describe 'Getting pull request from repository' { - BeforeAll { - $repo = Get-GitHubRepository -OwnerName 'microsoft' -RepositoryName 'PowerShellForGitHub' - } +Describe 'Getting pull request from repository' { + BeforeAll { + $repo = Get-GitHubRepository -OwnerName 'microsoft' -RepositoryName 'PowerShellForGitHub' + } - Context 'When getting a pull request' { + Context 'When getting a pull request' { + BeforeAll { $pullRequestNumber = 39 $pullRequest = Get-GitHubPullRequest -OwnerName 'microsoft' -RepositoryName 'PowerShellForGitHub' -PullRequest $pullRequestNumber + } - It 'Should be the expected pull request' { - $pullRequest.number | Should -Be $pullRequestNumber - } + It 'Should be the expected pull request' { + $pullRequest.number | Should -Be $pullRequestNumber + } - It 'Should have the expected type and additional properties' { - $elements = Split-GitHubUri -Uri $pullRequest.html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Should have the expected type and additional properties' { + $elements = Split-GitHubUri -Uri $pullRequest.html_url + $repositoryUrl = Join-GitHubUri @elements - $pullRequest.PSObject.TypeNames[0] | Should -Be 'GitHub.PullRequest' - $pullRequest.RepositoryUrl | Should -Be $repo.RepositoryUrl - $pullRequest.PullRequestId | Should -Be $pullRequest.id - $pullRequest.PullRequestNumber | Should -Be $pullRequest.number - $pullRequest.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $pullRequest.labels[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Label' - $pullRequest.assignee.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $pullRequest.assignees[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $pullRequest.requested_teams[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $pullRequest.merged_by.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + $pullRequest.PSObject.TypeNames[0] | Should -Be 'GitHub.PullRequest' + $pullRequest.RepositoryUrl | Should -Be $repo.RepositoryUrl + $pullRequest.PullRequestId | Should -Be $pullRequest.id + $pullRequest.PullRequestNumber | Should -Be $pullRequest.number + $pullRequest.user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $pullRequest.labels[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Label' + $pullRequest.assignee.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $pullRequest.assignees[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $pullRequest.requested_teams[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $pullRequest.merged_by.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should be refreshable via the pipeline' { - $refresh = $pullRequest | Get-GitHubPullRequest - $refresh.PullRequestNumber | Should -Be $pullRequest.PullRequestNumber - } + It 'Should be refreshable via the pipeline' { + $refresh = $pullRequest | Get-GitHubPullRequest + $refresh.PullRequestNumber | Should -Be $pullRequest.PullRequestNumber + } - It 'Should be retrievable by passing the repo on the pipeline' { - $pullRequest = $repo | Get-GitHubPullRequest -PullRequest $pullRequestNumber - $pullRequest.number | Should -Be $pullRequestNumber - } + It 'Should be retrievable by passing the repo on the pipeline' { + $pullRequest = $repo | Get-GitHubPullRequest -PullRequest $pullRequestNumber + $pullRequest.number | Should -Be $pullRequestNumber + } - It 'Should fail when it the pull request does not exist' { - { $repo | Get-GitHubPullRequest -PullRequest 1 } | Should -Throw - } + It 'Should fail when it the pull request does not exist' { + { $repo | Get-GitHubPullRequest -PullRequest 1 } | Should -Throw } } +} - Describe 'Getting multiple pull requests from repository' { - BeforeAll { - $ownerName = 'microsoft' - $repositoryName = 'PowerShellForGitHub' - } +Describe 'Getting multiple pull requests from repository' { + BeforeAll { + $ownerName = 'microsoft' + $repositoryName = 'PowerShellForGitHub' + } - Context 'All closed' { + Context 'All closed' { + BeforeAll { $pullRequests = @(Get-GitHubPullRequest -OwnerName $ownerName -RepositoryName $repositoryName -State 'Closed') + } - It 'Should return expected number of PRs' { - $pullRequests.Count | Should -BeGreaterOrEqual 140 - } + It 'Should return expected number of PRs' { + $pullRequests.Count | Should -BeGreaterOrEqual 140 } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubReactions.Tests.ps1 b/Tests/GitHubReactions.Tests.ps1 index 703b7f43..95625195 100644 --- a/Tests/GitHubReactions.Tests.ps1 +++ b/Tests/GitHubReactions.Tests.ps1 @@ -8,15 +8,14 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readonly, hidden variables. @{ defaultIssueTitle = "Test Title" @@ -26,43 +25,47 @@ try }.GetEnumerator() | ForEach-Object { Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value } +} - Describe 'Creating, modifying and deleting reactions' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $issue = New-GitHubIssue -Uri $repo.svn_url -Title $defaultIssueTitle - $issueComment = $issue | New-GitHubIssueComment -Body "Foo" - } +Describe 'Creating, modifying and deleting reactions' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $issue = New-GitHubIssue -Uri $repo.svn_url -Title $defaultIssueTitle + $issueComment = $issue | New-GitHubIssueComment -Body "Foo" + } - Context 'For creating a reaction' { + Context 'For creating a reaction' { + It "Should have the expected reaction type" { Set-GitHubReaction -Uri $repo.svn_url -Issue $issue.IssueNumber -ReactionType $defaultReactionType $existingReaction = Get-GitHubReaction -Uri $repo.svn_url -Issue $issue.IssueNumber - It "Should have the expected reaction type" { - $existingReaction.content | Should -Be $defaultReactionType - } + $existingReaction.content | Should -Be $defaultReactionType } + } - Context 'For getting reactions from an issue' { + Context 'For getting reactions from an issue' { + BeforeAll { Get-GitHubIssue -Uri $repo.svn_url -Issue $issue.IssueNumber | Set-GitHubReaction -ReactionType $otherReactionType $allReactions = Get-GitHubReaction -Uri $repo.svn_url -Issue $issue.IssueNumber $specificReactions = Get-GitHubReaction -Uri $repo.svn_url -Issue $issue.IssueNumber -ReactionType $otherReactionType + } - It 'Should have the expected number of reactions' { - $allReactions.Count | Should -Be 2 - $specificReactions | Measure-Object | Select-Object -ExpandProperty Count | Should -Be 1 - } - - It 'Should have the expected reaction content' { - $specificReactions.content | Should -Be $otherReactionType - $specificReactions.RepositoryUrl | Should -Be $repo.RepositoryUrl - $specificReactions.IssueNumber | Should -Be $issue.IssueNumber - $specificReactions.ReactionId | Should -Be $specificReactions.id - $specificReactions.PSObject.TypeNames[0] | Should -Be 'GitHub.Reaction' - } + It 'Should have the expected number of reactions' { + $allReactions.Count | Should -Be 2 + $specificReactions | Measure-Object | Select-Object -ExpandProperty Count | Should -Be 1 } - Context 'For getting reactions from a pull request' { + It 'Should have the expected reaction content' { + $specificReactions.content | Should -Be $otherReactionType + $specificReactions.RepositoryUrl | Should -Be $repo.RepositoryUrl + $specificReactions.IssueNumber | Should -Be $issue.IssueNumber + $specificReactions.ReactionId | Should -Be $specificReactions.id + $specificReactions.PSObject.TypeNames[0] | Should -Be 'GitHub.Reaction' + } + } + + Context 'For getting reactions from a pull request' { + BeforeAll { # TODO: there are currently PRs out to add the ability to create new branches and add content to a repo. # When those go in, this test can be refactored to use those so the test is more reliable using a test PR. $url = 'https://github.com/microsoft/PowerShellForGitHub' @@ -70,45 +73,47 @@ try $allReactions = $pr | Get-GitHubReaction $specificReactions = $pr | Get-GitHubReaction -ReactionType $otherReactionType + } - It 'Should have the expected number of reactions' { - $allReactions.Count | Should -Be 2 - $specificReactions | Measure-Object | Select-Object -ExpandProperty Count | Should -Be 1 - } - - It 'Should have the expected reaction content' { - $specificReactions.content | Should -Be $otherReactionType - $specificReactions.RepositoryUrl | Should -Be $url - $specificReactions.PullRequestNumber | Should -Be $pr.PullRequestNumber - $specificReactions.ReactionId | Should -Be $specificReactions.id - $specificReactions.PSObject.TypeNames[0] | Should -Be 'GitHub.Reaction' - } + It 'Should have the expected number of reactions' { + $allReactions.Count | Should -Be 2 + $specificReactions | Measure-Object | Select-Object -ExpandProperty Count | Should -Be 1 } - Context 'For getting reactions from an Issue and deleting them' { + It 'Should have the expected reaction content' { + $specificReactions.content | Should -Be $otherReactionType + $specificReactions.RepositoryUrl | Should -Be $url + $specificReactions.PullRequestNumber | Should -Be $pr.PullRequestNumber + $specificReactions.ReactionId | Should -Be $specificReactions.id + $specificReactions.PSObject.TypeNames[0] | Should -Be 'GitHub.Reaction' + } + } + + Context 'For getting reactions from an Issue and deleting them' { + BeforeAll { $existingReactions = @(Get-GitHubReaction -Uri $repo.svn_url -Issue $issue.number) + } - It 'Should have the expected number of reactions' { - $existingReactions.Count | Should -Be 2 - } + It 'Should have the expected number of reactions' { + $existingReactions.Count | Should -Be 2 + } + It 'Should have no reactions' { $existingReactions | Remove-GitHubReaction -Force $existingReactions = @(Get-GitHubReaction -Uri $repo.svn_url -Issue $issue.number) - It 'Should have no reactions' { - $existingReactions - $existingReactions.Count | Should -Be 0 - } + $existingReactions + $existingReactions.Count | Should -Be 0 } + } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubReleases.tests.ps1 b/Tests/GitHubReleases.tests.ps1 index b7dc69bd..18ac9e7d 100644 --- a/Tests/GitHubReleases.tests.ps1 +++ b/Tests/GitHubReleases.tests.ps1 @@ -8,391 +8,451 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} -try -{ - Describe 'Getting releases from repository' { - Context 'Common test state' { - BeforeAll { - $dotNetOwnerName = "dotnet" - $repositoryName = "core" +Describe 'Getting releases from repository' { + Context 'Common test state' { + BeforeAll { + $dotNetOwnerName = "dotnet" + $repositoryName = "core" - $releases = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName) - } + $releases = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName) + } - Context 'When getting all releases' { - It 'Should return multiple releases' { - $releases.Count | Should -BeGreaterThan 1 - } + Context 'When getting all releases' { + It 'Should return multiple releases' { + $releases.Count | Should -BeGreaterThan 1 + } - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $releases[0].html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $releases[0].html_url + $repositoryUrl = Join-GitHubUri @elements - $releases[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $releases[0].RepositoryUrl | Should -Be $repositoryUrl - $releases[0].ReleaseId | Should -Be $releases[0].id - } + $releases[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $releases[0].RepositoryUrl | Should -Be $repositoryUrl + $releases[0].ReleaseId | Should -Be $releases[0].id } + } - Context 'When getting the latest releases' { + Context 'When getting the latest releases' { + BeforeAll { $latest = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName -Latest) + } - It 'Should return one value' { - $latest.Count | Should -Be 1 - } + It 'Should return one value' { + $latest.Count | Should -Be 1 + } - It 'Should return the first release from the full releases list' { - $latest[0].url | Should -Be $releases[0].url - $latest[0].name | Should -Be $releases[0].name - } + It 'Should return the first release from the full releases list' { + $first = $releases | Where-Object prerelease -eq $false | Select-Object -First 1 + $latest[0].url | Should -Be $first[0].url + $latest[0].name | Should -Be $first[0].name + } - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $latest[0].html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $latest[0].html_url + $repositoryUrl = Join-GitHubUri @elements - $latest[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $latest[0].RepositoryUrl | Should -Be $repositoryUrl - $latest[0].ReleaseId | Should -Be $latest[0].id - } + $latest[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $latest[0].RepositoryUrl | Should -Be $repositoryUrl + $latest[0].ReleaseId | Should -Be $latest[0].id } + } - Context 'When getting the latest releases via the pipeline' { + Context 'When getting the latest releases via the pipeline' { + BeforeAll { $latest = @(Get-GitHubRepository -OwnerName $dotNetOwnerName -RepositoryName $repositoryName | Get-GitHubRelease -Latest) + } - It 'Should return one value' { - $latest.Count | Should -Be 1 - } + It 'Should return one value' { + $latest.Count | Should -Be 1 + } - It 'Should return the first release from the full releases list' { - $latest[0].url | Should -Be $releases[0].url - $latest[0].name | Should -Be $releases[0].name - } + It 'Should return the first release from the full releases list' { + $first = $releases | Where-Object prerelease -eq $false | Select-Object -First 1 + $latest[0].url | Should -Be $first[0].url + $latest[0].name | Should -Be $first[0].name + } - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $latest[0].html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $latest[0].html_url + $repositoryUrl = Join-GitHubUri @elements - $latest[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $latest[0].RepositoryUrl | Should -Be $repositoryUrl - $latest[0].ReleaseId | Should -Be $latest[0].id - } + $latest[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $latest[0].RepositoryUrl | Should -Be $repositoryUrl + $latest[0].ReleaseId | Should -Be $latest[0].id + } + It 'Should be the same release' { $latestAgain = @($latest | Get-GitHubRelease) - It 'Should be the same release' { - $latest[0].ReleaseId | Should -Be $latestAgain[0].ReleaseId - } + $latest[0].ReleaseId | Should -Be $latestAgain[0].ReleaseId } + } - Context 'When getting a specific release' { + Context 'When getting a specific release' { + BeforeAll { $specificIndex = 5 $specific = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName -ReleaseId $releases[$specificIndex].id) + } - It 'Should return one value' { - $specific.Count | Should -Be 1 - } + It 'Should return one value' { + $specific.Count | Should -Be 1 + } - It 'Should return the correct release' { - $specific.name | Should -Be $releases[$specificIndex].name - } + It 'Should return the correct release' { + $specific.name | Should -Be $releases[$specificIndex].name + } - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $specific[0].html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $specific[0].html_url + $repositoryUrl = Join-GitHubUri @elements - $specific[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $specific[0].RepositoryUrl | Should -Be $repositoryUrl - $specific[0].id | Should -Be $specific[0].ReleaseId - } + $specific[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $specific[0].RepositoryUrl | Should -Be $repositoryUrl + $specific[0].id | Should -Be $specific[0].ReleaseId } + } - Context 'When getting a tagged release' { + Context 'When getting a tagged release' { + BeforeAll { $taggedIndex = 8 $tagged = @(Get-GitHubRelease -OwnerName $dotNetOwnerName -RepositoryName $repositoryName -Tag $releases[$taggedIndex].tag_name) + } - It 'Should return one value' { - $tagged.Count | Should -Be 1 - } + It 'Should return one value' { + $tagged.Count | Should -Be 1 + } - It 'Should return the correct release' { - $tagged.name | Should -Be $releases[$taggedIndex].name - } + It 'Should return the correct release' { + $tagged.name | Should -Be $releases[$taggedIndex].name + } - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $tagged[0].html_url - $repositoryUrl = Join-GitHubUri @elements + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $tagged[0].html_url + $repositoryUrl = Join-GitHubUri @elements - $tagged[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $tagged[0].RepositoryUrl | Should -Be $repositoryUrl - $tagged[0].ReleaseId | Should -Be $tagged[0].id - } + $tagged[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $tagged[0].RepositoryUrl | Should -Be $repositoryUrl + $tagged[0].ReleaseId | Should -Be $tagged[0].id } } } +} - Describe 'Getting releases from default owner/repository' { - Context 'Common test state' { - BeforeAll { - $originalOwnerName = Get-GitHubConfiguration -Name DefaultOwnerName - $originalRepositoryName = Get-GitHubConfiguration -Name DefaultRepositoryName +Describe 'Getting releases from default owner/repository' { + Context 'Common test state' { + BeforeAll { + $originalOwnerName = Get-GitHubConfiguration -Name DefaultOwnerName + $originalRepositoryName = Get-GitHubConfiguration -Name DefaultRepositoryName - Set-GitHubConfiguration -DefaultOwnerName "dotnet" - Set-GitHubConfiguration -DefaultRepositoryName "core" - } + Set-GitHubConfiguration -DefaultOwnerName "dotnet" + Set-GitHubConfiguration -DefaultRepositoryName "core" + } - AfterAll { - Set-GitHubConfiguration -DefaultOwnerName $originalOwnerName - Set-GitHubConfiguration -DefaultRepositoryName $originalRepositoryName - } + AfterAll { + Set-GitHubConfiguration -DefaultOwnerName $originalOwnerName + Set-GitHubConfiguration -DefaultRepositoryName $originalRepositoryName + } - Context 'When getting all releases' { + Context 'When getting all releases' { + It 'Should return multiple releases' { $releases = @(Get-GitHubRelease) - It 'Should return multiple releases' { - $releases.Count | Should -BeGreaterThan 1 - } + $releases.Count | Should -BeGreaterThan 1 } } } +} - Describe 'Creating, changing and deleting releases with defaults' { - Context 'Common test state' { - BeforeAll { - $defaultTagName = '0.2.0' - $defaultReleaseName = 'Release Name' - $defaultReleaseBody = 'Releasey Body' - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private - $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName - $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id - } +Describe 'Creating, changing and deleting releases with defaults' { + Context 'Common test state' { + BeforeAll { + $defaultTagName = '0.2.0' + $defaultReleaseName = 'Release Name' + $defaultReleaseBody = 'Releasey Body' + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName + $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id + } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } - Context 'When creating a simple new release' { - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $release.html_url - $repositoryUrl = Join-GitHubUri @elements + Context 'When creating a simple new release' { + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $release.html_url + $repositoryUrl = Join-GitHubUri @elements - $release.PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $release.RepositoryUrl | Should -Be $repositoryUrl - $release.ReleaseId | Should -Be $release.id - } + $release.PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $release.RepositoryUrl | Should -Be $repositoryUrl + $release.ReleaseId | Should -Be $release.id + } - It 'Should be queryable' { - $queried.id | Should -Be $release.id - $queried.tag_name | Should -Be $defaultTagName - } + It 'Should be queryable' { + $queried.id | Should -Be $release.id + $queried.tag_name | Should -Be $defaultTagName + } - It 'Should have the expected default property values' { - $queried.name | Should -BeNullOrEmpty - $queried.body | Should -BeNullOrEmpty - $queried.draft | Should -BeFalse - $queried.prerelease | Should -BeFalse - } + It 'Should have the expected default property values' { + $queried.name | Should -BeNullOrEmpty + $queried.body | Should -BeNullOrEmpty + $queried.draft | Should -BeFalse + $queried.prerelease | Should -BeFalse + } - It 'Should be modifiable' { - Set-GitHubRelease -Uri $repo.svn_url -Release $release.id -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease - $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id - $queried.name | Should -Be $defaultReleaseName - $queried.body | Should -Be $defaultReleaseBody - $queried.draft | Should -BeTrue - $queried.prerelease | Should -BeTrue - } + It 'Should be modifiable' { + Set-GitHubRelease -Uri $repo.svn_url -Release $release.id -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease + $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeTrue + $queried.prerelease | Should -BeTrue + } - It 'Should be removable' { - Remove-GitHubRelease -Uri $repo.svn_url -Release $release.id -Confirm:$false - { Get-GitHubRelease -Uri $repo.svn_url -Release $release.id } | Should -Throw - } + It 'Should be removable' { + Remove-GitHubRelease -Uri $repo.svn_url -Release $release.id -Confirm:$false + { Get-GitHubRelease -Uri $repo.svn_url -Release $release.id } | Should -Throw } } } +} - Describe 'Creating, changing and deleting releases with defaults using the pipeline' { - Context 'Common test state' { - BeforeAll { - $defaultTagName = '0.2.0' - $defaultReleaseName = 'Release Name' - $defaultReleaseBody = 'Releasey Body' - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private - $release = $repo | New-GitHubRelease -Tag $defaultTagName - $queried = $release | Get-GitHubRelease - } +Describe 'Creating, changing and deleting releases with defaults using the pipeline' { + Context 'Common test state' { + BeforeAll { + $defaultTagName = '0.2.0' + $defaultReleaseName = 'Release Name' + $defaultReleaseBody = 'Releasey Body' + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = $repo | New-GitHubRelease -Tag $defaultTagName + $queried = $release | Get-GitHubRelease + } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } - Context 'When creating a simple new release' { - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $release.html_url - $repositoryUrl = Join-GitHubUri @elements + Context 'When creating a simple new release' { + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $release.html_url + $repositoryUrl = Join-GitHubUri @elements - $release.PSObject.TypeNames[0] | Should -Be 'GitHub.Release' - $release.RepositoryUrl | Should -Be $repositoryUrl - $release.ReleaseId | Should -Be $release.id - } + $release.PSObject.TypeNames[0] | Should -Be 'GitHub.Release' + $release.RepositoryUrl | Should -Be $repositoryUrl + $release.ReleaseId | Should -Be $release.id + } - It 'Should be queryable' { - $queried.id | Should -Be $release.id - $queried.tag_name | Should -Be $defaultTagName - } + It 'Should be queryable' { + $queried.id | Should -Be $release.id + $queried.tag_name | Should -Be $defaultTagName + } - It 'Should have the expected default property values' { - $queried.name | Should -BeNullOrEmpty - $queried.body | Should -BeNullOrEmpty - $queried.draft | Should -BeFalse - $queried.prerelease | Should -BeFalse - } + It 'Should have the expected default property values' { + $queried.name | Should -BeNullOrEmpty + $queried.body | Should -BeNullOrEmpty + $queried.draft | Should -BeFalse + $queried.prerelease | Should -BeFalse + } - It 'Should be modifiable with the release on the pipeline' { - $release | Set-GitHubRelease -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease - $queried = $release | Get-GitHubRelease - $queried.name | Should -Be $defaultReleaseName - $queried.body | Should -Be $defaultReleaseBody - $queried.draft | Should -BeTrue - $queried.prerelease | Should -BeTrue - } + It 'Should be modifiable with the release on the pipeline' { + $release | Set-GitHubRelease -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease + $queried = $release | Get-GitHubRelease + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeTrue + $queried.prerelease | Should -BeTrue + } - It 'Should be modifiable with the URI on the pipeline' { - $repo | Set-GitHubRelease -Release $release.id -Draft:$false - $queried = $repo | Get-GitHubRelease -Release $release.id - $queried.name | Should -Be $defaultReleaseName - $queried.body | Should -Be $defaultReleaseBody - $queried.draft | Should -BeFalse - $queried.prerelease | Should -BeTrue - } + It 'Should be modifiable with the URI on the pipeline' { + $repo | Set-GitHubRelease -Release $release.id -Draft:$false + $queried = $repo | Get-GitHubRelease -Release $release.id + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeFalse + $queried.prerelease | Should -BeTrue + } - It 'Should be removable' { - $release | Remove-GitHubRelease -Force - { $release | Get-GitHubRelease } | Should -Throw - } + It 'Should be removable' { + $release | Remove-GitHubRelease -Force + { $release | Get-GitHubRelease } | Should -Throw } } } +} - Describe 'Creating and changing releases with non-defaults' { - Context 'Common test state' { +Describe 'Creating and changing releases with non-defaults' { + Context 'Common test state' { + BeforeAll { + $defaultTagName = '0.2.0' + $defaultReleaseName = 'Release Name' + $defaultReleaseBody = 'Releasey Body' + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + } + + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + + Context 'When creating a simple new release' { BeforeAll { - $defaultTagName = '0.2.0' - $defaultReleaseName = 'Release Name' - $defaultReleaseBody = 'Releasey Body' - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease + $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id } AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + $release | Remove-GitHubRelease -Force } - Context 'When creating a simple new release' { - BeforeAll { - $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease - $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id - } - - AfterAll { - $release | Remove-GitHubRelease -Force - } - - It 'Should be creatable with non-default property values' { - $queried.id | Should -Be $release.id - $queried.tag_name | Should -Be $defaultTagName - $queried.name | Should -Be $defaultReleaseName - $queried.body | Should -Be $defaultReleaseBody - $queried.draft | Should -BeTrue - $queried.prerelease | Should -BeTrue - } + It 'Should be creatable with non-default property values' { + $queried.id | Should -Be $release.id + $queried.tag_name | Should -Be $defaultTagName + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeTrue + $queried.prerelease | Should -BeTrue } + } - Context 'When creating a simple new release with the repo on the pipeline' { - BeforeAll { - $release = $repo | New-GitHubRelease -Tag $defaultTagName -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease - $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id - } + Context 'When creating a simple new release with the repo on the pipeline' { + BeforeAll { + $release = $repo | New-GitHubRelease -Tag $defaultTagName -Name $defaultReleaseName -Body $defaultReleaseBody -Draft -PreRelease + $queried = Get-GitHubRelease -Uri $repo.svn_url -Release $release.id + } - AfterAll { - $release | Remove-GitHubRelease -Force - } + AfterAll { + $release | Remove-GitHubRelease -Force + } - It 'Should be creatable with non-default property values' { - $queried.id | Should -Be $release.id - $queried.tag_name | Should -Be $defaultTagName - $queried.name | Should -Be $defaultReleaseName - $queried.body | Should -Be $defaultReleaseBody - $queried.draft | Should -BeTrue - $queried.prerelease | Should -BeTrue - } + It 'Should be creatable with non-default property values' { + $queried.id | Should -Be $release.id + $queried.tag_name | Should -Be $defaultTagName + $queried.name | Should -Be $defaultReleaseName + $queried.body | Should -Be $defaultReleaseBody + $queried.draft | Should -BeTrue + $queried.prerelease | Should -BeTrue } } } +} - Describe 'Get-GitHubReleaseAsset' { - BeforeAll { - $defaultTagName = '0.2.0' +Describe 'Get-GitHubReleaseAsset' { + BeforeAll { + $defaultTagName = '0.2.0' - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private - $tempFile = New-TemporaryFile - $zipFile = "$($tempFile.FullName).zip" - Move-Item -Path $tempFile -Destination $zipFile + $tempFile = New-TemporaryFile + $zipFile = "$($tempFile.FullName).zip" + Move-Item -Path $tempFile -Destination $zipFile - $tempFile = New-TemporaryFile - $txtFile = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $txtFile - Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 + $tempFile = New-TemporaryFile + $txtFile = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $txtFile + Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 + + # The file we'll save the downloaded contents to + $saveFile = New-TemporaryFile - # The file we'll save the downloaded contents to - $saveFile = New-TemporaryFile + # Disable Progress Bar in function scope during Compress-Archive + $ProgressPreference = 'SilentlyContinue' + Compress-Archive -Path $txtFile -DestinationPath $zipFile -Force + + $labelBase = 'mylabel' + } + + AfterAll { + @($zipFile, $txtFile, $saveFile) | Remove-Item -ErrorAction SilentlyContinue | Out-Null + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } - # Disable Progress Bar in function scope during Compress-Archive - $ProgressPreference = 'SilentlyContinue' - Compress-Archive -Path $txtFile -DestinationPath $zipFile -Force + Context 'Using parameters' { + BeforeAll { + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName - $labelBase = 'mylabel' + # We want to make sure we start out without the file being there. + Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null } AfterAll { - @($zipFile, $txtFile, $saveFile) | Remove-Item -ErrorAction SilentlyContinue | Out-Null - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + $release | Remove-GitHubRelease -Force } - Context 'Using parameters' { - BeforeAll { - $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName + It 'Should have no assets so far' { + $assets = @(Get-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id) + $assets.Count | Should -Be 0 + } - # We want to make sure we start out without the file being there. - Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null + Context 'Add zip asset' { + BeforeAll { + $fileName = (Get-Item -Path $zipFile).Name + $finalLabel = "$labelBase-$fileName" + $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $zipFile -Label $finalLabel } - AfterAll { - $release | Remove-GitHubRelease -Force + It "Can add a release asset" { + $assetId = $asset.id + + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel } - $assets = @(Get-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id) - It 'Should have no assets so far' { - $assets.Count | Should -Be 0 + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - @($zipFile, $txtFile) | ForEach-Object { - $fileName = (Get-Item -Path $_).Name + Context 'Add txt asset' { + BeforeAll { + $fileName = (Get-Item -Path $txtFile).Name $finalLabel = "$labelBase-$fileName" - $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $_ -Label $finalLabel - It "Can add a release asset" { - $assetId = $asset.id + $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile -Label $finalLabel + } - $asset.name | Should -BeExactly $fileName - $asset.label | Should -BeExactly $finalLabel - } + It "Can add a release asset" { + $assetId = $asset.id - It 'Should have expected type and additional properties' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel + } + + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + Context 'Retrieve Assets' { + BeforeAll { + $assets = @(Get-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id) + } + + It 'Should have both assets now' { + $assets.Count | Should -Be 2 + } + + It 'Should have expected type and additional properties' { + foreach ($asset in $assets) + { $elements = Split-GitHubUri -Uri $asset.url $repositoryUrl = Join-GitHubUri @elements @@ -403,14 +463,19 @@ try } } - $assets = @(Get-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id) - It 'Should have both assets now' { - $assets.Count | Should -Be 2 - } - It 'Should have expected type and additional properties' { - foreach ($asset in $assets) - { + Context 'Retrieve txt asset' { + BeforeAll { + $txtFileName = (Get-Item -Path $txtFile).Name + $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } + $asset = Get-GitHubReleaseAsset -Uri $repo.svn_url -Asset $txtFileAsset.id + } + + It 'Should be able to query for a single asset' { + $asset.id | Should -Be $txtFileAsset.id + } + + It 'Should have expected type and additional properties' { $elements = Split-GitHubUri -Uri $asset.url $repositoryUrl = Join-GitHubUri @elements @@ -419,13 +484,85 @@ try $asset.AssetId | Should -Be $asset.id $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + + It 'Should not have the downloaded file yet' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse + } + + Context 'Dowload parameters' { + BeforeAll { + $downloadParams = @{ + OwnerName = $script:ownerName + RepositoryName = $repo.name + Asset = $txtFileAsset.id + Path = $saveFile + } + + $null = Get-GitHubReleaseAsset @downloadParams + } + + It 'Should be able to download the asset file' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue + } + + It 'Should be able the same file' { + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + + It 'Should fail if the download location already exists' { + { Get-GitHubReleaseAsset @downloadParams } | Should -Throw + } + + It 'Should work if the download location already exists and -Force is used' { + $null = Get-GitHubReleaseAsset @downloadParams -Force + + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + } } + } + } - $txtFileName = (Get-Item -Path $txtFile).Name - $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } - $asset = Get-GitHubReleaseAsset -Uri $repo.svn_url -Asset $txtFileAsset.id - It 'Should be able to query for a single asset' { - $asset.id | Should -Be $txtFileAsset.id + Context 'Using the repo on the pipeline' { + BeforeAll { + $release = $repo | New-GitHubRelease -Tag $defaultTagName + + # We want to make sure we start out without the file being there. + Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null + + $assets = @($repo | Get-GitHubReleaseAsset -Release $release.id) + } + + AfterAll { + $release | Remove-GitHubRelease -Force + } + + It 'Should have no assets so far' { + $assets.Count | Should -Be 0 + } + + Context 'Add zip file' { + BeforeAll { + $fileName = (Get-Item -Path $zipFile).Name + $finalLabel = "$labelBase-$fileName" + $asset = $repo | New-GitHubReleaseAsset -Release $release.id -Path $zipFile -Label $finalLabel + } + + It "Can add a release asset" { + $assetId = $asset.id + + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel } It 'Should have expected type and additional properties' { @@ -437,77 +574,45 @@ try $asset.AssetId | Should -Be $asset.id $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - It 'Should not have the downloaded file yet' { - Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse - } - - $downloadParams = @{ - OwnerName = $script:ownerName - RepositoryName = $repo.name - Asset = $txtFileAsset.id - Path = $saveFile - } - - $null = Get-GitHubReleaseAsset @downloadParams - It 'Should be able to download the asset file' { - Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue + Context 'Add txtFile' { + BeforeAll { + $fileName = (Get-Item -Path $txtFile).Name + $finalLabel = "$labelBase-$fileName" + $asset = $repo | New-GitHubReleaseAsset -Release $release.id -Path $txtFile -Label $finalLabel } - It 'Should be able the same file' { - $compareParams = @{ - ReferenceObject = (Get-Content -Path $txtFile) - DifferenceObject = (Get-Content -Path $saveFile) - } - - Compare-Object @compareParams | Should -BeNullOrEmpty - } + It "Can add a release asset" { + $assetId = $asset.id - It 'Should fail if the download location already exists' { - { Get-GitHubReleaseAsset @downloadParams } | Should -Throw + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel } - It 'Should work if the download location already exists and -Force is used' { - $null = Get-GitHubReleaseAsset @downloadParams -Force - - $compareParams = @{ - ReferenceObject = (Get-Content -Path $txtFile) - DifferenceObject = (Get-Content -Path $saveFile) - } + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements - Compare-Object @compareParams | Should -BeNullOrEmpty + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } - Context 'Using the repo on the pipeline' { + Context 'Retrieve Assets' { BeforeAll { - $release = $repo | New-GitHubRelease -Tag $defaultTagName - - # We want to make sure we start out without the file being there. - Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null + $assets = @($repo | Get-GitHubReleaseAsset -Release $release.id) } - AfterAll { - $release | Remove-GitHubRelease -Force - } - - $assets = @($repo | Get-GitHubReleaseAsset -Release $release.id) - It 'Should have no assets so far' { - $assets.Count | Should -Be 0 + It 'Should have both assets now' { + $assets.Count | Should -Be 2 } - @($zipFile, $txtFile) | ForEach-Object { - $fileName = (Get-Item -Path $_).Name - $finalLabel = "$labelBase-$fileName" - $asset = $repo | New-GitHubReleaseAsset -Release $release.id -Path $_ -Label $finalLabel - It "Can add a release asset" { - $assetId = $asset.id - - $asset.name | Should -BeExactly $fileName - $asset.label | Should -BeExactly $finalLabel - } - - It 'Should have expected type and additional properties' { + It 'Should have expected type and additional properties' { + foreach ($asset in $assets) + { $elements = Split-GitHubUri -Uri $asset.url $repositoryUrl = Join-GitHubUri @elements @@ -518,14 +623,18 @@ try } } - $assets = @($repo | Get-GitHubReleaseAsset -Release $release.id) - It 'Should have both assets now' { - $assets.Count | Should -Be 2 - } + Context 'Retrieve txt assets' { + BeforeAll { + $txtFileName = (Get-Item -Path $txtFile).Name + $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } + $asset = $repo | Get-GitHubReleaseAsset -Asset $txtFileAsset.id + } - It 'Should have expected type and additional properties' { - foreach ($asset in $assets) - { + It 'Should be able to query for a single asset' { + $asset.id | Should -Be $txtFileAsset.id + } + + It 'Should have expected type and additional properties' { $elements = Split-GitHubUri -Uri $asset.url $repositoryUrl = Join-GitHubUri @elements @@ -534,126 +643,108 @@ try $asset.AssetId | Should -Be $asset.id $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } - } - $txtFileName = (Get-Item -Path $txtFile).Name - $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } - $asset = $repo | Get-GitHubReleaseAsset -Asset $txtFileAsset.id - It 'Should be able to query for a single asset' { - $asset.id | Should -Be $txtFileAsset.id - } - - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $asset.url - $repositoryUrl = Join-GitHubUri @elements + It 'Should not have the downloaded file yet' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse + } - $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' - $asset.RepositoryUrl | Should -Be $repositoryUrl - $asset.AssetId | Should -Be $asset.id - $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + Context 'Download parameters' { + BeforeAll { + $downloadParams = @{ + Asset = $txtFileAsset.id + Path = $saveFile + } - It 'Should not have the downloaded file yet' { - Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse - } + $null = $repo | Get-GitHubReleaseAsset @downloadParams + } - $downloadParams = @{ - Asset = $txtFileAsset.id - Path = $saveFile - } + It 'Should be able to download the asset file' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue + } - $null = $repo | Get-GitHubReleaseAsset @downloadParams - It 'Should be able to download the asset file' { - Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue - } + It 'Should be able the same file' { + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } - It 'Should be able the same file' { - $compareParams = @{ - ReferenceObject = (Get-Content -Path $txtFile) - DifferenceObject = (Get-Content -Path $saveFile) - } + Compare-Object @compareParams | Should -BeNullOrEmpty + } - Compare-Object @compareParams | Should -BeNullOrEmpty - } + It 'Should fail if the download location already exists' { + { $repo | Get-GitHubReleaseAsset @downloadParams } | Should -Throw + } - It 'Should fail if the download location already exists' { - { $repo | Get-GitHubReleaseAsset @downloadParams } | Should -Throw - } + It 'Should work if the download location already exists and -Force is used' { + $null = $repo | Get-GitHubReleaseAsset @downloadParams -Force - It 'Should work if the download location already exists and -Force is used' { - $null = $repo | Get-GitHubReleaseAsset @downloadParams -Force + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } - $compareParams = @{ - ReferenceObject = (Get-Content -Path $txtFile) - DifferenceObject = (Get-Content -Path $saveFile) + Compare-Object @compareParams | Should -BeNullOrEmpty + } } - - Compare-Object @compareParams | Should -BeNullOrEmpty } } + } - Context 'Using the release on the pipeline' { - BeforeAll { - $release = $repo | New-GitHubRelease -Tag $defaultTagName - - # We want to make sure we start out without the file being there. - Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null - } + Context 'Using the release on the pipeline' { + BeforeAll { + $release = $repo | New-GitHubRelease -Tag $defaultTagName - AfterAll { - $release | Remove-GitHubRelease -Force - } + # We want to make sure we start out without the file being there. + Remove-Item -Path $saveFile -ErrorAction SilentlyContinue | Out-Null $assets = @($release | Get-GitHubReleaseAsset) - It 'Should have no assets so far' { - $assets.Count | Should -Be 0 - } - - @($zipFile, $txtFile) | ForEach-Object { - $fileName = (Get-Item -Path $_).Name - $finalLabel = "$labelBase-$fileName" - $asset = $release | New-GitHubReleaseAsset -Path $_ -Label $finalLabel - It "Can add a release asset" { - $assetId = $asset.id + } - $asset.name | Should -BeExactly $fileName - $asset.label | Should -BeExactly $finalLabel - } + AfterAll { + $release | Remove-GitHubRelease -Force + } - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $asset.url - $repositoryUrl = Join-GitHubUri @elements + It 'Should have no assets so far' { + $assets.Count | Should -Be 0 + } - $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' - $asset.RepositoryUrl | Should -Be $repositoryUrl - $asset.AssetId | Should -Be $asset.id - $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + Context 'Add zip file' { + BeforeAll { + $fileName = (Get-Item -Path $zipFile).Name + $finalLabel = "$labelBase-$fileName" + $asset = $release | New-GitHubReleaseAsset -Path $zipFile -Label $finalLabel } - $assets = @($release | Get-GitHubReleaseAsset) - It 'Should have both assets now' { - $assets.Count | Should -Be 2 + It "Can add a release asset" { + $assetId = $asset.id + + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel } It 'Should have expected type and additional properties' { - foreach ($asset in $assets) - { - $elements = Split-GitHubUri -Uri $asset.url - $repositoryUrl = Join-GitHubUri @elements + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements - $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' - $asset.RepositoryUrl | Should -Be $repositoryUrl - $asset.AssetId | Should -Be $asset.id - $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - $txtFileName = (Get-Item -Path $txtFile).Name - $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } - $asset = $release | Get-GitHubReleaseAsset -Asset $txtFileAsset.id - It 'Should be able to query for a single asset' { - $asset.id | Should -Be $txtFileAsset.id + Context 'Add txt file' { + BeforeAll { + $fileName = (Get-Item -Path $txtFile).Name + $finalLabel = "$labelBase-$fileName" + $asset = $release | New-GitHubReleaseAsset -Path $txtFile -Label $finalLabel + } + + It "Can add a release asset" { + $assetId = $asset.id + + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $finalLabel } It 'Should have expected type and additional properties' { @@ -665,127 +756,184 @@ try $asset.AssetId | Should -Be $asset.id $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - It 'Should not have the downloaded file yet' { - Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse + Context 'Retrieve assets' { + BeforeAll { + $assets = @($release | Get-GitHubReleaseAsset) } - $downloadParams = @{ - Asset = $txtFileAsset.id - Path = $saveFile + It 'Should have both assets now' { + $assets.Count | Should -Be 2 } - $null = $release | Get-GitHubReleaseAsset @downloadParams - It 'Should be able to download the asset file' { - Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue + It 'Should have expected type and additional properties' { + foreach ($asset in $assets) + { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements + + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } } - It 'Should be able the same file' { - $compareParams = @{ - ReferenceObject = (Get-Content -Path $txtFile) - DifferenceObject = (Get-Content -Path $saveFile) + Context 'Retrieve txt file' { + BeforeAll { + $txtFileName = (Get-Item -Path $txtFile).Name + $txtFileAsset = $assets | Where-Object { $_.name -eq $txtFileName } + $asset = $release | Get-GitHubReleaseAsset -Asset $txtFileAsset.id } - Compare-Object @compareParams | Should -BeNullOrEmpty - } + It 'Should be able to query for a single asset' { + $asset.id | Should -Be $txtFileAsset.id + } - It 'Should fail if the download location already exists' { - { $release | Get-GitHubReleaseAsset @downloadParams } | Should -Throw - } + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $asset.url + $repositoryUrl = Join-GitHubUri @elements - It 'Should work if the download location already exists and -Force is used' { - $null = $release | Get-GitHubReleaseAsset @downloadParams -Force + $asset.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $asset.RepositoryUrl | Should -Be $repositoryUrl + $asset.AssetId | Should -Be $asset.id + $asset.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - $compareParams = @{ - ReferenceObject = (Get-Content -Path $txtFile) - DifferenceObject = (Get-Content -Path $saveFile) + It 'Should not have the downloaded file yet' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeFalse } - Compare-Object @compareParams | Should -BeNullOrEmpty + Context 'Download file' { + BeforeAll { + $downloadParams = @{ + Asset = $txtFileAsset.id + Path = $saveFile + } + $null = $release | Get-GitHubReleaseAsset @downloadParams + } + + It 'Should be able to download the asset file' { + Test-Path -Path $saveFile -PathType Leaf | Should -BeTrue + } + + It 'Should be able the same file' { + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + + It 'Should fail if the download location already exists' { + { $release | Get-GitHubReleaseAsset @downloadParams } | Should -Throw + } + + It 'Should work if the download location already exists and -Force is used' { + $null = $release | Get-GitHubReleaseAsset @downloadParams -Force + + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $saveFile) + } + + Compare-Object @compareParams | Should -BeNullOrEmpty + } + } } } + } - Context 'Verifying a zip file' { - BeforeAll { - $release = $repo | New-GitHubRelease -Tag $defaultTagName + Context 'Verifying a zip file' { + BeforeAll { + $release = $repo | New-GitHubRelease -Tag $defaultTagName - # To get access to New-TemporaryDirectory - $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent - . (Join-Path -Path $moduleRootPath -ChildPath 'Helpers.ps1') - $tempPath = New-TemporaryDirectory + # To get access to New-TemporaryDirectory + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Helpers.ps1') + $tempPath = New-TemporaryDirectory - $tempFile = New-TemporaryFile - $downloadedZipFile = "$($tempFile.FullName).zip" - Move-Item -Path $tempFile -Destination $downloadedZipFile - } + $tempFile = New-TemporaryFile + $downloadedZipFile = "$($tempFile.FullName).zip" + Move-Item -Path $tempFile -Destination $downloadedZipFile - AfterAll { - $release | Remove-GitHubRelease -Force + $asset = $release | New-GitHubReleaseAsset -Path $zipFile -ContentType 'application/zip' + } - Remove-Item -Path $tempPath -Recurse -ErrorAction SilentlyContinue -Force - if (Get-Variable -Name downloadedZipFile -ErrorAction SilentlyContinue) - { - Remove-Item -Path $downloadedZipFile -ErrorAction SilentlyContinue - } - } + AfterAll { + $release | Remove-GitHubRelease -Force - $asset = $release | New-GitHubReleaseAsset -Path $zipFile -ContentType 'application/zip' - It "Has the expected content inside" { - $result = $asset | Get-GitHubReleaseAsset -Path $downloadedZipFile -Force - Expand-Archive -Path $downloadedZipFile -DestinationPath $tempPath + Remove-Item -Path $tempPath -Recurse -ErrorAction SilentlyContinue -Force + if (Get-Variable -Name downloadedZipFile -ErrorAction SilentlyContinue) + { + Remove-Item -Path $downloadedZipFile -ErrorAction SilentlyContinue + } + } - $result.FullName | Should -BeExactly $downloadedZipFile + It "Has the expected content inside" { + $result = $asset | Get-GitHubReleaseAsset -Path $downloadedZipFile -Force + Expand-Archive -Path $downloadedZipFile -DestinationPath $tempPath - $txtFileName = (Get-Item -Path $txtFile).Name - $downloadedTxtFile = (Get-ChildItem -Path $tempPath -Filter $txtFileName).FullName + $result.FullName | Should -BeExactly $downloadedZipFile - $compareParams = @{ - ReferenceObject = (Get-Content -Path $txtFile) - DifferenceObject = (Get-Content -Path $downloadedTxtFile) - } + $txtFileName = (Get-Item -Path $txtFile).Name + $downloadedTxtFile = (Get-ChildItem -Path $tempPath -Filter $txtFileName).FullName - Compare-Object @compareParams | Should -BeNullOrEmpty + $compareParams = @{ + ReferenceObject = (Get-Content -Path $txtFile) + DifferenceObject = (Get-Content -Path $downloadedTxtFile) } + + Compare-Object @compareParams | Should -BeNullOrEmpty } } +} - Describe 'Set-GitHubReleaseAsset' { - BeforeAll { - $defaultTagName = '0.2.0' +Describe 'Set-GitHubReleaseAsset' { + BeforeAll { + $defaultTagName = '0.2.0' - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private - $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName - $tempFile = New-TemporaryFile - $txtFile = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $txtFile - Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 + $tempFile = New-TemporaryFile + $txtFile = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $txtFile + Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 - $label = 'mylabel' - } + $label = 'mylabel' + } - AfterAll { - $txtFile | Remove-Item | Out-Null - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + AfterAll { + $txtFile | Remove-Item | Out-Null + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } - Context 'Using parameters' { + Context 'Using parameters' { + BeforeAll { $fileName = (Get-Item -Path $txtFile).Name $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile -Label $label + } - It 'Has the expected initial property values' { - $asset.name | Should -BeExactly $fileName - $asset.label | Should -BeExactly $label - } + It 'Has the expected initial property values' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $label + } - $setParams = @{ - OwnerName = $script:ownerName - RepositoryName = $repo.name - Asset = $asset.id - PassThru = $true + Context 'Update release asset' { + BeforeAll { + $setParams = @{ + OwnerName = $script:ownerName + RepositoryName = $repo.name + Asset = $asset.id + PassThru = $true + } + + $updated = Set-GitHubReleaseAsset @setParams } - $updated = Set-GitHubReleaseAsset @setParams It 'Should have the original property values' { $updated.name | Should -BeExactly $fileName $updated.label | Should -BeExactly $label @@ -800,7 +948,9 @@ try $updated.AssetId | Should -Be $updated.id $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should have a new name and the original label' { $updatedFileName = 'updated1.txt' $setParams = @{ OwnerName = $script:ownerName @@ -811,11 +961,12 @@ try } $updated = Set-GitHubReleaseAsset @setParams - It 'Should have a new name and the original label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $label - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $label + } + It 'Should have the current name and a new label' { + $updatedFileName = 'updated1.txt' $updatedLabel = 'updatedLabel2' $setParams = @{ OwnerName = $script:ownerName @@ -826,11 +977,11 @@ try } $updated = Set-GitHubReleaseAsset @setParams - It 'Should have the current name and a new label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $updatedLabel - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + It 'Should have a new name and a new label' { $updatedFileName = 'updated3parameter.txt' $updatedLabel = 'updatedLabel3parameter' $setParams = @{ @@ -843,27 +994,32 @@ try } $updated = Set-GitHubReleaseAsset @setParams - It 'Should have a new name and a new label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $updatedLabel - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel } + } - Context 'Using the repo on the pipeline' { + Context 'Using the repo on the pipeline' { + BeforeAll { $fileName = (Get-Item -Path $txtFile).Name $asset = $repo | New-GitHubReleaseAsset -Release $release.id -Path $txtFile -Label $label + } - It 'Has the expected initial property values' { - $asset.name | Should -BeExactly $fileName - $asset.label | Should -BeExactly $label - } + It 'Has the expected initial property values' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $label + } - $setParams = @{ - Asset = $asset.id - PassThru = $true + Context 'Update the release asset' { + BeforeAll { + $setParams = @{ + Asset = $asset.id + PassThru = $true + } + + $updated = $repo | Set-GitHubReleaseAsset @setParams } - $updated = $repo | Set-GitHubReleaseAsset @setParams It 'Should have the original property values' { $updated.name | Should -BeExactly $fileName $updated.label | Should -BeExactly $label @@ -878,7 +1034,9 @@ try $updated.AssetId | Should -Be $updated.id $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should have a new name and the original label' { $updatedFileName = 'updated1.txt' $setParams = @{ Asset = $asset.id @@ -887,11 +1045,12 @@ try } $updated = $repo | Set-GitHubReleaseAsset @setParams - It 'Should have a new name and the original label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $label - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $label + } + It 'Should have the current name and a new label' { + $updatedFileName = 'updated1.txt' $updatedLabel = 'updatedLabel2' $setParams = @{ Asset = $asset.id @@ -900,11 +1059,11 @@ try } $updated = $repo | Set-GitHubReleaseAsset @setParams - It 'Should have the current name and a new label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $updatedLabel - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + It 'Should have a new name and a new label' { $updatedFileName = 'updated3repo.txt' $updatedLabel = 'updatedLabel3repo' $setParams = @{ @@ -915,27 +1074,32 @@ try } $updated = $repo | Set-GitHubReleaseAsset @setParams - It 'Should have a new name and a new label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $updatedLabel - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel } + } - Context 'Using the release on the pipeline' { + Context 'Using the release on the pipeline' { + BeforeAll { $fileName = (Get-Item -Path $txtFile).Name $asset = $release | New-GitHubReleaseAsset -Path $txtFile -Label $label + } - It 'Has the expected initial property values' { - $asset.name | Should -BeExactly $fileName - $asset.label | Should -BeExactly $label - } + It 'Has the expected initial property values' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $label + } - $setParams = @{ - Asset = $asset.id - PassThru = $true + Context 'Update release' { + BeforeAll { + $setParams = @{ + Asset = $asset.id + PassThru = $true + } + + $updated = $release | Set-GitHubReleaseAsset @setParams } - $updated = $release | Set-GitHubReleaseAsset @setParams It 'Should have the original property values' { $updated.name | Should -BeExactly $fileName $updated.label | Should -BeExactly $label @@ -950,7 +1114,9 @@ try $updated.AssetId | Should -Be $updated.id $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } + It 'Should have a new name and the original label' { $updatedFileName = 'updated1.txt' $setParams = @{ Asset = $asset.id @@ -959,11 +1125,12 @@ try } $updated = $release | Set-GitHubReleaseAsset @setParams - It 'Should have a new name and the original label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $label - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $label + } + It 'Should have the current name and a new label' { + $updatedFileName = 'updated1.txt' $updatedLabel = 'updatedLabel2' $setParams = @{ Asset = $asset.id @@ -972,11 +1139,11 @@ try } $updated = $release | Set-GitHubReleaseAsset @setParams - It 'Should have the current name and a new label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $updatedLabel - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + It 'Should have a new name and a new label' { $updatedFileName = 'updated3release.txt' $updatedLabel = 'updatedLabel3release' $setParams = @{ @@ -987,80 +1154,83 @@ try } $updated = $release | Set-GitHubReleaseAsset @setParams - It 'Should have a new name and a new label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $updatedLabel - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel } + } - Context 'Using the asset on the pipeline' { + Context 'Using the asset on the pipeline' { + BeforeAll { $fileName = (Get-Item -Path $txtFile).Name $asset = $release | New-GitHubReleaseAsset -Path $txtFile -Label $label + $updated = $asset | Set-GitHubReleaseAsset -PassThru + } - It 'Has the expected initial property values' { - $asset.name | Should -BeExactly $fileName - $asset.label | Should -BeExactly $label - } + It 'Has the expected initial property values' { + $asset.name | Should -BeExactly $fileName + $asset.label | Should -BeExactly $label + } - $updated = $asset | Set-GitHubReleaseAsset -PassThru - It 'Should have the original property values' { - $updated.name | Should -BeExactly $fileName - $updated.label | Should -BeExactly $label - } + It 'Should have the original property values' { + $updated.name | Should -BeExactly $fileName + $updated.label | Should -BeExactly $label + } - It 'Should have expected type and additional properties' { - $elements = Split-GitHubUri -Uri $updated.url - $repositoryUrl = Join-GitHubUri @elements + It 'Should have expected type and additional properties' { + $elements = Split-GitHubUri -Uri $updated.url + $repositoryUrl = Join-GitHubUri @elements - $updated.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' - $updated.RepositoryUrl | Should -Be $repositoryUrl - $updated.AssetId | Should -Be $updated.id - $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + $updated.PSObject.TypeNames[0] | Should -Be 'GitHub.ReleaseAsset' + $updated.RepositoryUrl | Should -Be $repositoryUrl + $updated.AssetId | Should -Be $updated.id + $updated.uploader.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + It 'Should have a new name and the original label' { $updatedFileName = 'updated1.txt' $updated = $asset | Set-GitHubReleaseAsset -Name $updatedFileName -PassThru - It 'Should have a new name and the original label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $label - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $label + } + It 'Should have the current name and a new label' { + $updatedFileName = 'updated1.txt' $updatedLabel = 'updatedLabel2' $updated = $asset | Set-GitHubReleaseAsset -Label $updatedLabel -PassThru - It 'Should have the current name and a new label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $updatedLabel - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel + } + It 'Should have a new name and a new label' { $updatedFileName = 'updated3asset.txt' $updatedLabel = 'updatedLabel3asset' $updated = $asset | Set-GitHubReleaseAsset -Name $updatedFileName -Label $updatedLabel -PassThru - It 'Should have a new name and a new label' { - $updated.name | Should -BeExactly $updatedFileName - $updated.label | Should -BeExactly $updatedLabel - } + $updated.name | Should -BeExactly $updatedFileName + $updated.label | Should -BeExactly $updatedLabel } } +} - Describe 'Remove-GitHubReleaseAsset' { - BeforeAll { - $defaultTagName = '0.2.0' +Describe 'Remove-GitHubReleaseAsset' { + BeforeAll { + $defaultTagName = '0.2.0' - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private - $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit -Private + $release = New-GitHubRelease -Uri $repo.svn_url -Tag $defaultTagName - $tempFile = New-TemporaryFile - $txtFile = "$($tempFile.FullName).txt" - Move-Item -Path $tempFile -Destination $txtFile - Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 - } + $tempFile = New-TemporaryFile + $txtFile = "$($tempFile.FullName).txt" + Move-Item -Path $tempFile -Destination $txtFile + Out-File -FilePath $txtFile -InputObject "txt file content" -Encoding utf8 + } - AfterAll { - $txtFile | Remove-Item | Out-Null - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + AfterAll { + $txtFile | Remove-Item | Out-Null + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } - Context 'Using parameters' { + Context 'Using parameters' { + BeforeAll { $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile $params = @{ @@ -1071,41 +1241,42 @@ try } Remove-GitHubReleaseAsset @params - It 'Should be successfully deleted' { - { Remove-GitHubReleaseAsset @params } | Should -Throw - } } - Context 'Using the repo on the pipeline' { + It 'Should be successfully deleted' { + { Remove-GitHubReleaseAsset @params } | Should -Throw + } + } + + Context 'Using the repo on the pipeline' { + It 'Should be successfully deleted' { $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile $repo | Remove-GitHubReleaseAsset -Asset $asset.id -Force - It 'Should be successfully deleted' { - { $repo | Remove-GitHubReleaseAsset -Asset $asset.id -Force } | Should -Throw - } + { $repo | Remove-GitHubReleaseAsset -Asset $asset.id -Force } | Should -Throw } + } - Context 'Using the release on the pipeline' { + Context 'Using the release on the pipeline' { + It 'Should be successfully deleted' { $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile $release | Remove-GitHubReleaseAsset -Asset $asset.id -Force - It 'Should be successfully deleted' { - { $release | Remove-GitHubReleaseAsset -Asset $asset.id -Force } | Should -Throw - } + { $release | Remove-GitHubReleaseAsset -Asset $asset.id -Force } | Should -Throw } + } - Context 'Using the asset on the pipeline' { + Context 'Using the asset on the pipeline' { + It 'Should be successfully deleted' { $asset = New-GitHubReleaseAsset -Uri $repo.svn_url -Release $release.id -Path $txtFile $asset | Remove-GitHubReleaseAsset -Force - It 'Should be successfully deleted' { - { $asset | Remove-GitHubReleaseAsset -Force } | Should -Throw - } + { $asset | Remove-GitHubReleaseAsset -Force } | Should -Throw } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index f63d8f3e..0d5e5d8d 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -8,15 +8,14 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() # This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readonly, hidden variables. @{ defaultRepoDesc = "This is a description." @@ -25,799 +24,712 @@ try }.GetEnumerator() | ForEach-Object { Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value } +} - Describe 'GitHubRepositories\New-GitHubRepository' { - - Context -Name 'When creating a repository for the authenticated user' -Fixture { - - Context -Name 'When creating a public repository with default settings' -Fixture { - BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - } - $repo = New-GitHubRepository @newGitHubRepositoryParms - } - - It 'Should return an object of the correct type' { - $repo | Should -BeOfType PSCustomObject - } +Describe 'GitHubRepositories\New-GitHubRepository' { - It 'Should return the correct properties' { - $repo.name | Should -Be $repoName - $repo.private | Should -BeFalse - $repo.description | Should -BeNullOrEmpty - $repo.homepage | Should -BeNullOrEmpty - $repo.has_issues | Should -BeTrue - $repo.has_projects | Should -BeTrue - $repo.has_Wiki | Should -BeTrue - $repo.allow_squash_merge | Should -BeTrue - $repo.allow_merge_commit | Should -BeTrue - $repo.allow_rebase_merge | Should -BeTrue - $repo.delete_branch_on_merge | Should -BeFalse - $repo.is_template | Should -BeFalse - } + Context -Name 'When creating a repository for the authenticated user' -Fixture { - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + Context -Name 'When creating a public repository with default settings' -Fixture { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName } + $repo = New-GitHubRepository @newGitHubRepositoryParms } - Context -Name 'When creating a private repository with default settings' -Fixture { - BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - Private = $true - } - $repo = New-GitHubRepository @newGitHubRepositoryParms - } + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } - It 'Should return an object of the correct type' { - $repo | Should -BeOfType PSCustomObject - } + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.private | Should -BeFalse + $repo.description | Should -BeNullOrEmpty + $repo.homepage | Should -BeNullOrEmpty + $repo.has_issues | Should -BeTrue + $repo.has_projects | Should -BeTrue + $repo.has_Wiki | Should -BeTrue + $repo.allow_squash_merge | Should -BeTrue + $repo.allow_merge_commit | Should -BeTrue + $repo.allow_rebase_merge | Should -BeTrue + $repo.delete_branch_on_merge | Should -BeFalse + $repo.is_template | Should -BeFalse + } - It 'Should return the correct properties' { - $repo.name | Should -Be $repoName - $repo.private | Should -BeTrue - $repo.description | Should -BeNullOrEmpty - $repo.homepage | Should -BeNullOrEmpty - $repo.has_issues | Should -BeTrue - $repo.has_projects | Should -BeTrue - $repo.has_Wiki | Should -BeTrue - $repo.allow_squash_merge | Should -BeTrue - $repo.allow_merge_commit | Should -BeTrue - $repo.allow_rebase_merge | Should -BeTrue - $repo.delete_branch_on_merge | Should -BeFalse - $repo.is_template | Should -BeFalse + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } + } + } - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + Context -Name 'When creating a private repository with default settings' -Fixture { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + Private = $true } + $repo = New-GitHubRepository @newGitHubRepositoryParms } - Context -Name 'When creating a repository with all possible settings' -Fixture { - BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $testGitIgnoreTemplate=(Get-GitHubGitIgnore)[0] - $testLicenseTemplate=(Get-GitHubLicense)[0].key - - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - Description = $defaultRepoDesc - HomePage = $defaultRepoHomePage - NoIssues = $true - NoProjects = $true - NoWiki = $true - DisallowSquashMerge = $true - DisallowMergeCommit = $true - DisallowRebaseMerge = $false - DeleteBranchOnMerge = $true - GitIgnoreTemplate = $testGitIgnoreTemplate - LicenseTemplate = $testLicenseTemplate - IsTemplate = $true - } - - $repo = New-GitHubRepository @newGitHubRepositoryParms - } + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } - It 'Should return an object of the correct type' { - $repo | Should -BeOfType PSCustomObject - } + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.private | Should -BeTrue + $repo.description | Should -BeNullOrEmpty + $repo.homepage | Should -BeNullOrEmpty + $repo.has_issues | Should -BeTrue + $repo.has_projects | Should -BeTrue + $repo.has_Wiki | Should -BeTrue + $repo.allow_squash_merge | Should -BeTrue + $repo.allow_merge_commit | Should -BeTrue + $repo.allow_rebase_merge | Should -BeTrue + $repo.delete_branch_on_merge | Should -BeFalse + $repo.is_template | Should -BeFalse + } - It 'Should return the correct properties' { - $repo.name | Should -Be $repoName - $repo.description | Should -Be $defaultRepoDesc - $repo.homepage | Should -Be $defaultRepoHomePage - $repo.has_issues | Should -BeFalse - $repo.has_projects | Should -BeFalse - $repo.has_Wiki | Should -BeFalse - $repo.allow_squash_merge | Should -BeFalse - $repo.allow_merge_commit | Should -BeFalse - $repo.allow_rebase_merge | Should -BeTrue - $repo.delete_branch_on_merge | Should -BeTrue - $repo.is_template | Should -BeTrue + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } + } + } - It 'Should have created a .gitignore file' { - { Get-GitHubContent -Uri $repo.svn_url -Path '.gitignore' } | Should -Not -Throw - } + Context -Name 'When creating a repository with all possible settings' -Fixture { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $testGitIgnoreTemplate = (Get-GitHubGitIgnore)[0] + $testLicenseTemplate = (Get-GitHubLicense)[0].key - It 'Should have created a LICENSE file' { - { Get-GitHubContent -Uri $repo.svn_url -Path 'LICENSE' } | Should -Not -Throw + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + Description = $defaultRepoDesc + HomePage = $defaultRepoHomePage + NoIssues = $true + NoProjects = $true + NoWiki = $true + DisallowSquashMerge = $true + DisallowMergeCommit = $true + DisallowRebaseMerge = $false + DeleteBranchOnMerge = $true + GitIgnoreTemplate = $testGitIgnoreTemplate + LicenseTemplate = $testLicenseTemplate + IsTemplate = $true } - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } - } + $repo = New-GitHubRepository @newGitHubRepositoryParms } - Context -Name 'When creating a repository with alternative Merge settings' -Fixture { - BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - DisallowSquashMerge = $true - DisallowMergeCommit = $false - DisallowRebaseMerge = $true - } - $repo = New-GitHubRepository @newGitHubRepositoryParms - } - - It 'Should return an object of the correct type' { - $repo | Should -BeOfType PSCustomObject - } + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } - It 'Should return the correct properties' { - $repo.name | Should -Be $repoName - $repo.allow_squash_merge | Should -BeFalse - $repo.allow_merge_commit | Should -BeTrue - $repo.allow_rebase_merge | Should -BeFalse - } + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.description | Should -Be $defaultRepoDesc + $repo.homepage | Should -Be $defaultRepoHomePage + $repo.has_issues | Should -BeFalse + $repo.has_projects | Should -BeFalse + $repo.has_Wiki | Should -BeFalse + $repo.allow_squash_merge | Should -BeFalse + $repo.allow_merge_commit | Should -BeFalse + $repo.allow_rebase_merge | Should -BeTrue + $repo.delete_branch_on_merge | Should -BeTrue + $repo.is_template | Should -BeTrue + } - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } - } + It 'Should have created a .gitignore file' { + { Get-GitHubContent -Uri $repo.svn_url -Path '.gitignore' } | Should -Not -Throw } - Context -Name 'When a TeamID is specified' -Fixture { - BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $mockTeamID=1 - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - TeamID = $mockTeamID - } - } + It 'Should have created a LICENSE file' { + { Get-GitHubContent -Uri $repo.svn_url -Path 'LICENSE' } | Should -Not -Throw + } - It 'Should throw the correct exception' { - $errorMessage = 'TeamId may only be specified when creating a repository under an organization.' - { New-GitHubRepository @newGitHubRepositoryParms } | Should -Throw $errorMessage + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } } - Context -Name 'When creating an organization repository' -Fixture { - - Context -Name 'When creating a public repository with default settings' -Fixture { - BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - OrganizationName = $script:organizationName - } - $repo = New-GitHubRepository @newGitHubRepositoryParms - } - - It 'Should return an object of the correct type' { - $repo | Should -BeOfType PSCustomObject - } - - It 'Should return the correct properties' { - $repo.name | Should -Be $repoName - $repo.private | Should -BeFalse - $repo.organization.login | Should -Be $script:organizationName - $repo.description | Should -BeNullOrEmpty - $repo.homepage | Should -BeNullOrEmpty - $repo.has_issues | Should -BeTrue - $repo.has_projects | Should -BeTrue - $repo.has_Wiki | Should -BeTrue - $repo.allow_squash_merge | Should -BeTrue - $repo.allow_merge_commit | Should -BeTrue - $repo.allow_rebase_merge | Should -BeTrue - $repo.delete_branch_on_merge | Should -BeFalse - $repo.is_template | Should -BeFalse + Context -Name 'When creating a repository with alternative Merge settings' -Fixture { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + DisallowSquashMerge = $true + DisallowMergeCommit = $false + DisallowRebaseMerge = $true } + $repo = New-GitHubRepository @newGitHubRepositoryParms + } - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } - } + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject } - Context -Name 'When creating a private repository with default settings' -Fixture { - BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - Private = $true - OrganizationName = $script:organizationName - } - $repo = New-GitHubRepository @newGitHubRepositoryParms - } + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.allow_squash_merge | Should -BeFalse + $repo.allow_merge_commit | Should -BeTrue + $repo.allow_rebase_merge | Should -BeFalse + } - It 'Should return an object of the correct type' { - $repo | Should -BeOfType PSCustomObject + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } + } + } - It 'Should return the correct properties' { - $repo.name | Should -Be $repoName - $repo.private | Should -BeTrue - $repo.organization.login | Should -Be $script:organizationName - $repo.description | Should -BeNullOrEmpty - $repo.homepage | Should -BeNullOrEmpty - $repo.has_issues | Should -BeTrue - $repo.has_projects | Should -BeTrue - $repo.has_Wiki | Should -BeTrue - $repo.allow_squash_merge | Should -BeTrue - $repo.allow_merge_commit | Should -BeTrue - $repo.allow_rebase_merge | Should -BeTrue - $repo.delete_branch_on_merge | Should -BeFalse - $repo.is_template | Should -BeFalse + Context -Name 'When a TeamID is specified' -Fixture { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $mockTeamID = 1 + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + TeamID = $mockTeamID } + } - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } - } + It 'Should throw the correct exception' { + $errorMessage = 'TeamId may only be specified when creating a repository under an organization.' + { New-GitHubRepository @newGitHubRepositoryParms } | Should -Throw $errorMessage } } } - Describe 'GitHubRepositories\New-GitHubRepositoryFromTemplate' { - BeforeAll { - $templateRepoName = ([Guid]::NewGuid().Guid) - $ownerName = $script:ownerName - $testGitIgnoreTemplate = (Get-GitHubGitIgnore)[0] - $testLicenseTemplate = (Get-GitHubLicense)[0].key - - $newGitHubRepositoryParms = @{ - RepositoryName = $templateRepoName - Description = $defaultRepoDesc - GitIgnoreTemplate = $testGitIgnoreTemplate - LicenseTemplate = $testLicenseTemplate - IsTemplate = $true - } - - $templateRepo = New-GitHubRepository @newGitHubRepositoryParms - } + Context -Name 'When creating an organization repository' -Fixture { - Context 'When creating a public repository from a template' { - BeforeAll { + Context -Name 'When creating a public repository with default settings' -Fixture { + BeforeAll -ScriptBlock { $repoName = ([Guid]::NewGuid().Guid) - $newRepoDesc = 'New Repo Description' - $newGitHubRepositoryFromTemplateParms = @{ - RepositoryName = $templateRepoName - OwnerName = $templateRepo.owner.login - TargetOwnerName = $ownerName - TargetRepositoryName = $repoName - Description = $newRepoDesc + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + OrganizationName = $script:organizationName } + $repo = New-GitHubRepository @newGitHubRepositoryParms + } - $repo = New-GitHubRepositoryFromTemplate @newGitHubRepositoryFromTemplateParms + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject } - It 'Should have the expected type and addititional properties' { - $repo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + It 'Should return the correct properties' { $repo.name | Should -Be $repoName $repo.private | Should -BeFalse - $repo.owner.login | Should -Be $script:ownerName - $repo.description | Should -Be $newRepoDesc + $repo.organization.login | Should -Be $script:organizationName + $repo.description | Should -BeNullOrEmpty + $repo.homepage | Should -BeNullOrEmpty + $repo.has_issues | Should -BeTrue + $repo.has_projects | Should -BeTrue + $repo.has_Wiki | Should -BeTrue + $repo.allow_squash_merge | Should -BeTrue + $repo.allow_merge_commit | Should -BeTrue + $repo.allow_rebase_merge | Should -BeTrue + $repo.delete_branch_on_merge | Should -BeFalse $repo.is_template | Should -BeFalse - $repo.RepositoryId | Should -Be $repo.id - $repo.RepositoryUrl | Should -Be $repo.html_url - } - - It 'Should have created a .gitignore file' { - { Get-GitHubContent -Uri $repo.svn_url -Path '.gitignore' } | Should -Not -Throw } - It 'Should have created a LICENSE file' { - { Get-GitHubContent -Uri $repo.svn_url -Path 'LICENSE' } | Should -Not -Throw - } - - AfterAll { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + AfterAll -ScriptBlock { + if ($repo) { Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } } - Context 'When creating a public repository from a template (via pipeline input)' { - BeforeAll { + Context -Name 'When creating a private repository with default settings' -Fixture { + BeforeAll -ScriptBlock { $repoName = ([Guid]::NewGuid().Guid) - $newRepoDesc = 'New Repo Description' - $newGitHubRepositoryFromTemplateParms = @{ - TargetOwnerName = $ownerName - TargetRepositoryName = $repoName - Description = $newRepoDesc + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + Private = $true + OrganizationName = $script:organizationName } + $repo = New-GitHubRepository @newGitHubRepositoryParms + } - $repo = $templateRepo | New-GitHubRepositoryFromTemplate @newGitHubRepositoryFromTemplateParms + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject } - It 'Should have the expected type and addititional properties' { - $repo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + It 'Should return the correct properties' { $repo.name | Should -Be $repoName - $repo.private | Should -BeFalse - $repo.owner.login | Should -Be $script:ownerName - $repo.description | Should -Be $newRepoDesc + $repo.private | Should -BeTrue + $repo.organization.login | Should -Be $script:organizationName + $repo.description | Should -BeNullOrEmpty + $repo.homepage | Should -BeNullOrEmpty + $repo.has_issues | Should -BeTrue + $repo.has_projects | Should -BeTrue + $repo.has_Wiki | Should -BeTrue + $repo.allow_squash_merge | Should -BeTrue + $repo.allow_merge_commit | Should -BeTrue + $repo.allow_rebase_merge | Should -BeTrue + $repo.delete_branch_on_merge | Should -BeFalse $repo.is_template | Should -BeFalse - $repo.RepositoryId | Should -Be $repo.id - $repo.RepositoryUrl | Should -Be $repo.html_url - } - - It 'Should have created a .gitignore file' { - { Get-GitHubContent -Uri $repo.svn_url -Path '.gitignore' } | Should -Not -Throw } - It 'Should have created a LICENSE file' { - { Get-GitHubContent -Uri $repo.svn_url -Path 'LICENSE' } | Should -Not -Throw - } - - AfterAll { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + AfterAll -ScriptBlock { + if ($repo) { Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } } + } +} - AfterAll { - if (Get-Variable -Name templateRepo -ErrorAction SilentlyContinue) - { - Remove-GitHubRepository -Uri $templateRepo.svn_url -Confirm:$false - } +Describe 'GitHubRepositories\New-GitHubRepositoryFromTemplate' { + BeforeAll { + $templateRepoName = ([Guid]::NewGuid().Guid) + $ownerName = $script:ownerName + $testGitIgnoreTemplate = (Get-GitHubGitIgnore)[0] + $testLicenseTemplate = (Get-GitHubLicense)[0].key + + $newGitHubRepositoryParms = @{ + RepositoryName = $templateRepoName + Description = $defaultRepoDesc + GitIgnoreTemplate = $testGitIgnoreTemplate + LicenseTemplate = $testLicenseTemplate + IsTemplate = $true } + + $templateRepo = New-GitHubRepository @newGitHubRepositoryParms } - Describe 'GitHubRepositories\Get-GitHubRepository' { - Context 'When getting a repository for the authenticated user' { - BeforeAll { - $publicRepo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) - $privateRepo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -Private + Context 'When creating a public repository from a template' { + BeforeAll { + $repoName = ([Guid]::NewGuid().Guid) + $newRepoDesc = 'New Repo Description' + $newGitHubRepositoryFromTemplateParms = @{ + RepositoryName = $templateRepoName + OwnerName = $templateRepo.owner.login + TargetOwnerName = $ownerName + TargetRepositoryName = $repoName + Description = $newRepoDesc } - Context 'When specify the visibility parameter' { - BeforeAll { - $publicRepos = Get-GitHubRepository -Visibility Public - $privateRepos = Get-GitHubRepository -Visibility Private - } + $repo = New-GitHubRepositoryFromTemplate @newGitHubRepositoryFromTemplateParms + } - It 'Should return objects of the correct type' { - $publicRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $privateRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - } + It 'Should have the expected type and addititional properties' { + $repo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $repo.name | Should -Be $repoName + $repo.private | Should -BeFalse + $repo.owner.login | Should -Be $script:ownerName + $repo.description | Should -Be $newRepoDesc + $repo.is_template | Should -BeFalse + $repo.RepositoryId | Should -Be $repo.id + $repo.RepositoryUrl | Should -Be $repo.html_url + } - It "Should return the correct membership" { - $publicRepo.name | Should -BeIn $publicRepos.name - $publicRepo.name | Should -Not -BeIn $privateRepos.name - $privateRepo.name | Should -BeIn $privateRepos.name - $privateRepo.name | Should -Not -BeIn $publicRepos.name - } - } + It 'Should have created a .gitignore file' { + { Get-GitHubContent -Uri $repo.svn_url -Path '.gitignore' } | Should -Not -Throw + } - Context 'When specifying the Type parameter' { - BeforeAll { - $publicRepos = Get-GitHubRepository -Type Public - $privateRepos = Get-GitHubRepository -Type Private - $ownerRepos = Get-GitHubRepository -Type Owner - $allRepos = Get-GitHubRepository -Type All - } + It 'Should have created a LICENSE file' { + { Get-GitHubContent -Uri $repo.svn_url -Path 'LICENSE' } | Should -Not -Throw + } - It 'Should return objects of the correct type' { - $publicRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $publicRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $ownerRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - } + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } - It "Should return the correct membership" { - $publicRepo.name | Should -BeIn $publicRepos.name - $publicRepo.name | Should -Not -BeIn $privateRepos.name - $privateRepo.name | Should -BeIn $privateRepos.name - $privateRepo.name | Should -Not -BeIn $publicRepos.name - $publicRepo.name | Should -BeIn $ownerRepos.name - $privateRepo.name | Should -BeIn $ownerRepos.name - $publicRepo.name | Should -BeIn $allRepos.name - $privateRepo.name | Should -BeIn $allRepos.name - } + Context 'When creating a public repository from a template (via pipeline input)' { + BeforeAll { + $repoName = ([Guid]::NewGuid().Guid) + $newRepoDesc = 'New Repo Description' + $newGitHubRepositoryFromTemplateParms = @{ + TargetOwnerName = $ownerName + TargetRepositoryName = $repoName + Description = $newRepoDesc } - Context 'When specifying the Affiliation parameter' { - BeforeAll { - $ownerRepos = Get-GitHubRepository -Affiliation Owner, Collaborator - } + $repo = $templateRepo | New-GitHubRepositoryFromTemplate @newGitHubRepositoryFromTemplateParms + } - It 'Should return objects of the correct type' { - $ownerRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - } + It 'Should have the expected type and addititional properties' { + $repo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $repo.name | Should -Be $repoName + $repo.private | Should -BeFalse + $repo.owner.login | Should -Be $script:ownerName + $repo.description | Should -Be $newRepoDesc + $repo.is_template | Should -BeFalse + $repo.RepositoryId | Should -Be $repo.id + $repo.RepositoryUrl | Should -Be $repo.html_url + } - It "Should return the correct membership" { - $publicRepo.name | Should -BeIn $ownerRepos.name - $privateRepo.name | Should -BeIn $ownerRepos.name - } - } + It 'Should have created a .gitignore file' { + { Get-GitHubContent -Uri $repo.svn_url -Path '.gitignore' } | Should -Not -Throw + } - Context 'When specifying the Sort and Direction parameters' { - BeforeAll { - $sortedRepos = Get-GitHubRepository -Sort 'FullName' - $sortedDescendingRepos = Get-GitHubRepository -Sort FullName -Direction Descending + It 'Should have created a LICENSE file' { + { Get-GitHubContent -Uri $repo.svn_url -Path 'LICENSE' } | Should -Not -Throw + } - $sortedRepoFullNames = [System.Collections.ArrayList]$sortedRepos.full_Name - $sortedRepoFullNames.Sort([System.StringComparer]::OrdinalIgnoreCase) - $sortedDescendingRepoFullNames = [System.Collections.ArrayList]$sortedDescendingRepos.full_Name - $sortedDescendingRepoFullNames.Sort([System.StringComparer]::OrdinalIgnoreCase) - $sortedDescendingRepoFullNames.Reverse() - } + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } - It 'Should return objects of the correct type' { - $sortedRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $sortedDescendingRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - } + AfterAll { + if (Get-Variable -Name templateRepo -ErrorAction SilentlyContinue) + { + Remove-GitHubRepository -Uri $templateRepo.svn_url -Confirm:$false + } + } +} - It "Should return the correct membership order" { - for ($i = 1; $i -le $sortedRepos.count; $i++) - { - $sortedRepos[$i].full_name | Should -Be $sortedRepoFullNames[$i] - $sortedDescendingRepos[$i].full_name | Should -Be $sortedDescendingRepoFullNames[$i] - } - } - } +Describe 'GitHubRepositories\Get-GitHubRepository' { + Context 'When getting a repository for the authenticated user' { + BeforeAll { + $publicRepo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + $privateRepo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -Private + } - Context 'When Specifying an invalid Visibility parameter set' { - It 'Should throw the correct exception' { - $errorMessage = 'Unable to specify -Type when using -Visibility and/or -Affiliation.' - { Get-GitHubRepository -Type All -Visibility All } | Should -Throw $errorMessage - } + Context 'When specify the visibility parameter' { + BeforeAll { + $publicRepos = Get-GitHubRepository -Visibility Public + $privateRepos = Get-GitHubRepository -Visibility Private } - Context 'When Specifying an invalid Affiliation parameter set' { - It 'Should throw the correct exception' { - $errorMessage = 'Unable to specify -Type when using -Visibility and/or -Affiliation.' - { Get-GitHubRepository -Type All -Visibility All } | Should -Throw $errorMessage - } + It 'Should return objects of the correct type' { + $publicRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $privateRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' } - AfterAll { - Remove-GitHubRepository -Uri $publicRepo.svn_url -Force - Remove-GitHubRepository -Uri $privateRepo.svn_url -Force + It "Should return the correct membership" { + $publicRepo.name | Should -BeIn $publicRepos.name + $publicRepo.name | Should -Not -BeIn $privateRepos.name + $privateRepo.name | Should -BeIn $privateRepos.name + $privateRepo.name | Should -Not -BeIn $publicRepos.name } } - Context 'When getting a repository for a specified owner' { + Context 'When specifying the Type parameter' { BeforeAll { - $ownerName = 'octocat' - $repos = Get-GitHubRepository -OwnerName $ownerName + $publicRepos = Get-GitHubRepository -Type Public + $privateRepos = Get-GitHubRepository -Type Private + $ownerRepos = Get-GitHubRepository -Type Owner + $allRepos = Get-GitHubRepository -Type All } It 'Should return objects of the correct type' { - $repos | Should -BeOfType PSCustomObject + $publicRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $publicRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $ownerRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' } - It "Should return one or more results" { - $repos.Count | Should -BeGreaterOrEqual 1 - } - - It 'Should return the correct properties' { - foreach ($repo in $repos) - { - $repo.owner.login | Should -Be $ownerName - } + It "Should return the correct membership" { + $publicRepo.name | Should -BeIn $publicRepos.name + $publicRepo.name | Should -Not -BeIn $privateRepos.name + $privateRepo.name | Should -BeIn $privateRepos.name + $privateRepo.name | Should -Not -BeIn $publicRepos.name + $publicRepo.name | Should -BeIn $ownerRepos.name + $privateRepo.name | Should -BeIn $ownerRepos.name + $publicRepo.name | Should -BeIn $allRepos.name + $privateRepo.name | Should -BeIn $allRepos.name } } - Context 'When getting a repository for a specified organization' { + Context 'When specifying the Affiliation parameter' { BeforeAll { - $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName ([Guid]::NewGuid().Guid) + $ownerRepos = Get-GitHubRepository -Affiliation Owner, Collaborator } - It "Should have results for the organization" { - $repos = Get-GitHubRepository -OrganizationName $script:organizationName -Type All - $repo.name | Should -BeIn $repos.name + It 'Should return objects of the correct type' { + $ownerRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + It "Should return the correct membership" { + $publicRepo.name | Should -BeIn $ownerRepos.name + $privateRepo.name | Should -BeIn $ownerRepos.name } } - Context 'When getting all public repositories' { + Context 'When specifying the Sort and Direction parameters' { BeforeAll { - $repo1 = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) - $repo2 = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) - $repos = Get-GitHubRepository -GetAllPublicRepositories -Since $repo1.id - } + $sortedRepos = Get-GitHubRepository -Sort 'FullName' + $sortedDescendingRepos = Get-GitHubRepository -Sort FullName -Direction Descending - It 'Should return an object of the correct type' { - $repos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $sortedRepoFullNames = [System.Collections.ArrayList]$sortedRepos.full_Name + $sortedRepoFullNames.Sort([System.StringComparer]::OrdinalIgnoreCase) + $sortedDescendingRepoFullNames = [System.Collections.ArrayList]$sortedDescendingRepos.full_Name + $sortedDescendingRepoFullNames.Sort([System.StringComparer]::OrdinalIgnoreCase) + $sortedDescendingRepoFullNames.Reverse() } - It 'Should return at least one result' { - $repos.count | Should -BeGreaterOrEqual 1 + It 'Should return objects of the correct type' { + $sortedRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $sortedDescendingRepos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' } - It "Should return the correct membership" { - $repo2.name | Should -BeIn $repos.name + It "Should return the correct membership order" { + for ($i = 1; $i -le $sortedRepos.count; $i++) + { + $sortedRepos[$i].full_name | Should -Be $sortedRepoFullNames[$i] + $sortedDescendingRepos[$i].full_name | Should -Be $sortedDescendingRepoFullNames[$i] + } } + } - AfterAll { - Remove-GitHubRepository -Uri $repo1.svn_url -Force - Remove-GitHubRepository -Uri $repo2.svn_url -Force + Context 'When Specifying an invalid Visibility parameter set' { + It 'Should throw the correct exception' { + $errorMessage = 'Unable to specify -Type when using -Visibility and/or -Affiliation.' + { Get-GitHubRepository -Type All -Visibility All } | Should -Throw $errorMessage } } - Context 'When getting a specific repository' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $newGitHubRepositoryParms = @{ - RepositoryName = $repoName - Description = $defaultRepoDesc - HomePage = $defaultRepoHomePage - } - - $repo = New-GitHubRepository @newGitHubRepositoryParms + Context 'When Specifying an invalid Affiliation parameter set' { + It 'Should throw the correct exception' { + $errorMessage = 'Unable to specify -Type when using -Visibility and/or -Affiliation.' + { Get-GitHubRepository -Type All -Visibility All } | Should -Throw $errorMessage } + } - Context 'When specifiying the Uri parameter' { - BeforeAll { - $uriRepo = Get-GitHubRepository -Uri $repo.svn_url - } + AfterAll { + Remove-GitHubRepository -Uri $publicRepo.svn_url -Force + Remove-GitHubRepository -Uri $privateRepo.svn_url -Force + } + } - It 'Should return an object of the correct type' { - $uriRepo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - } + Context 'When getting a repository for a specified owner' { + BeforeAll { + $ownerName = 'octocat' + $repos = Get-GitHubRepository -OwnerName $ownerName + } - It 'Should return a single result' { - $uriRepo | Should -HaveCount 1 - } + It 'Should return objects of the correct type' { + $repos | Should -BeOfType PSCustomObject + } - It 'Should return the correct properties' { - $uriRepo.name | Should -Be $repoName - $uriRepo.description | Should -Be $defaultRepoDesc - $uriRepo.homepage | Should -Be $defaultRepoHomePage - } + It "Should return one or more results" { + $repos.Count | Should -BeGreaterOrEqual 1 + } + + It 'Should return the correct properties' { + foreach ($repo in $repos) + { + $repo.owner.login | Should -Be $ownerName } + } + } - Context 'When specifying the Owner and RepositoryName parameters' { - BeforeAll { - $elementsRepo = Get-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name - } + Context 'When getting a repository for a specified organization' { + BeforeAll { + $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName ([Guid]::NewGuid().Guid) + } - It 'Should return an object of the correct type' { - $uriRepo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - } + It "Should have results for the organization" { + $repos = Get-GitHubRepository -OrganizationName $script:organizationName -Type All + $repo.name | Should -BeIn $repos.name + } - It 'Should return a single result' { - $uriRepo | Should -HaveCount 1 - } + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } - It 'Should return the correct properties' { - $uriRepo.name | Should -Be $repoName - $uriRepo.description | Should -Be $defaultRepoDesc - $uriRepo.homepage | Should -Be $defaultRepoHomePage - } + Context 'When getting all public repositories' { + BeforeAll { + $repo1 = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + $repo2 = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + $repos = Get-GitHubRepository -GetAllPublicRepositories -Since $repo1.id + } - Context 'When specifying additional invalid parameters' { - It 'Should throw the correct exception' { - $errorMessage = 'Unable to specify -Type, -Sort and/or -Direction when retrieving a specific repository.' - { Get-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name -Type All } | - Should -Throw $errorMessage - } - } - } + It 'Should return an object of the correct type' { + $repos[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + } - Context 'When specifying only the Repository parameter' { - It 'Should throw the correct exception' { - $errorMessage = 'OwnerName could not be determined.' - { Get-GitHubRepository -RepositoryName $repo.name } | Should -Throw $errorMessage - } - } + It 'Should return at least one result' { + $repos.count | Should -BeGreaterOrEqual 1 + } - AfterAll { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } - } + It "Should return the correct membership" { + $repo2.name | Should -BeIn $repos.name + } + + AfterAll { + Remove-GitHubRepository -Uri $repo1.svn_url -Force + Remove-GitHubRepository -Uri $repo2.svn_url -Force } } - Describe 'GitHubRepositories\Delete-GitHubRepository' { + Context 'When getting a specific repository' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + Description = $defaultRepoDesc + HomePage = $defaultRepoHomePage + } + + $repo = New-GitHubRepository @newGitHubRepositoryParms + } + + Context 'When specifiying the Uri parameter' { + BeforeAll { + $uriRepo = Get-GitHubRepository -Uri $repo.svn_url + } - Context -Name 'When deleting a repository' -Fixture { - BeforeEach -ScriptBlock { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -Description $defaultRepoDesc -AutoInit + It 'Should return an object of the correct type' { + $uriRepo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' } - It 'Should get no content using -Confirm:$false' { - Remove-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name -Confirm:$false - { Get-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name } | Should -Throw + It 'Should return a single result' { + $uriRepo | Should -HaveCount 1 } - It 'Should get no content using -Force' { - Remove-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name -Force - { Get-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name } | Should -Throw + It 'Should return the correct properties' { + $uriRepo.name | Should -Be $repoName + $uriRepo.description | Should -Be $defaultRepoDesc + $uriRepo.homepage | Should -Be $defaultRepoHomePage } } - } - Describe 'GitHubRepositories\Rename-GitHubRepository' { + Context 'When specifying the Owner and RepositoryName parameters' { + BeforeAll { + $uriRepo = Get-GitHubRepository -Uri $repo.svn_url + $elementsRepo = Get-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name + } - Context -Name 'When renaming a repository' -Fixture { - BeforeEach -Scriptblock { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - $suffixToAddToRepo = "_renamed" - $newRepoName = "$($repo.name)$suffixToAddToRepo" + It 'Should return an object of the correct type' { + $uriRepo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' } - It "Should have the expected new repository name - by URI" { - $renamedRepo = Rename-GitHubRepository -Uri ($repo.RepositoryUrl) -NewName $newRepoName -Force -PassThru - $renamedRepo.name | Should -Be $newRepoName + It 'Should return a single result' { + $uriRepo | Should -HaveCount 1 } - It "Should have the expected new repository name - by Elements" { - $renamedRepo = Rename-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name -NewName $newRepoName -Confirm:$false -PassThru - $renamedRepo.name | Should -Be $newRepoName + It 'Should return the correct properties' { + $uriRepo.name | Should -Be $repoName + $uriRepo.description | Should -Be $defaultRepoDesc + $uriRepo.homepage | Should -Be $defaultRepoHomePage } - It "Should work via the pipeline" { - $renamedRepo = $repo | Rename-GitHubRepository -NewName $newRepoName -Confirm:$false -PassThru - $renamedRepo.name | Should -Be $newRepoName - $renamedRepo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + Context 'When specifying additional invalid parameters' { + It 'Should throw the correct exception' { + $errorMessage = 'Unable to specify -Type, -Sort and/or -Direction when retrieving a specific repository.' + { Get-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name -Type All } | + Should -Throw $errorMessage + } } + } - It "Should be possible to rename with Set-GitHubRepository too" { - $renamedRepo = $repo | Set-GitHubRepository -NewName $newRepoName -Confirm:$false -PassThru - $renamedRepo.name | Should -Be $newRepoName - $renamedRepo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + Context 'When specifying only the Repository parameter' { + It 'Should throw the correct exception' { + $errorMessage = 'OwnerName could not be determined.' + { Get-GitHubRepository -RepositoryName $repo.name } | Should -Throw $errorMessage } + } - AfterEach -Scriptblock { - Remove-GitHubRepository -Uri "$($repo.svn_url)$suffixToAddToRepo" -Confirm:$false + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } } +} - Describe 'GitHubRepositories\Set-GitHubRepository' { +Describe 'GitHubRepositories\Delete-GitHubRepository' { - Context -Name 'When updating a public repository' -Fixture { - BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $repo = New-GitHubRepository -RepositoryName $repoName - } - - Context -Name 'When updating a repository with all possible settings' { - BeforeAll -ScriptBlock { - $updateGithubRepositoryParms = @{ - OwnerName = $repo.owner.login - RepositoryName = $repoName - Private = $true - Description = $defaultRepoDesc - HomePage = $defaultRepoHomePage - NoIssues = $true - NoProjects = $true - NoWiki = $true - DisallowSquashMerge = $true - DisallowMergeCommit = $true - DisallowRebaseMerge = $false - DeleteBranchOnMerge = $true - IsTemplate = $true - } - - $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru - } - - It 'Should return an object of the correct type' { - $updatedRepo | Should -BeOfType PSCustomObject - } + Context -Name 'When deleting a repository' -Fixture { + BeforeEach -ScriptBlock { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -Description $defaultRepoDesc -AutoInit + } - It 'Should return the correct properties' { - $updatedRepo.name | Should -Be $repoName - $updatedRepo.private | Should -BeTrue - $updatedRepo.description | Should -Be $defaultRepoDesc - $updatedRepo.homepage | Should -Be $defaultRepoHomePage - $updatedRepo.has_issues | Should -BeFalse - $updatedRepo.has_projects | Should -BeFalse - $updatedRepo.has_Wiki | Should -BeFalse - $updatedRepo.allow_squash_merge | Should -BeFalse - $updatedRepo.allow_merge_commit | Should -BeFalse - $updatedRepo.allow_rebase_merge | Should -BeTrue - $updatedRepo.delete_branch_on_merge | Should -BeTrue - $updatedRepo.is_template | Should -BeTrue - } - } + It 'Should get no content using -Confirm:$false' { + Remove-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name -Confirm:$false + { Get-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name } | Should -Throw + } - Context -Name 'When updating a repository with alternative Merge settings' { - BeforeAll -ScriptBlock { - $updateGithubRepositoryParms = @{ - OwnerName = $repo.owner.login - RepositoryName = $repoName - DisallowSquashMerge = $true - DisallowMergeCommit = $false - DisallowRebaseMerge = $true - } + It 'Should get no content using -Force' { + Remove-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name -Force + { Get-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name } | Should -Throw + } + } +} - $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru - } +Describe 'GitHubRepositories\Rename-GitHubRepository' { + Context -Name 'When renaming a repository' -Fixture { + BeforeEach -Scriptblock { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + $suffixToAddToRepo = "_renamed" + $newRepoName = "$($repo.name)$suffixToAddToRepo" + } - It 'Should return an object of the correct type' { - $updatedRepo | Should -BeOfType PSCustomObject - } + It "Should have the expected new repository name - by URI" { + $renamedRepo = Rename-GitHubRepository -Uri ($repo.RepositoryUrl) -NewName $newRepoName -Force -PassThru + $renamedRepo.name | Should -Be $newRepoName + } - It 'Should return the correct properties' { - $updatedRepo.name | Should -Be $repoName - $updatedRepo.allow_squash_merge | Should -BeFalse - $updatedRepo.allow_merge_commit | Should -BeTrue - $updatedRepo.allow_rebase_merge | Should -BeFalse - } - } + It "Should have the expected new repository name - by Elements" { + $renamedRepo = Rename-GitHubRepository -OwnerName $repo.owner.login -RepositoryName $repo.name -NewName $newRepoName -Confirm:$false -PassThru + $renamedRepo.name | Should -Be $newRepoName + } - Context -Name 'When updating a repository with the Archive setting' { - BeforeAll -ScriptBlock { - $updateGithubRepositoryParms = @{ - OwnerName = $repo.owner.login - RepositoryName = $repoName - Archived = $true - } + It "Should work via the pipeline" { + $renamedRepo = $repo | Rename-GitHubRepository -NewName $newRepoName -Confirm:$false -PassThru + $renamedRepo.name | Should -Be $newRepoName + $renamedRepo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + } - $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru - } + It "Should be possible to rename with Set-GitHubRepository too" { + $renamedRepo = $repo | Set-GitHubRepository -NewName $newRepoName -Confirm:$false -PassThru + $renamedRepo.name | Should -Be $newRepoName + $renamedRepo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + } - It 'Should return an object of the correct type' { - $updatedRepo | Should -BeOfType PSCustomObject - } + AfterEach -Scriptblock { + Remove-GitHubRepository -Uri "$($repo.svn_url)$suffixToAddToRepo" -Confirm:$false + } + } +} - It 'Should return the correct properties' { - $updatedRepo.name | Should -Be $repoName - $updatedRepo.archived | Should -BeTrue - } - } +Describe 'GitHubRepositories\Set-GitHubRepository' { - AfterAll -ScriptBlock { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } - } + Context -Name 'When updating a public repository' -Fixture { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $repo = New-GitHubRepository -RepositoryName $repoName } - Context -Name 'When updating a private repository' -Fixture { + Context -Name 'When updating a repository with all possible settings' { BeforeAll -ScriptBlock { - $repoName = ([Guid]::NewGuid().Guid) - $repo = New-GitHubRepository -RepositoryName $repoName -Private - $updateGithubRepositoryParms = @{ OwnerName = $repo.owner.login RepositoryName = $repoName - Private = $false + Private = $true + Description = $defaultRepoDesc + HomePage = $defaultRepoHomePage + NoIssues = $true + NoProjects = $true + NoWiki = $true + DisallowSquashMerge = $true + DisallowMergeCommit = $true + DisallowRebaseMerge = $false + DeleteBranchOnMerge = $true + IsTemplate = $true } $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru @@ -829,175 +741,227 @@ try It 'Should return the correct properties' { $updatedRepo.name | Should -Be $repoName - $updatedRepo.private | Should -BeFalse + $updatedRepo.private | Should -BeTrue + $updatedRepo.description | Should -Be $defaultRepoDesc + $updatedRepo.homepage | Should -Be $defaultRepoHomePage + $updatedRepo.has_issues | Should -BeFalse + $updatedRepo.has_projects | Should -BeFalse + $updatedRepo.has_Wiki | Should -BeFalse + $updatedRepo.allow_squash_merge | Should -BeFalse + $updatedRepo.allow_merge_commit | Should -BeFalse + $updatedRepo.allow_rebase_merge | Should -BeTrue + $updatedRepo.delete_branch_on_merge | Should -BeTrue + $updatedRepo.is_template | Should -BeTrue } + } - AfterAll -ScriptBlock { - if ($repo) - { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + Context -Name 'When updating a repository with alternative Merge settings' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + DisallowSquashMerge = $true + DisallowMergeCommit = $false + DisallowRebaseMerge = $true } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru } - } - } - Describe 'Common user repository pipeline scenarios' { - Context 'For authenticated user' { - BeforeAll -Scriptblock { - $repo = ([Guid]::NewGuid().Guid) | New-GitHubRepository -AutoInit + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject } - It "Should have expected additional properties and type after creation" { - $repo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $repo.RepositoryUrl | Should -Be (Join-GitHubUri -OwnerName $script:ownerName -RepositoryName $repo.name) - $repo.RepositoryId | Should -Be $repo.id - $repo.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_squash_merge | Should -BeFalse + $updatedRepo.allow_merge_commit | Should -BeTrue + $updatedRepo.allow_rebase_merge | Should -BeFalse } + } - It "Should have expected additional properties and type after creation" { - $returned = ($repo | Get-GitHubRepository) - $returned.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $returned.RepositoryUrl | Should -Be (Join-GitHubUri -OwnerName $script:ownerName -RepositoryName $returned.name) - $returned.RepositoryId | Should -Be $returned.id - $returned.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + Context -Name 'When updating a repository with the Archive setting' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + Archived = $true + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru } - It "Should get the repository by user" { - $repos = @($script:ownerName | Get-GitHubUser | Get-GitHubRepository) - $repos.name | Should -Contain $repo.name + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject } - It 'Should be removable by the pipeline' { - ($repo | Remove-GitHubRepository -Confirm:$false) | Should -BeNullOrEmpty + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.archived | Should -BeTrue + } + } - { $repo | Get-GitHubRepository } | Should -Throw + AfterAll -ScriptBlock { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } } - Describe 'Common organization repository pipeline scenarios' { - Context 'For organization' { - BeforeAll -Scriptblock { - $org = [PSCustomObject]@{'OrganizationName' = $script:organizationName} - $repo = $org | New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - } + Context -Name 'When updating a private repository' -Fixture { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $repo = New-GitHubRepository -RepositoryName $repoName -Private - It "Should have expected additional properties and type after creation" { - $repo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $repo.RepositoryUrl | Should -Be (Join-GitHubUri -OwnerName $script:organizationName -RepositoryName $repo.name) - $repo.RepositoryId | Should -Be $repo.id - $repo.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $repo.organization.PSObject.TypeNames[0] | Should -Be 'GitHub.Organization' - $repo.organization.OrganizationName | Should -Be $repo.organization.login - $repo.organization.OrganizationId | Should -Be $repo.organization.id + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + Private = $false } - It "Should have expected additional properties and type after creation" { - $returned = ($repo | Get-GitHubRepository) - $returned.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $returned.RepositoryUrl | Should -Be (Join-GitHubUri -OwnerName $script:organizationName -RepositoryName $returned.name) - $returned.RepositoryId | Should -Be $returned.id - $returned.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - $returned.organization.PSObject.TypeNames[0] | Should -Be 'GitHub.Organization' - $returned.organization.OrganizationName | Should -Be $returned.organization.login - $returned.organization.OrganizationId | Should -Be $returned.organization.id - } + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } - It 'Should be removable by the pipeline' { - ($repo | Remove-GitHubRepository -Confirm:$false) | Should -BeNullOrEmpty - { $repo | Get-GitHubRepository } | Should -Throw - } + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject } - } - Describe 'GitHubRepositories\Get-GitHubRepositoryTopic' { + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.private | Should -BeFalse + } - Context -Name 'When getting a repository topic' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) - Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Name $defaultRepoTopic - $topic = Get-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } + } + } +} - It 'Should have the expected topic' { - Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Topic $defaultRepoTopic - $topic = Get-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name - - $topic.names | Should -Be $defaultRepoTopic - } +Describe 'Common user repository pipeline scenarios' { + Context 'For authenticated user' { + BeforeAll -Scriptblock { + $repo = ([Guid]::NewGuid().Guid) | New-GitHubRepository -AutoInit + } - It 'Should have no topics' { - Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Clear - $topic = Get-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name + It "Should have expected additional properties and type after creation" { + $repo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $repo.RepositoryUrl | Should -Be (Join-GitHubUri -OwnerName $script:ownerName -RepositoryName $repo.name) + $repo.RepositoryId | Should -Be $repo.id + $repo.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - $topic.names | Should -BeNullOrEmpty - } + It "Should have expected additional properties and type after creation" { + $returned = ($repo | Get-GitHubRepository) + $returned.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $returned.RepositoryUrl | Should -Be (Join-GitHubUri -OwnerName $script:ownerName -RepositoryName $returned.name) + $returned.RepositoryId | Should -Be $returned.id + $returned.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } - It 'Should have the expected topic (using repo via pipeline)' { - $repo | Set-GitHubRepositoryTopic -Topic $defaultRepoTopic - $topic = $repo | Get-GitHubRepositoryTopic + It "Should get the repository by user" { + $repos = @($script:ownerName | Get-GitHubUser | Get-GitHubRepository) + $repos.name | Should -Contain $repo.name + } - $topic.names | Should -Be $defaultRepoTopic - $topic.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryTopic' - $topic.RepositoryUrl | Should -Be $repo.RepositoryUrl - } + It 'Should be removable by the pipeline' { + ($repo | Remove-GitHubRepository -Confirm:$false) | Should -BeNullOrEmpty - It 'Should have the expected topic (using topic via pipeline)' { - $defaultRepoTopic | Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name - $topic = $repo | Get-GitHubRepositoryTopic + { $repo | Get-GitHubRepository } | Should -Throw + } + } +} - $topic.names | Should -Be $defaultRepoTopic - $topic.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryTopic' - $topic.RepositoryUrl | Should -Be $repo.RepositoryUrl - } +Describe 'Common organization repository pipeline scenarios' { + Context 'For organization' { + BeforeAll -Scriptblock { + $org = [PSCustomObject]@{'OrganizationName' = $script:organizationName } + $repo = $org | New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - It 'Should have the expected multi-topic (using topic via pipeline)' { - $topics = @('one', 'two') - $topics | Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name - $result = $repo | Get-GitHubRepositoryTopic + It "Should have expected additional properties and type after creation" { + $repo.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $repo.RepositoryUrl | Should -Be (Join-GitHubUri -OwnerName $script:organizationName -RepositoryName $repo.name) + $repo.RepositoryId | Should -Be $repo.id + $repo.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $repo.organization.PSObject.TypeNames[0] | Should -Be 'GitHub.Organization' + $repo.organization.OrganizationName | Should -Be $repo.organization.login + $repo.organization.OrganizationId | Should -Be $repo.organization.id + } - $result.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryTopic' - $result.RepositoryUrl | Should -Be $repo.RepositoryUrl - $result.names.count | Should -Be $topics.Count - foreach ($topic in $topics) - { - $result.names | Should -Contain $topic - } - } + It "Should have expected additional properties and type after creation" { + $returned = ($repo | Get-GitHubRepository) + $returned.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $returned.RepositoryUrl | Should -Be (Join-GitHubUri -OwnerName $script:organizationName -RepositoryName $returned.name) + $returned.RepositoryId | Should -Be $returned.id + $returned.owner.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + $returned.organization.PSObject.TypeNames[0] | Should -Be 'GitHub.Organization' + $returned.organization.OrganizationName | Should -Be $returned.organization.login + $returned.organization.OrganizationId | Should -Be $returned.organization.id + } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + It 'Should be removable by the pipeline' { + ($repo | Remove-GitHubRepository -Confirm:$false) | Should -BeNullOrEmpty + { $repo | Get-GitHubRepository } | Should -Throw } } +} - Describe 'GitHubRepositories\Set-GitHubRepositoryTopic' { +Describe 'GitHubRepositories\Get-GitHubRepositoryTopic' { + + Context -Name 'When getting a repository topic' { BeforeAll { $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) - $topic = Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Name $defaultRepoTopic -PassThru + Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Name $defaultRepoTopic + $topic = Get-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name } - Context -Name 'When setting a repository topic' { - It 'Should return an object of the correct type' { - $topic | Should -BeOfType PSCustomObject - } + It 'Should have the expected topic' { + Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Topic $defaultRepoTopic + $topic = Get-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name - It 'Should return the correct properties' { - $defaultRepoTopic | Should -BeIn $topic.names - } + $topic.names | Should -Be $defaultRepoTopic } - Context -Name 'When clearing all repository topics' { - BeforeAll { - $topic = Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Clear -PassThru - } + It 'Should have no topics' { + Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Clear + $topic = Get-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name - It 'Should return an object of the correct type' { - $topic.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryTopic' - } + $topic.names | Should -BeNullOrEmpty + } - It 'Should return the correct properties' { - $topic.names | Should -BeNullOrEmpty + It 'Should have the expected topic (using repo via pipeline)' { + $repo | Set-GitHubRepositoryTopic -Topic $defaultRepoTopic + $topic = $repo | Get-GitHubRepositoryTopic + + $topic.names | Should -Be $defaultRepoTopic + $topic.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryTopic' + $topic.RepositoryUrl | Should -Be $repo.RepositoryUrl + } + + It 'Should have the expected topic (using topic via pipeline)' { + $defaultRepoTopic | Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name + $topic = $repo | Get-GitHubRepositoryTopic + + $topic.names | Should -Be $defaultRepoTopic + $topic.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryTopic' + $topic.RepositoryUrl | Should -Be $repo.RepositoryUrl + } + + It 'Should have the expected multi-topic (using topic via pipeline)' { + $topics = @('one', 'two') + $topics | Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name + $result = $repo | Get-GitHubRepositoryTopic + + $result.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryTopic' + $result.RepositoryUrl | Should -Be $repo.RepositoryUrl + $result.names.count | Should -Be $topics.Count + foreach ($topic in $topics) + { + $result.names | Should -Contain $topic } } @@ -1005,794 +969,828 @@ try Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } +} - Describe 'GitHubRepositories\Get-GitHubRepositoryContributor' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit - } +Describe 'GitHubRepositories\Set-GitHubRepositoryTopic' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + $topic = Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Name $defaultRepoTopic -PassThru + } - Context 'When getting GitHub Repository Contributors' { - BeforeAll { - $getGitHubRepositoryContributorParms = @{ - OwnerName = $repo.owner.login - RepositoryName = $repoName - } + Context -Name 'When setting a repository topic' { + It 'Should return an object of the correct type' { + $topic | Should -BeOfType PSCustomObject + } - $contributors = @(Get-GitHubRepositoryContributor @getGitHubRepositoryContributorParms) - } + It 'Should return the correct properties' { + $defaultRepoTopic | Should -BeIn $topic.names + } + } - It 'Should return objects of the correct type' { - $contributors[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryContributor' - } + Context -Name 'When clearing all repository topics' { + BeforeAll { + $topic = Set-GitHubRepositoryTopic -OwnerName $repo.owner.login -RepositoryName $repo.name -Clear -PassThru + } - It 'Should return expected number of contributors' { - $contributors.Count | Should -Be 1 - } + It 'Should return an object of the correct type' { + $topic.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryTopic' + } - It "Should return the correct membership" { - $repo.owner.login | Should -BeIn $contributors.login - } + It 'Should return the correct properties' { + $topic.names | Should -BeNullOrEmpty } + } - # TODO: This test has been disabled because GitHub isn't returning back a result after over - # one hour of retries. See here for more info: - # https://github.community/t/unable-to-retrieve-contributor-statistics-for-a-brand-new-repo/136658 - # - # Context 'When getting Github Repository Contributors with Statistics' { - # BeforeAll { - # $getGitHubRepositoryContributorParms = @{ - # OwnerName = $repo.owner.login - # RepositoryName = $repoName - # IncludeStatistics = $true - # } + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } +} - # $contributors = @(Get-GitHubRepositoryContributor @getGitHubRepositoryContributorParms) - # } +Describe 'GitHubRepositories\Get-GitHubRepositoryContributor' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit + } - # It 'Should return objects of the correct type' { - # $contributors[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryContributorStatistics' - # $contributors[0].author.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - # } + Context 'When getting GitHub Repository Contributors' { + BeforeAll { + $getGitHubRepositoryContributorParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + } - # It 'Should return expected number of contributors' { - # $contributors.Count | Should -Be 1 - # } + $contributors = @(Get-GitHubRepositoryContributor @getGitHubRepositoryContributorParms) + } - # It 'Should return the correct membership' { - # $repo.owner.login | Should -BeIn $contributors.author.login - # } + It 'Should return objects of the correct type' { + $contributors[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryContributor' + } - # It 'Should return the correct properties' { - # $contributors.weeks | Should -Not -BeNullOrEmpty - # } - # } + It 'Should return expected number of contributors' { + $contributors.Count | Should -Be 1 + } - Context 'When getting Github Repository Contributors including Anonymous' { - BeforeAll { - $getGitHubRepositoryContributorParms = @{ - OwnerName = $repo.owner.login - RepositoryName = $repoName - IncludeAnonymousContributors = $true - } + It "Should return the correct membership" { + $repo.owner.login | Should -BeIn $contributors.login + } + } - $contributors = @(Get-GitHubRepositoryContributor @getGitHubRepositoryContributorParms) + # TODO: This test has been disabled because GitHub isn't returning back a result after over + # one hour of retries. See here for more info: + # https://github.community/t/unable-to-retrieve-contributor-statistics-for-a-brand-new-repo/136658 + # + # Context 'When getting Github Repository Contributors with Statistics' { + # BeforeAll { + # $getGitHubRepositoryContributorParms = @{ + # OwnerName = $repo.owner.login + # RepositoryName = $repoName + # IncludeStatistics = $true + # } + + # $contributors = @(Get-GitHubRepositoryContributor @getGitHubRepositoryContributorParms) + # } + + # It 'Should return objects of the correct type' { + # $contributors[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryContributorStatistics' + # $contributors[0].author.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + # } + + # It 'Should return expected number of contributors' { + # $contributors.Count | Should -Be 1 + # } + + # It 'Should return the correct membership' { + # $repo.owner.login | Should -BeIn $contributors.author.login + # } + + # It 'Should return the correct properties' { + # $contributors.weeks | Should -Not -BeNullOrEmpty + # } + # } + + Context 'When getting Github Repository Contributors including Anonymous' { + BeforeAll { + $getGitHubRepositoryContributorParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + IncludeAnonymousContributors = $true } - It 'Should return objects of the correct type' { - $contributors[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryContributor' - } + $contributors = @(Get-GitHubRepositoryContributor @getGitHubRepositoryContributorParms) + } - It 'Should return at least one result' { - $contributors.count | Should -BeGreaterOrEqual 1 - } + It 'Should return objects of the correct type' { + $contributors[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryContributor' + } - It 'Should return the correct membership' { - $repo.owner.login | Should -BeIn $contributors.login - } + It 'Should return at least one result' { + $contributors.count | Should -BeGreaterOrEqual 1 } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + It 'Should return the correct membership' { + $repo.owner.login | Should -BeIn $contributors.login } } - Describe 'GitHubRepositories\Get-GitHubRepositoryCollaborator' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit - } + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } +} - Context 'When getting GitHub Repository Collaborators' { - BeforeAll { - $getGitHubRepositoryCollaboratorParms = @{ - OwnerName = $repo.owner.login - RepositoryName = $repoName - } +Describe 'GitHubRepositories\Get-GitHubRepositoryCollaborator' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repoName -AutoInit + } - $collaborators = @(Get-GitHubRepositoryCollaborator @getGitHubRepositoryCollaboratorParms) + Context 'When getting GitHub Repository Collaborators' { + BeforeAll { + $getGitHubRepositoryCollaboratorParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName } - It 'Should return objects of the correct type' { - $collaborators[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryCollaborator' - } + $collaborators = @(Get-GitHubRepositoryCollaborator @getGitHubRepositoryCollaboratorParms) + } - It 'Should return expected number of collaborators' { - $collaborators.Count | Should -Be 1 - } + It 'Should return objects of the correct type' { + $collaborators[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryCollaborator' + } - It "Should return the correct membership" { - $repo.owner.login | Should -BeIn $collaborators.login - } + It 'Should return expected number of collaborators' { + $collaborators.Count | Should -Be 1 } - Context 'When getting GitHub Repository Collaborators (via pipeline)' { - BeforeAll { - $collaborators = @($repo | Get-GitHubRepositoryCollaborator) - } + It "Should return the correct membership" { + $repo.owner.login | Should -BeIn $collaborators.login + } + } - It 'Should return objects of the correct type' { - $collaborators[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryCollaborator' - } + Context 'When getting GitHub Repository Collaborators (via pipeline)' { + BeforeAll { + $collaborators = @($repo | Get-GitHubRepositoryCollaborator) + } - It 'Should return expected number of collaborators' { - $collaborators.Count | Should -Be 1 - } + It 'Should return objects of the correct type' { + $collaborators[0].PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryCollaborator' + } - It "Should return the correct membership" { - $repo.owner.login | Should -BeIn $collaborators.login - } + It 'Should return expected number of collaborators' { + $collaborators.Count | Should -Be 1 } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + It "Should return the correct membership" { + $repo.owner.login | Should -BeIn $collaborators.login } } - Describe 'GitHubRepositories\Get-GitHubRepositoryLanguage' { + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } +} - Context -Name 'When getting repository languages' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - } +Describe 'GitHubRepositories\Get-GitHubRepositoryLanguage' { - It 'Should be empty' { - $languages = Get-GitHubRepositoryLanguage -OwnerName $repo.owner.login -RepositoryName $repo.name - $languages | Should -BeNullOrEmpty - } + Context -Name 'When getting repository languages' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - It 'Should contain PowerShell' { - $languages = Get-GitHubRepositoryLanguage -OwnerName "microsoft" -RepositoryName "PowerShellForGitHub" - $languages.PowerShell | Should -Not -BeNullOrEmpty - $languages.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryLanguage' - } + It 'Should be empty' { + $languages = Get-GitHubRepositoryLanguage -OwnerName $repo.owner.login -RepositoryName $repo.name + $languages | Should -BeNullOrEmpty + } - It 'Should contain PowerShell (via pipeline)' { - $psfg = Get-GitHubRepository -OwnerName "microsoft" -RepositoryName "PowerShellForGitHub" - $languages = $psfg | Get-GitHubRepositoryLanguage - $languages.PowerShell | Should -Not -BeNullOrEmpty - $languages.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryLanguage' - } + It 'Should contain PowerShell' { + $languages = Get-GitHubRepositoryLanguage -OwnerName "microsoft" -RepositoryName "PowerShellForGitHub" + $languages.PowerShell | Should -Not -BeNullOrEmpty + $languages.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryLanguage' + } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Force - } + It 'Should contain PowerShell (via pipeline)' { + $psfg = Get-GitHubRepository -OwnerName "microsoft" -RepositoryName "PowerShellForGitHub" + $languages = $psfg | Get-GitHubRepositoryLanguage + $languages.PowerShell | Should -Not -BeNullOrEmpty + $languages.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryLanguage' + } + + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Force } } +} - Describe 'GitHubRepositories\Get-GitHubRepositoryTag' { +Describe 'GitHubRepositories\Get-GitHubRepositoryTag' { - Context -Name 'When getting repository tags' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - } + Context -Name 'When getting repository tags' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - It 'Should be empty' { - $tags = Get-GitHubRepositoryTag -OwnerName $repo.owner.login -RepositoryName $repo.name - $tags | Should -BeNullOrEmpty - } + It 'Should be empty' { + $tags = Get-GitHubRepositoryTag -OwnerName $repo.owner.login -RepositoryName $repo.name + $tags | Should -BeNullOrEmpty + } - It 'Should be empty (via pipeline)' { - $tags = $repo | Get-GitHubRepositoryTag - $tags | Should -BeNullOrEmpty - } + It 'Should be empty (via pipeline)' { + $tags = $repo | Get-GitHubRepositoryTag + $tags | Should -BeNullOrEmpty + } - AfterAll { - Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false - } + AfterAll { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false } } +} + +Describe 'GitHubRepositories\Test-GitHubRepositoryVulnerabilityAlert' { + BeforeAll -ScriptBlock { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + } - Describe 'GitHubRepositories\Test-GitHubRepositoryVulnerabilityAlert' { + Context 'When the Git Hub Repository Vulnerability Alert Status is Enabled' { BeforeAll -ScriptBlock { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url + $result = Test-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url } - Context 'When the Git Hub Repository Vulnerability Alert Status is Enabled' { - BeforeAll -ScriptBlock { - Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url - $result = Test-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url - } - - It 'Should return an object of the correct type' { - $result | Should -BeOfType System.Boolean - } - - It 'Should return the correct value' { - $result | Should -Be $true - } + It 'Should return an object of the correct type' { + $result | Should -BeOfType System.Boolean } - Context 'When the Git Hub Repository Vulnerability Alert Status is Disabled' { - BeforeAll -ScriptBlock { - Disable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url - $status = Test-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url - } - - It 'Should return an object of the correct type' { - $status | Should -BeOfType System.Boolean - } - - It 'Should return the correct value' { - $status | Should -BeFalse - } + It 'Should return the correct value' { + $result | Should -Be $true } + } - Context 'When Invoke-GHRestMethod returns an unexpected error' { - It 'Should throw' { - $getGitHubRepositoryVulnerabilityAlertParms = @{ - OwnerName = 'octocat' - RepositoryName = 'IncorrectRepostioryName' - } - { Test-GitHubRepositoryVulnerabilityAlert @getGitHubRepositoryVulnerabilityAlertParms } | - Should -Throw - } + Context 'When the Git Hub Repository Vulnerability Alert Status is Disabled' { + BeforeAll -ScriptBlock { + Disable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url + $status = Test-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url } - Context "When specifiying the 'URI' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - $status = $repo | Test-GitHubRepositoryVulnerabilityAlert - } + It 'Should return an object of the correct type' { + $status | Should -BeOfType System.Boolean + } - It 'Should return an object of the correct type' { - $status | Should -BeOfType System.Boolean - } + It 'Should return the correct value' { + $status | Should -BeFalse } + } - AfterAll -ScriptBlock { - Remove-GitHubRepository -Uri $repo.svn_url -Force + Context 'When Invoke-GHRestMethod returns an unexpected error' { + It 'Should throw' { + $getGitHubRepositoryVulnerabilityAlertParms = @{ + OwnerName = 'octocat' + RepositoryName = 'IncorrectRepostioryName' + } + { Test-GitHubRepositoryVulnerabilityAlert @getGitHubRepositoryVulnerabilityAlertParms } | + Should -Throw } } - Describe 'GitHubRepositories\Enable-GitHubRepositoryVulnerabilityAlert' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + Context "When specifiying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $status = $repo | Test-GitHubRepositoryVulnerabilityAlert } - Context 'When Enabling GitHub Repository Vulnerability Alerts' { - It 'Should not throw' { - { Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url } | - Should -Not -Throw - } + It 'Should return an object of the correct type' { + $status | Should -BeOfType System.Boolean } + } - Context "When specifiying the 'URI' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - Disable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url - } + AfterAll -ScriptBlock { + Remove-GitHubRepository -Uri $repo.svn_url -Force + } +} - It 'Should not throw' { - { $repo | Enable-GitHubRepositoryVulnerabilityAlert } | - Should -Not -Throw - } - } +Describe 'GitHubRepositories\Enable-GitHubRepositoryVulnerabilityAlert' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + } - AfterAll -ScriptBlock { - Remove-GitHubRepository -Uri $repo.svn_url -Force + Context 'When Enabling GitHub Repository Vulnerability Alerts' { + It 'Should not throw' { + { Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url } | + Should -Not -Throw } } - Describe 'GitHubRepositories\Disable-GitHubRepositoryVulnerabilityAlert' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) - Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url + Context "When specifiying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + Disable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url } - Context 'When Disabling GitHub Repository Vulnerability Alerts' { - It 'Should not throw' { - { Disable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url } | - Should -Not -Throw - } + It 'Should not throw' { + { $repo | Enable-GitHubRepositoryVulnerabilityAlert } | + Should -Not -Throw } + } - Context "When specifiying the 'URI' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url - } + AfterAll -ScriptBlock { + Remove-GitHubRepository -Uri $repo.svn_url -Force + } +} - It 'Should not throw' { - { $repo | Disable-GitHubRepositoryVulnerabilityAlert } | - Should -Not -Throw - } - } +Describe 'GitHubRepositories\Disable-GitHubRepositoryVulnerabilityAlert' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url + } - AfterAll -ScriptBlock { - Remove-GitHubRepository -Uri $repo.svn_url -Force + Context 'When Disabling GitHub Repository Vulnerability Alerts' { + It 'Should not throw' { + { Disable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url } | + Should -Not -Throw } } - Describe 'GitHubRepositories\Enable-GitHubRepositorySecurityFix' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + Context "When specifiying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url } - Context 'When Enabling GitHub Repository Security Fixes' { - It 'Should not throw' { - { Enable-GitHubRepositorySecurityFix -Uri $repo.svn_url } | - Should -Not -Throw - } + It 'Should not throw' { + { $repo | Disable-GitHubRepositoryVulnerabilityAlert } | + Should -Not -Throw } + } - Context "When specifiying the 'URI' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - Disable-GitHubRepositorySecurityFix -Uri $repo.svn_url - } + AfterAll -ScriptBlock { + Remove-GitHubRepository -Uri $repo.svn_url -Force + } +} - It 'Should not throw' { - { $repo | Enable-GitHubRepositorySecurityFix } | - Should -Not -Throw - } - } +Describe 'GitHubRepositories\Enable-GitHubRepositorySecurityFix' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url + } - AfterAll -ScriptBlock { - Remove-GitHubRepository -Uri $repo.svn_url -Force + Context 'When Enabling GitHub Repository Security Fixes' { + It 'Should not throw' { + { Enable-GitHubRepositorySecurityFix -Uri $repo.svn_url } | + Should -Not -Throw } } - Describe 'GitHubRepositories\Disable-GitHubRepositorySecurityFix' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) - Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url - Enable-GitHubRepositorySecurityFix -Uri $repo.svn_url + Context "When specifiying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + Disable-GitHubRepositorySecurityFix -Uri $repo.svn_url } - Context 'When Disabling GitHub Repository Security Fixes' { - It 'Should not throw' { - { Disable-GitHubRepositorySecurityFix -Uri $repo.svn_url } | - Should -Not -Throw - } + It 'Should not throw' { + { $repo | Enable-GitHubRepositorySecurityFix } | + Should -Not -Throw } + } - Context "When specifiying the 'URI' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - Enable-GitHubRepositorySecurityFix -Uri $repo.svn_url - } + AfterAll -ScriptBlock { + Remove-GitHubRepository -Uri $repo.svn_url -Force + } +} - It 'Should not throw' { - { $repo | Disable-GitHubRepositorySecurityFix } | - Should -Not -Throw - } - } +Describe 'GitHubRepositories\Disable-GitHubRepositorySecurityFix' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + Enable-GitHubRepositoryVulnerabilityAlert -Uri $repo.svn_url + Enable-GitHubRepositorySecurityFix -Uri $repo.svn_url + } - AfterAll -ScriptBlock { - Remove-GitHubRepository -Uri $repo.svn_url -Force + Context 'When Disabling GitHub Repository Security Fixes' { + It 'Should not throw' { + { Disable-GitHubRepositorySecurityFix -Uri $repo.svn_url } | + Should -Not -Throw } } - Describe 'GitHubRepositories\Get-GitHubRepositoryActionsPermission' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -RepositoryName $repoName + Context "When specifiying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + Enable-GitHubRepositorySecurityFix -Uri $repo.svn_url + } - $allowedActions = 'All', 'LocalOnly', 'Selected', 'Disabled' + It 'Should not throw' { + { $repo | Disable-GitHubRepositorySecurityFix } | + Should -Not -Throw } + } - foreach ($allowedAction in $allowedActions) - { - Context "When the AllowedAction is $allowedAction" { - BeforeAll { - $setGitHubRepositoryActionsPermissionParms = @{ - Uri = $repo.svn_url - AllowedActions = $allowedAction - } + AfterAll -ScriptBlock { + Remove-GitHubRepository -Uri $repo.svn_url -Force + } +} - Set-GitHubRepositoryActionsPermission @setGitHubRepositoryActionsPermissionParms +Describe 'GitHubRepositories\Get-GitHubRepositoryActionsPermission' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -RepositoryName $repoName - $permissions = Get-GitHubRepositoryActionsPermission -Uri $repo.svn_url - } + } - It 'Should return the correct type and properties' { - $permissions.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryActionsPermission' - - $permissions.RepositoryName | Should -Be $repoName - $permissions.RepositoryUrl | Should -Be $repo.svn_url - - if ($allowedAction -eq 'Disabled') - { - $permissions.Enabled | Should -BeFalse - } - else - { - $permissions.Enabled | Should -BeTrue - $permissions.AllowedActions | Should -Be $allowedAction - } - } + Context "Checking AllowedActions" -ForEach @('All', 'LocalOnly', 'Selected', 'Disabled') { + BeforeAll { + $setGitHubRepositoryActionsPermissionParms = @{ + Uri = $repo.svn_url + AllowedActions = $_ } - } - Context "When specifiying the 'URI' Parameter from the Pipeline" { - BeforeAll { - $permissions = $repo | Get-GitHubRepositoryActionsPermission - } + Set-GitHubRepositoryActionsPermission @setGitHubRepositoryActionsPermissionParms - It 'Should return an object of the correct type' { - $permissions.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryActionsPermission' - } + $permissions = Get-GitHubRepositoryActionsPermission -Uri $repo.svn_url } - AfterAll { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + It "Should return the correct type and properties for $_" { + $permissions.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryActionsPermission' + + $permissions.RepositoryName | Should -Be $repoName + $permissions.RepositoryUrl | Should -Be $repo.svn_url + + if ($_ -eq 'Disabled') + { + $permissions.Enabled | Should -BeFalse + } + else { - $repo | Remove-GitHubRepository -Force + $permissions.Enabled | Should -BeTrue + $permissions.AllowedActions | Should -Be $_ } } } - Describe 'GitHubRepositories\Set-GitHubRepositoryActionsPermission' { + Context "When specifiying the 'URI' Parameter from the Pipeline" { BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + $permissions = $repo | Get-GitHubRepositoryActionsPermission + } - $allowedActions = 'All', 'LocalOnly', 'Selected', 'Disabled' + It 'Should return an object of the correct type' { + $permissions.PSObject.TypeNames[0] | Should -Be 'GitHub.RepositoryActionsPermission' } + } - foreach ($allowedAction in $allowedActions) + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) { - Context "When the AllowedAction Parameter is $allowedAction" { - BeforeAll { - $setGitHubRepositoryActionsPermissionParms = @{ - Uri = $repo.svn_url - AllowedActions = $allowedAction - } - - Set-GitHubRepositoryActionsPermission @setGitHubRepositoryActionsPermissionParms - } - - It 'Should have set the expected permissions' { - $permissions = Get-GitHubRepositoryActionsPermission -Uri $repo.svn_url - - if ($allowedAction -eq 'Disabled') - { - $permissions.Enabled | Should -BeFalse - } - else - { - $permissions.Enabled | Should -BeTrue - $permissions.AllowedActions | Should -Be $allowedAction - } - } - } + $repo | Remove-GitHubRepository -Force } + } +} - Context "When specifiying the 'URI' Parameter from the Pipeline" { - It 'Should not throw' { - { $repo | Set-GitHubRepositoryActionsPermission -AllowedActions 'All' } | - Should -Not -Throw +Describe 'GitHubRepositories\Set-GitHubRepositoryActionsPermission' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) + + } + + Context "Checking the AllowedAction Parameter" -ForEach @('All', 'LocalOnly', 'Selected', 'Disabled') { + BeforeAll { + $setGitHubRepositoryActionsPermissionParms = @{ + Uri = $repo.svn_url + AllowedActions = $_ } + + Set-GitHubRepositoryActionsPermission @setGitHubRepositoryActionsPermissionParms } - AfterAll { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + It "Should have set the expected permissions for $_" { + $permissions = Get-GitHubRepositoryActionsPermission -Uri $repo.svn_url + + if ($_ -eq 'Disabled') + { + $permissions.Enabled | Should -BeFalse + } + else { - $repo | Remove-GitHubRepository -Force + $permissions.Enabled | Should -BeTrue + $permissions.AllowedActions | Should -Be $_ } } } - Describe 'GitHubRepositories\Get-GitHubRepositoryTeamPermission' { - BeforeAll { - $repositoryTeamPermissionTypeName = 'GitHub.RepositoryTeamPermission' - $repoName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName + Context "When specifiying the 'URI' Parameter from the Pipeline" { + It 'Should not throw' { + { $repo | Set-GitHubRepositoryActionsPermission -AllowedActions 'All' } | + Should -Not -Throw + } + } - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'closed' - $MaintainerName = $script:ownerName + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } +} - $newGithubTeamParms = @{ - OrganizationName = $script:organizationName - TeamName = $teamName - Description = $description - Privacy = $privacy - MaintainerName = $MaintainerName - } +Describe 'GitHubRepositories\Get-GitHubRepositoryTeamPermission' { + BeforeAll { + $repositoryTeamPermissionTypeName = 'GitHub.RepositoryTeamPermission' + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName - $team = New-GitHubTeam @newGithubTeamParms + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName - $permissions = 'Push', 'Pull', 'Maintain', 'Triage', 'Admin' + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName } - Foreach ($permission in $permissions) { - Context "When the Team Permission is $permission" { - BeforeAll { - $setGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - Permission = $permission - } - - Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + $team = New-GitHubTeam @newGithubTeamParms - $getGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - } - - $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms - } + } - It 'Should have the expected type and additional properties' { - $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName - $repoPermission.RepositoryName | Should -Be $repo.full_name - $repoPermission.RepositoryUrl | Should -Be $repo.svn_url - $repoPermission.RepositoryId | Should -Be $repo.RepositoryId - $repoPermission.TeamName | Should -Be $team.TeamName - $repoPermission.TeamSlug | Should -Be $team.TeamSlug - $repoPermission.Permission | Should -Be $permission - } + Context "Checking the Team Permissions" -ForEach @('Push', 'Pull', 'Maintain', 'Triage', 'Admin') { + BeforeAll { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = $_ } - } - Context "When specifying the 'TeamName' parameter" { - BeforeAll { - $permission = 'Pull' + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms - $setGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - Permission = $permission - } + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + } - Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + } - $getGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamName = $teamName - } + It "Should have the expected type and additional properties for $_" { + $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName + $repoPermission.RepositoryName | Should -Be $repo.full_name + $repoPermission.RepositoryUrl | Should -Be $repo.svn_url + $repoPermission.RepositoryId | Should -Be $repo.RepositoryId + $repoPermission.TeamName | Should -Be $team.TeamName + $repoPermission.TeamSlug | Should -Be $team.TeamSlug + $repoPermission.Permission | Should -Be $_ + } + } - $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms - } + Context "When specifying the 'TeamName' parameter" { + BeforeAll { + $permission = 'Pull' - It 'Should have the expected type and additional properties' { - $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName - $repoPermission.RepositoryName | Should -Be $repo.full_name - $repoPermission.RepositoryUrl | Should -Be $repo.svn_url - $repoPermission.RepositoryId | Should -Be $repo.RepositoryId - $repoPermission.TeamName | Should -Be $team.TeamName - $repoPermission.TeamSlug | Should -Be $team.TeamSlug - $repoPermission.Permission | Should -Be $permission + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = $permission } - Context 'When the specified TeamName does not exist' { - BeforeAll { - $nonExistingTeamName = [Guid]::NewGuid().Guid - - $getGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamName = $nonExistingTeamName - } - } + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms - It 'Should throw the correct exception' { - { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | - Should -Throw "Team '$nonExistingTeamName' not found" - } + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $teamName } - } - Context "When specifying the 'URI' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - $getGitHubRepositoryTeamPermissionParms = @{ - TeamName = $teamName - } - $repoPermission = $repo | - Get-GitHubRepositoryTeamPermission @getGitHubRepositoryTeamPermissionParms - } + $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + } - It 'Should have the expected type and additional properties' { - $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName - $repoPermission.RepositoryName | Should -Be $repo.full_name - $repoPermission.TeamName | Should -Be $teamName - } + It 'Should have the expected type and additional properties' { + $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName + $repoPermission.RepositoryName | Should -Be $repo.full_name + $repoPermission.RepositoryUrl | Should -Be $repo.svn_url + $repoPermission.RepositoryId | Should -Be $repo.RepositoryId + $repoPermission.TeamName | Should -Be $team.TeamName + $repoPermission.TeamSlug | Should -Be $team.TeamSlug + $repoPermission.Permission | Should -Be $permission } - Context "When specifying the 'TeamSlug' and 'OrganizationName' Parameters from the Pipeline" { - BeforeAll -ScriptBlock { - $getGitHubRepositoryTeamPermissionParms = @{ + Context 'When the specified TeamName does not exist' { + BeforeAll { + $nonExistingTeamName = [Guid]::NewGuid().Guid + + $getGithubRepositoryTeamPermissionParms = @{ Uri = $repo.svn_url + TeamName = $nonExistingTeamName } - $repoPermission = $team | - Get-GitHubRepositoryTeamPermission @getGitHubRepositoryTeamPermissionParms } - It 'Should have the expected type and additional properties' { - $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName - $repoPermission.RepositoryName | Should -Be $repo.full_name - $repoPermission.TeamName | Should -Be $teamName - $repoPermission.TeamSlug | Should -Be $team.TeamSlug + It 'Should throw the correct exception' { + { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | + Should -Throw "Team '$nonExistingTeamName' not found" } } + } - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force + Context "When specifying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $getGitHubRepositoryTeamPermissionParms = @{ + TeamName = $teamName } + $repoPermission = $repo | + Get-GitHubRepositoryTeamPermission @getGitHubRepositoryTeamPermissionParms + } - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - $repo | Remove-GitHubRepository -Force - } + It 'Should have the expected type and additional properties' { + $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName + $repoPermission.RepositoryName | Should -Be $repo.full_name + $repoPermission.TeamName | Should -Be $teamName } } - Describe 'GitHubRepositories\Set-GitHubRepositoryTeamPermission' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName - - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'closed' - $MaintainerName = $script:ownerName - - $newGithubTeamParms = @{ - OrganizationName = $script:organizationName - TeamName = $teamName - Description = $description - Privacy = $privacy - MaintainerName = $MaintainerName + Context "When specifying the 'TeamSlug' and 'OrganizationName' Parameters from the Pipeline" { + BeforeAll -ScriptBlock { + $getGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url } + $repoPermission = $team | + Get-GitHubRepositoryTeamPermission @getGitHubRepositoryTeamPermissionParms + } - $team = New-GitHubTeam @newGithubTeamParms + It 'Should have the expected type and additional properties' { + $repoPermission.PSObject.TypeNames[0] | Should -Be $repositoryTeamPermissionTypeName + $repoPermission.RepositoryName | Should -Be $repo.full_name + $repoPermission.TeamName | Should -Be $teamName + $repoPermission.TeamSlug | Should -Be $team.TeamSlug + } + } - $permissions = 'Push', 'Pull', 'Maintain', 'Triage', 'Admin' + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force } - Foreach ($permission in $permissions) { - Context "When the Team Permission is specified as $permission" { - BeforeAll { - $setGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - Permission = $permission - } + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } +} - } +Describe 'GitHubRepositories\Set-GitHubRepositoryTeamPermission' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName - It 'Should not throw' { - { Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | - Should -Not -Throw + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName - } + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } - It 'Should have set the correct Team permission' { - $getGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - } + $team = New-GitHubTeam @newGithubTeamParms - $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + } - $repoPermission.Permission | Should -Be $permission - } + Context "Checking the Team Permission" -ForEach @('Push', 'Pull', 'Maintain', 'Triage', 'Admin') { + BeforeAll { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = $_ } + } - Context "When specifying the 'TeamName' parameter" { - BeforeAll { - $permission = 'Pull' + It 'Should not throw' { + { Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw - $setGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamName = $teamName - Permission = $permission - } - } + } - It 'Should not throw' { - { Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | - Should -Not -Throw + It "Should have set the correct Team permission of $_" { + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug } - It 'Should have set the correct Team permission' { - $getGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - } - - $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms - $repoPermission.Permission | Should -Be $permission - } + $repoPermission.Permission | Should -Be $_ + } + } - Context 'When the specified TeamName does not exist' { - BeforeAll { - $nonExistingTeamName = [Guid]::NewGuid().Guid - $setGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamName = $nonExistingTeamName - } - } + Context "When specifying the 'TeamName' parameter" { + BeforeAll { + $permission = 'Pull' - It 'Should throw the correct exception' { - { Set-GitHubRepositoryTeamPermission @setGithubRepositoryTeamPermissionParms } | - Should -Throw "Team '$nonExistingTeamName' not found" - } + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $teamName + Permission = $permission } } - Context "When specifying the 'URI' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - $setGitHubRepositoryTeamPermissionParms = @{ - TeamName = $teamName - } - } + It 'Should not throw' { + { Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } - It 'Should not throw' { - { $repo | Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | - Should -Not -Throw + It 'Should have set the correct Team permission' { + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug } + + $repoPermission = Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms + + $repoPermission.Permission | Should -Be $permission } - Context "When specifying the 'TeamSlug' and 'OrganizationName' Parameters from the Pipeline" { - BeforeAll -ScriptBlock { - $setGitHubRepositoryTeamPermissionParms = @{ + Context 'When the specified TeamName does not exist' { + BeforeAll { + $nonExistingTeamName = [Guid]::NewGuid().Guid + + $setGithubRepositoryTeamPermissionParms = @{ Uri = $repo.svn_url + TeamName = $nonExistingTeamName } } - It 'Should not throw' { - { $team | Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | - Should -Not -Throw + It 'Should throw the correct exception' { + { Set-GitHubRepositoryTeamPermission @setGithubRepositoryTeamPermissionParms } | + Should -Throw "Team '$nonExistingTeamName' not found" } } + } - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force + Context "When specifying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $setGitHubRepositoryTeamPermissionParms = @{ + TeamName = $teamName } + } - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - $repo | Remove-GitHubRepository -Force + It 'Should not throw' { + { $repo | Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } + } + + Context "When specifying the 'TeamSlug' and 'OrganizationName' Parameters from the Pipeline" { + BeforeAll -ScriptBlock { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url } } + + It 'Should not throw' { + { $team | Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } } - Describe 'GitHubRepositories\Remove-GitHubRepositoryTeamPermission' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid - $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + } +} - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'closed' - $MaintainerName = $script:ownerName +Describe 'GitHubRepositories\Remove-GitHubRepositoryTeamPermission' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + $repo = New-GitHubRepository -OrganizationName $script:organizationName -RepositoryName $repoName - $newGithubTeamParms = @{ - OrganizationName = $script:organizationName - TeamName = $teamName - Description = $description - Privacy = $privacy - MaintainerName = $MaintainerName - } + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName + + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } + + $team = New-GitHubTeam @newGithubTeamParms - $team = New-GitHubTeam @newGithubTeamParms + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = 'Pull' + } + + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + } + Context "When specifying the 'TeamSlug' parameter" { + BeforeAll { $setGitHubRepositoryTeamPermissionParms = @{ Uri = $repo.svn_url TeamSlug = $team.slug @@ -1802,133 +1800,121 @@ try Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms } - Context "When specifying the 'TeamSlug' parameter" { - BeforeAll { - $setGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - Permission = 'Pull' - } - - Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + It 'Should not throw' { + $removeGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Force = $true } - It 'Should not throw' { - $removeGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - Force = $true - } + { Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw - { Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | - Should -Not -Throw + } + It 'Should have removed the Team permission' { + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug } - It 'Should have removed the Team permission' { - $getGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - } - - { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | - Should -Throw 'Not Found' - } + { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | + Should -Throw } + } - Context "When specifying the 'TeamName' parameter" { - BeforeAll { - $setGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - Permission = 'Pull' - } - - Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + Context "When specifying the 'TeamName' parameter" { + BeforeAll { + $setGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug + Permission = 'Pull' } - It 'Should not throw' { - $removeGitHubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamName = $teamName - Force = $true - } + Set-GitHubRepositoryTeamPermission @setGitHubRepositoryTeamPermissionParms + } - { Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | - Should -Not -Throw + It 'Should not throw' { + $removeGitHubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $teamName + Force = $true } - It 'Should have removed the Team permission' { - $getGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamSlug = $team.slug - } + { Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } - { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | - Should -Throw 'Not Found' + It 'Should have removed the Team permission' { + $getGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamSlug = $team.slug } - Context 'When the specified TeamName does not exist' { - BeforeAll { - $nonExistingTeamName = [Guid]::NewGuid().Guid - - $removeGithubRepositoryTeamPermissionParms = @{ - Uri = $repo.svn_url - TeamName = $nonExistingTeamName - Force = $true - } - } - - It 'Should throw the correct exception' { - { Remove-GitHubRepositoryTeamPermission @removeGithubRepositoryTeamPermissionParms } | - Should -Throw "Team '$nonExistingTeamName' not found" - } - } + { Get-GitHubRepositoryTeamPermission @getGithubRepositoryTeamPermissionParms } | + Should -Throw } - Context "When specifying the 'URI' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - $removeGitHubRepositoryTeamPermissionParms = @{ - TeamName = $teamName + Context 'When the specified TeamName does not exist' { + BeforeAll { + $nonExistingTeamName = [Guid]::NewGuid().Guid + + $removeGithubRepositoryTeamPermissionParms = @{ + Uri = $repo.svn_url + TeamName = $nonExistingTeamName Force = $true } } - It 'Should not throw' { - { $repo | Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | - Should -Not -Throw + It 'Should throw the correct exception' { + { Remove-GitHubRepositoryTeamPermission @removeGithubRepositoryTeamPermissionParms } | + Should -Throw "Team '$nonExistingTeamName' not found" } } + } - Context "When specifying the 'TeamSlug' and 'Organization' Parameter from the Pipeline" { - BeforeAll -ScriptBlock { - $removeGitHubRepositoryTeamPermissionParms = @{ - RepositoryUrl = $repo.svn_url - Force = $true - } + Context "When specifying the 'URI' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $removeGitHubRepositoryTeamPermissionParms = @{ + TeamName = $teamName + Force = $true } + } - It 'Should not throw' { - { $team | Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | - Should -Not -Throw - } + It 'Should not throw' { + { $repo | Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw } + } - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force + Context "When specifying the 'TeamSlug' and 'Organization' Parameter from the Pipeline" { + BeforeAll -ScriptBlock { + $removeGitHubRepositoryTeamPermissionParms = @{ + RepositoryUrl = $repo.svn_url + Force = $true } + } - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - $repo | Remove-GitHubRepository -Force - } + It 'Should not throw' { + { $team | Remove-GitHubRepositoryTeamPermission @removeGitHubRepositoryTeamPermissionParms } | + Should -Not -Throw + } + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubRepositoryForks.tests.ps1 b/Tests/GitHubRepositoryForks.tests.ps1 index e78e6b82..7ddb6ffd 100644 --- a/Tests/GitHubRepositoryForks.tests.ps1 +++ b/Tests/GitHubRepositoryForks.tests.ps1 @@ -8,15 +8,14 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readonly, hidden variables. @{ upstreamOwnerName = 'octocat' @@ -24,81 +23,80 @@ try }.GetEnumerator() | ForEach-Object { Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value } - - Describe 'Creating a new fork for user' { - Context 'When a new fork is created' { - BeforeAll { - $repo = New-GitHubRepositoryFork -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName - } - - AfterAll { - $repo | Remove-GitHubRepository -Force - } - +} +Describe 'Creating a new fork for user' { + Context 'When a new fork is created' { + BeforeAll { + $repo = New-GitHubRepositoryFork -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName $newForks = @(Get-GitHubRepositoryFork -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName -Sort Newest) $ourFork = $newForks | Where-Object { $_.owner.login -eq $script:ownerName } + } - It 'Should be in the list' { - # Doing this syntax, because due to odd timing with GitHub, it's possible it may - # think that there's an existing clone out there and so may name this one "...-1" - $ourFork.full_name.StartsWith("$($script:ownerName)/$script:upstreamRepositoryName") | Should -BeTrue - } - - It 'Should have the expected additional type and properties' { - $ourFork.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $ourFork.RepositoryId | Should -Be $ourFork.id - } + AfterAll { + $repo | Remove-GitHubRepository -Force } - Context 'When a new fork is created (with the pipeline)' { - BeforeAll { - $upstream = Get-GitHubRepository -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName - $repo = $upstream | New-GitHubRepositoryFork - } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + It 'Should be in the list' { + # Doing this syntax, because due to odd timing with GitHub, it's possible it may + # think that there's an existing clone out there and so may name this one "...-1" + $ourFork.full_name.StartsWith("$($script:ownerName)/$script:upstreamRepositoryName") | Should -BeTrue + } + + It 'Should have the expected additional type and properties' { + $ourFork.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $ourFork.RepositoryId | Should -Be $ourFork.id + } + } + Context 'When a new fork is created (with the pipeline)' { + BeforeAll { + $upstream = Get-GitHubRepository -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName + $repo = $upstream | New-GitHubRepositoryFork $newForks = @(Get-GitHubRepositoryFork -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName -Sort Newest) $ourFork = $newForks | Where-Object { $_.owner.login -eq $script:ownerName } + } - It 'Should be in the list' { - # Doing this syntax, because due to odd timing with GitHub, it's possible it may - # think that there's an existing clone out there and so may name this one "...-1" - $ourFork.full_name.StartsWith("$($script:ownerName)/$script:upstreamRepositoryName") | Should -BeTrue - } - - It 'Should have the expected additional type and properties' { - $ourFork.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' - $ourFork.RepositoryId | Should -Be $ourFork.id - } + AfterAll { + $repo | Remove-GitHubRepository -Force } - } - Describe 'Creating a new fork for an org' { - Context 'When a new fork is created' { - BeforeAll { - $repo = New-GitHubRepositoryFork -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName -OrganizationName $script:organizationName - } - AfterAll { - $repo | Remove-GitHubRepository -Force - } + It 'Should be in the list' { + # Doing this syntax, because due to odd timing with GitHub, it's possible it may + # think that there's an existing clone out there and so may name this one "...-1" + $ourFork.full_name.StartsWith("$($script:ownerName)/$script:upstreamRepositoryName") | Should -BeTrue + } + + It 'Should have the expected additional type and properties' { + $ourFork.PSObject.TypeNames[0] | Should -Be 'GitHub.Repository' + $ourFork.RepositoryId | Should -Be $ourFork.id + } + } +} +Describe 'Creating a new fork for an org' { + Context 'When a new fork is created' { + BeforeAll { + $repo = New-GitHubRepositoryFork -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName -OrganizationName $script:organizationName $newForks = @(Get-GitHubRepositoryFork -OwnerName $script:upstreamOwnerName -RepositoryName $script:upstreamRepositoryName -Sort Newest) $ourFork = $newForks | Where-Object { $_.owner.login -eq $script:organizationName } + } - It 'Should be in the list' { - # Doing this syntax, because due to odd timing with GitHub, it's possible it may - # think that there's an existing clone out there and so may name this one "...-1" - $ourFork.full_name.StartsWith("$($script:organizationName)/$script:upstreamRepositoryName") | Should -BeTrue - } + AfterAll { + $repo | Remove-GitHubRepository -Force + } + + + It 'Should be in the list' { + # Doing this syntax, because due to odd timing with GitHub, it's possible it may + # think that there's an existing clone out there and so may name this one "...-1" + $ourFork.full_name.StartsWith("$($script:organizationName)/$script:upstreamRepositoryName") | Should -BeTrue } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubRepositoryTraffic.tests.ps1 b/Tests/GitHubRepositoryTraffic.tests.ps1 index 7136ee0a..fe47a8f7 100644 --- a/Tests/GitHubRepositoryTraffic.tests.ps1 +++ b/Tests/GitHubRepositoryTraffic.tests.ps1 @@ -8,105 +8,104 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} + +Describe 'Testing the referrer traffic on a repository' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } -try -{ - Describe 'Testing the referrer traffic on a repository' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } + + Context 'When initially created, there are no referrers' { + It 'Should return expected number of referrers' { + $traffic = Get-GitHubReferrerTraffic -Uri $repo.svn_url + $traffic | Should -BeNullOrEmpty } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + It 'Should have the expected type (via pipeline)' { + $traffic = $repo | Get-GitHubReferrerTraffic + $traffic | Should -BeNullOrEmpty } + } +} - Context 'When initially created, there are no referrers' { - It 'Should return expected number of referrers' { - $traffic = Get-GitHubReferrerTraffic -Uri $repo.svn_url - $traffic | Should -BeNullOrEmpty - } +Describe 'Testing the path traffic on a repository' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - It 'Should have the expected type (via pipeline)' { - $traffic = $repo | Get-GitHubReferrerTraffic - $traffic | Should -BeNullOrEmpty - } - } + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false } - Describe 'Testing the path traffic on a repository' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + Context 'Getting the popular content over the last 14 days' { + It 'Should have no traffic since it was just created' { + $traffic = Get-GitHubPathTraffic -Uri $repo.svn_url + $traffic | Should -BeNullOrEmpty } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + It 'Should have the expected type (via pipeline)' { + $traffic = $repo | Get-GitHubPathTraffic + $traffic | Should -BeNullOrEmpty } + } +} - Context 'Getting the popular content over the last 14 days' { - It 'Should have no traffic since it was just created' { - $traffic = Get-GitHubPathTraffic -Uri $repo.svn_url - $traffic | Should -BeNullOrEmpty - } +Describe 'Testing the view traffic on a repository' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } - It 'Should have the expected type (via pipeline)' { - $traffic = $repo | Get-GitHubPathTraffic - $traffic | Should -BeNullOrEmpty - } - } + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false } - Describe 'Testing the view traffic on a repository' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + Context 'Getting the views over the last 14 days' { + It 'Should have no traffic since it was just created' { + $traffic = Get-GitHubViewTraffic -Uri $repo.svn_url + $traffic.Count | Should -Be 0 } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + It 'Should have the expected type (via pipeline)' { + $traffic = $repo | Get-GitHubViewTraffic + $traffic.PSObject.TypeNames[0] | Should -Be 'GitHub.ViewTraffic' } + } +} - Context 'Getting the views over the last 14 days' { - It 'Should have no traffic since it was just created' { - $traffic = Get-GitHubViewTraffic -Uri $repo.svn_url - $traffic.Count | Should -Be 0 - } - - It 'Should have the expected type (via pipeline)' { - $traffic = $repo | Get-GitHubViewTraffic - $traffic.PSObject.TypeNames[0] | Should -Be 'GitHub.ViewTraffic' - } - } +Describe 'Testing the clone traffic on a repository' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit } - Describe 'Testing the clone traffic on a repository' { - BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit - } + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } - AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + Context 'Getting the clones over the last 14 days' { + It 'Should have no clones since it was just created' { + $traffic = Get-GitHubCloneTraffic -Uri $repo.svn_url + $traffic.Count | Should -Be 0 } - Context 'Getting the clones over the last 14 days' { - It 'Should have no clones since it was just created' { - $traffic = Get-GitHubCloneTraffic -Uri $repo.svn_url - $traffic.Count | Should -Be 0 - } - - It 'Should have no clones since it was just created (via pipeline)' { - $traffic = $repo | Get-GitHubCloneTraffic - $traffic.PSObject.TypeNames[0] | Should -Be 'GitHub.CloneTraffic' - } + It 'Should have no clones since it was just created (via pipeline)' { + $traffic = $repo | Get-GitHubCloneTraffic + $traffic.PSObject.TypeNames[0] | Should -Be 'GitHub.CloneTraffic' } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubTeams.tests.ps1 b/Tests/GitHubTeams.tests.ps1 index 03035d7c..67f34a8a 100644 --- a/Tests/GitHubTeams.tests.ps1 +++ b/Tests/GitHubTeams.tests.ps1 @@ -8,15 +8,14 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +BeforeAll { + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') -try -{ # Define Script-scoped, readonly, hidden variables. @{ defaultRepoDesc = "This is a description." @@ -25,118 +24,74 @@ try }.GetEnumerator() | ForEach-Object { Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value } +} +Describe 'GitHubTeams\Get-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + } - Describe 'GitHubTeams\Get-GitHubTeam' { + Context 'When getting a GitHub Team by organization' { BeforeAll { - $organizationName = $script:organizationName - } + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName - Context 'When getting a GitHub Team by organization' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'closed' - $MaintainerName = $script:ownerName + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Description = $description - Privacy = $privacy - MaintainerName = $MaintainerName - } + New-GitHubTeam @newGithubTeamParms | Out-Null - New-GitHubTeam @newGithubTeamParms | Out-Null + $orgTeams = Get-GitHubTeam -OrganizationName $organizationName - $orgTeams = Get-GitHubTeam -OrganizationName $organizationName + $team = $orgTeams | Where-Object -Property name -eq $teamName + } - $team = $orgTeams | Where-Object -Property name -eq $teamName + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.TeamSummary' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.parent | Should -BeNullOrEmpty + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $team.name + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + Context 'When specifying the "TeamName" parameter' { + BeforeAll { + $team = Get-GitHubTeam -OrganizationName $organizationName -TeamName $teamName } It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.TeamSummary' + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' $team.name | Should -Be $teamName $team.description | Should -Be $description $team.parent | Should -BeNullOrEmpty $team.privacy | Should -Be $privacy + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 $team.TeamName | Should -Be $team.name $team.TeamId | Should -Be $team.id $team.OrganizationName | Should -Be $organizationName } - - Context 'When specifying the "TeamName" parameter' { - BeforeAll { - $team = Get-GitHubTeam -OrganizationName $organizationName -TeamName $teamName - } - - It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $team.name | Should -Be $teamName - $team.description | Should -Be $description - $team.parent | Should -BeNullOrEmpty - $team.privacy | Should -Be $privacy - $team.created_at | Should -Not -BeNullOrEmpty - $team.updated_at | Should -Not -BeNullOrEmpty - $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 0 - $team.TeamName | Should -Be $team.name - $team.TeamId | Should -Be $team.id - $team.OrganizationName | Should -Be $organizationName - } - } - - Context 'When specifying the "OrganizationName" and "TeamSlug" through the pipeline' { - BeforeAll { - $orgTeams = $team | Get-GitHubTeam - $team = $orgTeams | Where-Object -Property name -eq $teamName - } - - It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $team.name | Should -Be $teamName - $team.description | Should -Be $description - $team.parent | Should -BeNullOrEmpty - $team.privacy | Should -Be $privacy - $team.TeamName | Should -Be $team.name - $team.TeamId | Should -Be $team.id - $team.OrganizationName | Should -Be $organizationName - } - } - - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } - } } - Context 'When getting a GitHub Team by repository' { + Context 'When specifying the "OrganizationName" and "TeamSlug" through the pipeline' { BeforeAll { - $repoName = [Guid]::NewGuid().Guid - - $repo = New-GitHubRepository -RepositoryName $repoName -OrganizationName $organizationName - - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'closed' - - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Description = $description - RepositoryName = $repoName - Privacy = $privacy - } - - New-GitHubTeam @newGithubTeamParms | Out-Null - - $orgTeams = Get-GitHubTeam -OwnerName $organizationName -RepositoryName $repoName + $orgTeams = $team | Get-GitHubTeam $team = $orgTeams | Where-Object -Property name -eq $teamName } It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.TeamSummary' + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' $team.name | Should -Be $teamName $team.description | Should -Be $description $team.parent | Should -BeNullOrEmpty @@ -145,107 +100,85 @@ try $team.TeamId | Should -Be $team.id $team.OrganizationName | Should -Be $organizationName } + } - Context 'When specifying the "TeamName" parameter' { - BeforeAll { - $getGitHubTeamParms = @{ - OwnerName = $organizationName - RepositoryName = $repoName - TeamName = $teamName - } + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } - $team = Get-GitHubTeam @getGitHubTeamParms - } + Context 'When getting a GitHub Team by repository' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid - It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $team.name | Should -Be $teamName - $team.description | Should -Be $description - $team.parent | Should -BeNullOrEmpty - $team.privacy | Should -Be $privacy - $team.created_at | Should -Not -BeNullOrEmpty - $team.updated_at | Should -Not -BeNullOrEmpty - $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 1 - $team.TeamName | Should -Be $team.name - $team.TeamId | Should -Be $team.id - $team.OrganizationName | Should -Be $organizationName - } - } + $repo = New-GitHubRepository -RepositoryName $repoName -OrganizationName $organizationName - Context 'When specifying the "Uri" parameter through the pipeline' { - BeforeAll { - $orgTeams = $repo | Get-GitHubTeam -TeamName $teamName - $team = $orgTeams | Where-Object -Property name -eq $teamName - } + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' - It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $team.name | Should -Be $teamName - $team.description | Should -Be $description - $team.organization.login | Should -Be $organizationName - $team.parent | Should -BeNullOrEmpty - $team.created_at | Should -Not -BeNullOrEmpty - $team.updated_at | Should -Not -BeNullOrEmpty - $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 1 - $team.privacy | Should -Be $privacy - $team.TeamName | Should -Be $team.name - $team.TeamId | Should -Be $team.id - $team.OrganizationName | Should -Be $organizationName - } + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + RepositoryName = $repoName + Privacy = $privacy } - AfterAll { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - $repo | Remove-GitHubRepository -Force - } + New-GitHubTeam @newGithubTeamParms | Out-Null - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } - } + $orgTeams = Get-GitHubTeam -OwnerName $organizationName -RepositoryName $repoName + $team = $orgTeams | Where-Object -Property name -eq $teamName } - Context 'When getting a GitHub Team by TeamSlug' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'closed' - $MaintainerName = $script:ownerName + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.TeamSummary' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.parent | Should -BeNullOrEmpty + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $team.name + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } - $newGithubTeamParms = @{ - OrganizationName = $script:organizationName + Context 'When specifying the "TeamName" parameter' { + BeforeAll { + $getGitHubTeamParms = @{ + OwnerName = $organizationName + RepositoryName = $repoName TeamName = $teamName - Description = $description - Privacy = $privacy - MaintainerName = $MaintainerName } - $newTeam = New-GitHubTeam @newGithubTeamParms + $team = Get-GitHubTeam @getGitHubTeamParms } - It 'Should have the expected type and additional properties as a parameter' { - $team = Get-GitHubTeam -OrganizationName $script:organizationName -TeamSlug $newTeam.slug + It 'Should have the expected type and additional properties' { $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' $team.name | Should -Be $teamName $team.description | Should -Be $description - $team.organization.login | Should -Be $organizationName $team.parent | Should -BeNullOrEmpty + $team.privacy | Should -Be $privacy $team.created_at | Should -Not -BeNullOrEmpty $team.updated_at | Should -Not -BeNullOrEmpty $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 0 - $team.privacy | Should -Be $privacy + $team.repos_count | Should -Be 1 $team.TeamName | Should -Be $team.name $team.TeamId | Should -Be $team.id $team.OrganizationName | Should -Be $organizationName } + } + + Context 'When specifying the "Uri" parameter through the pipeline' { + BeforeAll { + $orgTeams = $repo | Get-GitHubTeam -TeamName $teamName + $team = $orgTeams | Where-Object -Property name -eq $teamName + } - It 'Should have the expected type and additional properties via the pipeline' { - $team = $newTeam | Get-GitHubTeam + It 'Should have the expected type and additional properties' { $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' $team.name | Should -Be $teamName $team.description | Should -Be $description @@ -254,749 +187,820 @@ try $team.created_at | Should -Not -BeNullOrEmpty $team.updated_at | Should -Not -BeNullOrEmpty $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 0 + $team.repos_count | Should -Be 1 $team.privacy | Should -Be $privacy $team.TeamName | Should -Be $team.name $team.TeamId | Should -Be $team.id $team.OrganizationName | Should -Be $organizationName } + } - AfterAll { - if (Get-Variable -Name newTeam -ErrorAction SilentlyContinue) - { - $newTeam | Remove-GitHubTeam -Force - } + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } + + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force } } } - Describe 'GitHubTeams\New-GitHubTeam' { + Context 'When getting a GitHub Team by TeamSlug' { BeforeAll { - $organizationName = $script:organizationName - } - - Context 'When creating a new GitHub team with default settings' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - } + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $MaintainerName = $script:ownerName - $team = New-GitHubTeam @newGithubTeamParms + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName } - It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $team.name | Should -Be $teamName - $team.description | Should -BeNullOrEmpty - $team.organization.login | Should -Be $organizationName - $team.parent | Should -BeNullOrEmpty - $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 0 - $team.TeamName | Should -Be $team.name - $team.TeamId | Should -Be $team.id - $team.OrganizationName | Should -Be $organizationName - } + $newTeam = New-GitHubTeam @newGithubTeamParms + } - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } - } + It 'Should have the expected type and additional properties as a parameter' { + $team = Get-GitHubTeam -OrganizationName $script:organizationName -TeamSlug $newTeam.slug + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $team.name + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName } - Context 'When creating a new GitHub team with all possible settings' { - BeforeAll { - $repoName = [Guid]::NewGuid().Guid + It 'Should have the expected type and additional properties via the pipeline' { + $team = $newTeam | Get-GitHubTeam + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $team.name + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } - $newGithubRepositoryParms = @{ - RepositoryName = $repoName - OrganizationName = $organizationName - } + AfterAll { + if (Get-Variable -Name newTeam -ErrorAction SilentlyContinue) + { + $newTeam | Remove-GitHubTeam -Force + } + } + } +} - $repo = New-GitHubRepository @newGitHubRepositoryParms +Describe 'GitHubTeams\New-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + } - $maintainer = Get-GitHubUser -UserName $script:ownerName + Context 'When creating a new GitHub team with default settings' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + } - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'closed' + $team = New-GitHubTeam @newGithubTeamParms + } - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Description = $description - RepositoryName = $repoName - Privacy = $privacy - MaintainerName = $maintainer.UserName - } + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -BeNullOrEmpty + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.TeamName | Should -Be $team.name + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } - $team = New-GitHubTeam @newGithubTeamParms + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force } + } + } - It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $team.name | Should -Be $teamName - $team.description | Should -Be $description - $team.organization.login | Should -Be $organizationName - $team.parent | Should -BeNullOrEmpty - $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 1 - $team.privacy | Should -Be $privacy - $team.TeamName | Should -Be $team.name - $team.TeamId | Should -Be $team.id - $team.OrganizationName | Should -Be $organizationName + Context 'When creating a new GitHub team with all possible settings' { + BeforeAll { + $repoName = [Guid]::NewGuid().Guid + + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + OrganizationName = $organizationName } - AfterAll { - if (Get-Variable -Name repo -ErrorAction SilentlyContinue) - { - $repo | Remove-GitHubRepository -Force - } + $repo = New-GitHubRepository @newGitHubRepositoryParms - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } - } - } + $maintainer = Get-GitHubUser -UserName $script:ownerName - Context 'When creating a child GitHub team using the Parent TeamName' { - BeforeAll { - $parentTeamName = [Guid]::NewGuid().Guid - $privacy = 'Closed' + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $parentTeamName - Privacy = $privacy - } + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + RepositoryName = $repoName + Privacy = $privacy + MaintainerName = $maintainer.UserName + } - $parentTeam = New-GitHubTeam @newGithubTeamParms + $team = New-GitHubTeam @newGithubTeamParms + } - $childTeamName = [Guid]::NewGuid().Guid + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.description | Should -Be $description + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 1 + $team.privacy | Should -Be $privacy + $team.TeamName | Should -Be $team.name + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $childTeamName - ParentTeamName = $parentTeamName - Privacy = $privacy - } + AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + $repo | Remove-GitHubRepository -Force + } - $childTeam = New-GitHubTeam @newGithubTeamParms + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force } + } + } - It 'Should have the expected type and additional properties' { - $childTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $childTeam.name | Should -Be $childTeamName - $childTeam.organization.login | Should -Be $organizationName - $childTeam.parent.name | Should -Be $parentTeamName - $childTeam.privacy | Should -Be $privacy - $childTeam.TeamName | Should -Be $childTeam.name - $childTeam.TeamId | Should -Be $childTeam.id - $childTeam.OrganizationName | Should -Be $organizationName - } - - AfterAll { - if (Get-Variable -Name childTeam -ErrorAction SilentlyContinue) - { - $childTeam | Remove-GitHubTeam -Force - } + Context 'When creating a child GitHub team using the Parent TeamName' { + BeforeAll { + $parentTeamName = [Guid]::NewGuid().Guid + $privacy = 'Closed' - if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) - { - $parentTeam | Remove-GitHubTeam -Force - } + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $parentTeamName + Privacy = $privacy } - } - Context 'When creating a child GitHub team using the Parent TeamId' { - BeforeAll { - $parentTeamName = [Guid]::NewGuid().Guid - $privacy = 'Closed' + $parentTeam = New-GitHubTeam @newGithubTeamParms - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $parentTeamName - Privacy = $privacy - } + $childTeamName = [Guid]::NewGuid().Guid - $parentTeam = New-GitHubTeam @newGithubTeamParms + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $childTeamName + ParentTeamName = $parentTeamName + Privacy = $privacy + } - $childTeamName = [Guid]::NewGuid().Guid + $childTeam = New-GitHubTeam @newGithubTeamParms + } - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $childTeamName - ParentTeamId = $parentTeam.id - Privacy = $privacy - } + It 'Should have the expected type and additional properties' { + $childTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $childTeam.name | Should -Be $childTeamName + $childTeam.organization.login | Should -Be $organizationName + $childTeam.parent.name | Should -Be $parentTeamName + $childTeam.privacy | Should -Be $privacy + $childTeam.TeamName | Should -Be $childTeam.name + $childTeam.TeamId | Should -Be $childTeam.id + $childTeam.OrganizationName | Should -Be $organizationName + } - $childTeam = New-GitHubTeam @newGithubTeamParms + AfterAll { + if (Get-Variable -Name childTeam -ErrorAction SilentlyContinue) + { + $childTeam | Remove-GitHubTeam -Force } - It 'Should have the expected type and additional properties' { - $childTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $childTeam.name | Should -Be $childTeamName - $childTeam.organization.login | Should -Be $organizationName - $childTeam.parent.name | Should -Be $parentTeamName - $childTeam.privacy | Should -Be $privacy - $childTeam.TeamName | Should -Be $childTeam.name - $childTeam.TeamId | Should -Be $childTeam.id - $childTeam.OrganizationName | Should -Be $organizationName - } - - AfterAll { - if (Get-Variable -Name childTeam -ErrorAction SilentlyContinue) - { - $childTeam | Remove-GitHubTeam -Force - } - - if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) - { - $parentTeam | Remove-GitHubTeam -Force - } + if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) + { + $parentTeam | Remove-GitHubTeam -Force } } + } - Context 'When creating a child GitHub team using the Parent TeamId on the pipeline' { - BeforeAll { - $parentTeamName = [Guid]::NewGuid().Guid - $privacy = 'Closed' - - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $parentTeamName - Privacy = $privacy - } + Context 'When creating a child GitHub team using the Parent TeamId' { + BeforeAll { + $parentTeamName = [Guid]::NewGuid().Guid + $privacy = 'Closed' - $parentTeam = New-GitHubTeam @newGithubTeamParms + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $parentTeamName + Privacy = $privacy + } - $childTeamName = [Guid]::NewGuid().Guid + $parentTeam = New-GitHubTeam @newGithubTeamParms - $newGithubTeamParms = @{ - TeamName = $childTeamName - Privacy = $privacy - } + $childTeamName = [Guid]::NewGuid().Guid - $childTeam = $parentTeam | New-GitHubTeam @newGithubTeamParms + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $childTeamName + ParentTeamId = $parentTeam.id + Privacy = $privacy } - It 'Should have the expected type and additional properties' { - $childTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $childTeam.name | Should -Be $childTeamName - $childTeam.organization.login | Should -Be $organizationName - $childTeam.parent.name | Should -Be $parentTeamName - $childTeam.privacy | Should -Be $privacy - $childTeam.TeamName | Should -Be $childTeam.name - $childTeam.TeamId | Should -Be $childTeam.id - $childTeam.OrganizationName | Should -Be $organizationName - } - - AfterAll { - if (Get-Variable -Name childTeam -ErrorAction SilentlyContinue) - { - $childTeam | Remove-GitHubTeam -Force - } + $childTeam = New-GitHubTeam @newGithubTeamParms + } - if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) - { - $parentTeam | Remove-GitHubTeam -Force - } - } + It 'Should have the expected type and additional properties' { + $childTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $childTeam.name | Should -Be $childTeamName + $childTeam.organization.login | Should -Be $organizationName + $childTeam.parent.name | Should -Be $parentTeamName + $childTeam.privacy | Should -Be $privacy + $childTeam.TeamName | Should -Be $childTeam.name + $childTeam.TeamId | Should -Be $childTeam.id + $childTeam.OrganizationName | Should -Be $organizationName } - Context 'When specifying the "TeamName" parameter through the pipeline' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid + AfterAll { + if (Get-Variable -Name childTeam -ErrorAction SilentlyContinue) + { + $childTeam | Remove-GitHubTeam -Force + } - $team = $teamName | New-GitHubTeam -OrganizationName $organizationName + if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) + { + $parentTeam | Remove-GitHubTeam -Force } + } + } - It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $team.name | Should -Be $teamName - $team.organization.login | Should -Be $organizationName - $team.parent | Should -BeNullOrEmpty - $team.created_at | Should -Not -BeNullOrEmpty - $team.updated_at | Should -Not -BeNullOrEmpty - $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 0 - $team.TeamName | Should -Be $team.name - $team.TeamId | Should -Be $team.id - $team.OrganizationName | Should -Be $organizationName + Context 'When creating a child GitHub team using the Parent TeamId on the pipeline' { + BeforeAll { + $parentTeamName = [Guid]::NewGuid().Guid + $privacy = 'Closed' + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $parentTeamName + Privacy = $privacy } - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } + $parentTeam = New-GitHubTeam @newGithubTeamParms + + $childTeamName = [Guid]::NewGuid().Guid + + $newGithubTeamParms = @{ + TeamName = $childTeamName + Privacy = $privacy } + + $childTeam = $parentTeam | New-GitHubTeam @newGithubTeamParms } - Context 'When specifying the "MaintainerName" parameter through the pipeline' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid - $maintainer = Get-GitHubUser -UserName $script:ownerName + It 'Should have the expected type and additional properties' { + $childTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $childTeam.name | Should -Be $childTeamName + $childTeam.organization.login | Should -Be $organizationName + $childTeam.parent.name | Should -Be $parentTeamName + $childTeam.privacy | Should -Be $privacy + $childTeam.TeamName | Should -Be $childTeam.name + $childTeam.TeamId | Should -Be $childTeam.id + $childTeam.OrganizationName | Should -Be $organizationName + } - $team = $maintainer | New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + AfterAll { + if (Get-Variable -Name childTeam -ErrorAction SilentlyContinue) + { + $childTeam | Remove-GitHubTeam -Force } - It 'Should have the expected type and additional properties' { - $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $team.name | Should -Be $teamName - $team.organization.login | Should -Be $organizationName - $team.parent | Should -BeNullOrEmpty - $team.created_at | Should -Not -BeNullOrEmpty - $team.updated_at | Should -Not -BeNullOrEmpty - $team.members_count | Should -Be 1 - $team.repos_count | Should -Be 0 - $team.TeamName | Should -Be $team.name - $team.TeamId | Should -Be $team.id - $team.OrganizationName | Should -Be $organizationName + if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) + { + $parentTeam | Remove-GitHubTeam -Force } + } + } - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } + Context 'When specifying the "TeamName" parameter through the pipeline' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + + $team = $teamName | New-GitHubTeam -OrganizationName $organizationName + } + + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.TeamName | Should -Be $team.name + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } + + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force } } } - Describe 'GitHubTeams\Set-GitHubTeam' { + Context 'When specifying the "MaintainerName" parameter through the pipeline' { BeforeAll { - $organizationName = $script:organizationName + $teamName = [Guid]::NewGuid().Guid + $maintainer = Get-GitHubUser -UserName $script:ownerName + + $team = $maintainer | New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName } - Context 'When updating a Child GitHub team' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid - $parentTeamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'Closed' - - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $parentTeamName - Privacy = $privacy - } + It 'Should have the expected type and additional properties' { + $team.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $team.name | Should -Be $teamName + $team.organization.login | Should -Be $organizationName + $team.parent | Should -BeNullOrEmpty + $team.created_at | Should -Not -BeNullOrEmpty + $team.updated_at | Should -Not -BeNullOrEmpty + $team.members_count | Should -Be 1 + $team.repos_count | Should -Be 0 + $team.TeamName | Should -Be $team.name + $team.TeamId | Should -Be $team.id + $team.OrganizationName | Should -Be $organizationName + } - $parentTeam = New-GitHubTeam @newGithubTeamParms + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } +} - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Privacy = $privacy - } +Describe 'GitHubTeams\Set-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + } - $team = New-GitHubTeam @newGithubTeamParms + Context 'When updating a Child GitHub team' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $parentTeamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'Closed' - $updateGitHubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Description = $description - Privacy = $privacy - ParentTeamName = $parentTeamName - } + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $parentTeamName + Privacy = $privacy + } - $updatedTeam = Set-GitHubTeam @updateGitHubTeamParms -PassThru + $parentTeam = New-GitHubTeam @newGithubTeamParms + + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Privacy = $privacy } - It 'Should have the expected type and additional properties' { - $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $updatedTeam.name | Should -Be $teamName - $updatedTeam.organization.login | Should -Be $organizationName - $updatedTeam.description | Should -Be $description - $updatedTeam.parent.name | Should -Be $parentTeamName - $updatedTeam.privacy | Should -Be $privacy - $updatedTeam.TeamName | Should -Be $team.name - $updatedTeam.TeamId | Should -Be $team.id - $updatedTeam.OrganizationName | Should -Be $organizationName - } - - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } + $team = New-GitHubTeam @newGithubTeamParms - if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) - { - $parentTeam | Remove-GitHubTeam -Force - } + $updateGitHubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + ParentTeamName = $parentTeamName } + + $updatedTeam = Set-GitHubTeam @updateGitHubTeamParms -PassThru } - Context 'When updating a non-child GitHub team' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'Closed' + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $teamName + $updatedTeam.organization.login | Should -Be $organizationName + $updatedTeam.description | Should -Be $description + $updatedTeam.parent.name | Should -Be $parentTeamName + $updatedTeam.privacy | Should -Be $privacy + $updatedTeam.TeamName | Should -Be $team.name + $updatedTeam.TeamId | Should -Be $team.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Privacy = 'Secret' - } + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } - $team = New-GitHubTeam @newGithubTeamParms + if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) + { + $parentTeam | Remove-GitHubTeam -Force + } + } + } - $updateGitHubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Description = $description - Privacy = $privacy - } + Context 'When updating a non-child GitHub team' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'Closed' - $updatedTeam = Set-GitHubTeam @updateGitHubTeamParms -PassThru + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Privacy = 'Secret' } - It 'Should have the expected type and additional properties' { - $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $updatedTeam.name | Should -Be $teamName - $updatedTeam.organization.login | Should -Be $OrganizationName - $updatedTeam.description | Should -Be $description - $updatedTeam.parent.name | Should -BeNullOrEmpty - $updatedTeam.privacy | Should -Be $privacy - $updatedTeam.created_at | Should -Not -BeNullOrEmpty - $updatedTeam.updated_at | Should -Not -BeNullOrEmpty - $updatedTeam.members_count | Should -Be 1 - $updatedTeam.repos_count | Should -Be 0 - $updatedTeam.TeamName | Should -Be $team.name - $updatedTeam.TeamId | Should -Be $team.id - $updatedTeam.OrganizationName | Should -Be $organizationName - } - - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } + $team = New-GitHubTeam @newGithubTeamParms + + $updateGitHubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy } + + $updatedTeam = Set-GitHubTeam @updateGitHubTeamParms -PassThru } - Context 'When updating a GitHub team to be a child using the Parent TeamId' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid - $parentTeamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - $privacy = 'Closed' - - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $parentTeamName - Privacy = $privacy - } + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $teamName + $updatedTeam.organization.login | Should -Be $OrganizationName + $updatedTeam.description | Should -Be $description + $updatedTeam.parent.name | Should -BeNullOrEmpty + $updatedTeam.privacy | Should -Be $privacy + $updatedTeam.created_at | Should -Not -BeNullOrEmpty + $updatedTeam.updated_at | Should -Not -BeNullOrEmpty + $updatedTeam.members_count | Should -Be 1 + $updatedTeam.repos_count | Should -Be 0 + $updatedTeam.TeamName | Should -Be $team.name + $updatedTeam.TeamId | Should -Be $team.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } - $parentTeam = New-GitHubTeam @newGithubTeamParms + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force + } + } + } - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Privacy = $privacy - } + Context 'When updating a GitHub team to be a child using the Parent TeamId' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid + $parentTeamName = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'Closed' - $team = New-GitHubTeam @newGithubTeamParms + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $parentTeamName + Privacy = $privacy + } - $updateGitHubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Description = $description - Privacy = $privacy - ParentTeamId = $parentTeam.id - } + $parentTeam = New-GitHubTeam @newGithubTeamParms - $updatedTeam = Set-GitHubTeam @updateGitHubTeamParms -PassThru + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Privacy = $privacy } - It 'Should have the expected type and additional properties' { - $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $updatedTeam.name | Should -Be $teamName - $updatedTeam.organization.login | Should -Be $organizationName - $updatedTeam.description | Should -Be $description - $updatedTeam.parent.name | Should -Be $parentTeamName - $updatedTeam.privacy | Should -Be $privacy - $updatedTeam.TeamName | Should -Be $team.name - $updatedTeam.TeamId | Should -Be $team.id - $updatedTeam.OrganizationName | Should -Be $organizationName - } - - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } + $team = New-GitHubTeam @newGithubTeamParms - if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) - { - $parentTeam | Remove-GitHubTeam -Force - } + $updateGitHubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Description = $description + Privacy = $privacy + ParentTeamId = $parentTeam.id } - } - Context 'When specifying the "Organization" and "TeamName" parameters through the pipeline' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid - $description = 'Team Description' - - $newGithubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - } + $updatedTeam = Set-GitHubTeam @updateGitHubTeamParms -PassThru + } - $team = New-GitHubTeam @newGithubTeamParms + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $teamName + $updatedTeam.organization.login | Should -Be $organizationName + $updatedTeam.description | Should -Be $description + $updatedTeam.parent.name | Should -Be $parentTeamName + $updatedTeam.privacy | Should -Be $privacy + $updatedTeam.TeamName | Should -Be $team.name + $updatedTeam.TeamId | Should -Be $team.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } - $updatedTeam = $team | Set-GitHubTeam -Description $description -PassThru + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force } - It 'Should have the expected type and additional properties' { - $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $updatedTeam.name | Should -Be $teamName - $updatedTeam.organization.login | Should -Be $OrganizationName - $updatedTeam.description | Should -Be $description - $updatedTeam.parent.name | Should -BeNullOrEmpty - $updatedTeam.created_at | Should -Not -BeNullOrEmpty - $updatedTeam.updated_at | Should -Not -BeNullOrEmpty - $updatedTeam.members_count | Should -Be 1 - $updatedTeam.repos_count | Should -Be 0 - $updatedTeam.TeamName | Should -Be $team.name - $updatedTeam.TeamId | Should -Be $updatedTeam.id - $updatedTeam.OrganizationName | Should -Be $organizationName - } - - AfterAll { - if (Get-Variable -Name team -ErrorAction SilentlyContinue) - { - $team | Remove-GitHubTeam -Force - } + if (Get-Variable -Name parentTeam -ErrorAction SilentlyContinue) + { + $parentTeam | Remove-GitHubTeam -Force } } } - Describe 'GitHubTeams\Rename-GitHubTeam' { + Context 'When specifying the "Organization" and "TeamName" parameters through the pipeline' { BeforeAll { - $organizationName = $script:organizationName $teamName = [Guid]::NewGuid().Guid - $newTeamName = [Guid]::NewGuid().Guid - } - - Context 'When renaming a GitHub team with the TeamName' { - BeforeAll { - $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName - } + $description = 'Team Description' - $updatedTeam = Rename-GitHubTeam -OrganizationName $organizationName -TeamName $teamName -NewTeamName $newTeamName -PassThru - It 'Should have the expected type and additional properties' { - $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $updatedTeam.name | Should -Be $newTeamName - $updatedTeam.organization.login | Should -Be $OrganizationName - $updatedTeam.description | Should -BeNullOrEmpty - $updatedTeam.parent.name | Should -BeNullOrEmpty - $updatedTeam.created_at | Should -Not -BeNullOrEmpty - $updatedTeam.updated_at | Should -Not -BeNullOrEmpty - $updatedTeam.members_count | Should -Be 1 - $updatedTeam.repos_count | Should -Be 0 - $updatedTeam.TeamName | Should -Be $updatedTeam.name - $updatedTeam.TeamId | Should -Be $updatedTeam.id - $updatedTeam.OrganizationName | Should -Be $organizationName + $newGithubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName } - It 'Should find the renamed team' { - { Get-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName } | - Should -Not -Throw - } + $team = New-GitHubTeam @newGithubTeamParms - AfterAll { - Remove-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName -Force - } + $updatedTeam = $team | Set-GitHubTeam -Description $description -PassThru } - Context 'When renaming a GitHub team with the TeamSlug' { - BeforeAll { - $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName - } + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $teamName + $updatedTeam.organization.login | Should -Be $OrganizationName + $updatedTeam.description | Should -Be $description + $updatedTeam.parent.name | Should -BeNullOrEmpty + $updatedTeam.created_at | Should -Not -BeNullOrEmpty + $updatedTeam.updated_at | Should -Not -BeNullOrEmpty + $updatedTeam.members_count | Should -Be 1 + $updatedTeam.repos_count | Should -Be 0 + $updatedTeam.TeamName | Should -Be $team.name + $updatedTeam.TeamId | Should -Be $updatedTeam.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } - $updatedTeam = Rename-GitHubTeam -OrganizationName $organizationName -TeamSlug $team.slug -NewTeamName $newTeamName -PassThru - It 'Should have the expected type and additional properties' { - $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $updatedTeam.name | Should -Be $newTeamName - $updatedTeam.organization.login | Should -Be $OrganizationName - $updatedTeam.description | Should -BeNullOrEmpty - $updatedTeam.parent.name | Should -BeNullOrEmpty - $updatedTeam.created_at | Should -Not -BeNullOrEmpty - $updatedTeam.updated_at | Should -Not -BeNullOrEmpty - $updatedTeam.members_count | Should -Be 1 - $updatedTeam.repos_count | Should -Be 0 - $updatedTeam.TeamName | Should -Be $updatedTeam.name - $updatedTeam.TeamId | Should -Be $updatedTeam.id - $updatedTeam.OrganizationName | Should -Be $organizationName + AfterAll { + if (Get-Variable -Name team -ErrorAction SilentlyContinue) + { + $team | Remove-GitHubTeam -Force } + } + } +} - It 'Should find the renamed team' { - { Get-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName } | - Should -Not -Throw - } +Describe 'GitHubTeams\Rename-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + $teamName = [Guid]::NewGuid().Guid + $newTeamName = [Guid]::NewGuid().Guid + } - AfterAll { - Remove-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName -Force - } + Context 'When renaming a GitHub team with the TeamName' { + BeforeAll { + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + $updatedTeam = Rename-GitHubTeam -OrganizationName $organizationName -TeamName $teamName -NewTeamName $newTeamName -PassThru } - Context 'When renaming a GitHub team with the TeamSlug on the pipeline' { - BeforeAll { - $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName - } - - $updatedTeam = $team | Rename-GitHubTeam -NewTeamName $newTeamName -PassThru - It 'Should have the expected type and additional properties' { - $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' - $updatedTeam.name | Should -Be $newTeamName - $updatedTeam.organization.login | Should -Be $OrganizationName - $updatedTeam.description | Should -BeNullOrEmpty - $updatedTeam.parent.name | Should -BeNullOrEmpty - $updatedTeam.created_at | Should -Not -BeNullOrEmpty - $updatedTeam.updated_at | Should -Not -BeNullOrEmpty - $updatedTeam.members_count | Should -Be 1 - $updatedTeam.repos_count | Should -Be 0 - $updatedTeam.TeamName | Should -Be $updatedTeam.name - $updatedTeam.TeamId | Should -Be $updatedTeam.id - $updatedTeam.OrganizationName | Should -Be $organizationName - } + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $newTeamName + $updatedTeam.organization.login | Should -Be $OrganizationName + $updatedTeam.description | Should -BeNullOrEmpty + $updatedTeam.parent.name | Should -BeNullOrEmpty + $updatedTeam.created_at | Should -Not -BeNullOrEmpty + $updatedTeam.updated_at | Should -Not -BeNullOrEmpty + $updatedTeam.members_count | Should -Be 1 + $updatedTeam.repos_count | Should -Be 0 + $updatedTeam.TeamName | Should -Be $updatedTeam.name + $updatedTeam.TeamId | Should -Be $updatedTeam.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } - It 'Should find the renamed team' { - { Get-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName } | - Should -Not -Throw - } + It 'Should find the renamed team' { + { Get-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName } | + Should -Not -Throw + } - AfterAll { - Remove-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName -Force - } + AfterAll { + Remove-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName -Force } } - Describe 'GitHubTeams\Remove-GitHubTeam' { + Context 'When renaming a GitHub team with the TeamSlug' { BeforeAll { - $organizationName = $script:organizationName + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + $updatedTeam = Rename-GitHubTeam -OrganizationName $organizationName -TeamSlug $team.slug -NewTeamName $newTeamName -PassThru } - Context 'When removing a GitHub team with the TeamName' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $newTeamName + $updatedTeam.organization.login | Should -Be $OrganizationName + $updatedTeam.description | Should -BeNullOrEmpty + $updatedTeam.parent.name | Should -BeNullOrEmpty + $updatedTeam.created_at | Should -Not -BeNullOrEmpty + $updatedTeam.updated_at | Should -Not -BeNullOrEmpty + $updatedTeam.members_count | Should -Be 1 + $updatedTeam.repos_count | Should -Be 0 + $updatedTeam.TeamName | Should -Be $updatedTeam.name + $updatedTeam.TeamId | Should -Be $updatedTeam.id + $updatedTeam.OrganizationName | Should -Be $organizationName + } - $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName - } + It 'Should find the renamed team' { + { Get-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName } | + Should -Not -Throw + } - It 'Should not throw an exception' { - $removeGitHubTeamParms = @{ - OrganizationName = $organizationName - TeamName = $teamName - Confirm = $false - } + AfterAll { + Remove-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName -Force + } + } - { Remove-GitHubTeam @RemoveGitHubTeamParms } | Should -Not -Throw - } + Context 'When renaming a GitHub team with the TeamSlug on the pipeline' { + BeforeAll { + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + $updatedTeam = $team | Rename-GitHubTeam -NewTeamName $newTeamName -PassThru + } - It 'Should have removed the team' { - { Get-GitHubTeam -OrganizationName $organizationName -TeamName $teamName } | - Should -Throw - } + It 'Should have the expected type and additional properties' { + $updatedTeam.PSObject.TypeNames[0] | Should -Be 'GitHub.Team' + $updatedTeam.name | Should -Be $newTeamName + $updatedTeam.organization.login | Should -Be $OrganizationName + $updatedTeam.description | Should -BeNullOrEmpty + $updatedTeam.parent.name | Should -BeNullOrEmpty + $updatedTeam.created_at | Should -Not -BeNullOrEmpty + $updatedTeam.updated_at | Should -Not -BeNullOrEmpty + $updatedTeam.members_count | Should -Be 1 + $updatedTeam.repos_count | Should -Be 0 + $updatedTeam.TeamName | Should -Be $updatedTeam.name + $updatedTeam.TeamId | Should -Be $updatedTeam.id + $updatedTeam.OrganizationName | Should -Be $organizationName } - Context 'When removing a GitHub team with the TeamSlug' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid + It 'Should find the renamed team' { + { Get-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName } | + Should -Not -Throw + } - $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName - } + AfterAll { + Remove-GitHubTeam -OrganizationName $organizationName -TeamName $newTeamName -Force + } + } +} - It 'Should not throw an exception' { - $removeGitHubTeamParms = @{ - OrganizationName = $organizationName - TeamSlug = $team.slug - Confirm = $false - } +Describe 'GitHubTeams\Remove-GitHubTeam' { + BeforeAll { + $organizationName = $script:organizationName + } - { Remove-GitHubTeam @RemoveGitHubTeamParms } | Should -Not -Throw - } + Context 'When removing a GitHub team with the TeamName' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid - It 'Should have removed the team' { - { Get-GitHubTeam -OrganizationName $organizationName -TeamSlug $team.slug } | - Should -Throw + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + } + + It 'Should not throw an exception' { + $removeGitHubTeamParms = @{ + OrganizationName = $organizationName + TeamName = $teamName + Confirm = $false } + + { Remove-GitHubTeam @RemoveGitHubTeamParms } | Should -Not -Throw } - Context 'When removing a GitHub team with the TeamSlug on the pipeline' { - BeforeAll { - $teamName = [Guid]::NewGuid().Guid + It 'Should have removed the team' { + { Get-GitHubTeam -OrganizationName $organizationName -TeamName $teamName } | + Should -Throw + } + } - $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName - } + Context 'When removing a GitHub team with the TeamSlug' { + BeforeAll { + $teamName = [Guid]::NewGuid().Guid - It 'Should not throw an exception' { - { $team | Remove-GitHubTeam -Force } | Should -Not -Throw - } + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + } - It 'Should have removed the team' { - { $team | Get-GitHubTeam } | Should -Throw + It 'Should not throw an exception' { + $removeGitHubTeamParms = @{ + OrganizationName = $organizationName + TeamSlug = $team.slug + Confirm = $false } + + { Remove-GitHubTeam @RemoveGitHubTeamParms } | Should -Not -Throw + } + + It 'Should have removed the team' { + { Get-GitHubTeam -OrganizationName $organizationName -TeamSlug $team.slug } | + Should -Throw } } - Describe 'GitHubTeams\Get-GitHubTeamMember' { + Context 'When removing a GitHub team with the TeamSlug on the pipeline' { BeforeAll { - $organizationName = $script:organizationName $teamName = [Guid]::NewGuid().Guid + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName } - AfterAll { - $team | Remove-GitHubTeam -Force + It 'Should not throw an exception' { + { $team | Remove-GitHubTeam -Force } | Should -Not -Throw + } + + It 'Should have removed the team' { + { $team | Get-GitHubTeam } | Should -Throw } + } +} - Context 'Getting team members using TeamName' { +Describe 'GitHubTeams\Get-GitHubTeamMember' { + BeforeAll { + $organizationName = $script:organizationName + $teamName = [Guid]::NewGuid().Guid + $team = New-GitHubTeam -OrganizationName $organizationName -TeamName $teamName + } + + AfterAll { + $team | Remove-GitHubTeam -Force + } + + Context 'Getting team members using TeamName' { + BeforeAll { $members = @(Get-GitHubTeamMember -OrganizationName $organizationName -TeamName $teamName) + } - It 'Should have the expected type number of members' { - $members.Count | Should -Be 1 - } + It 'Should have the expected type number of members' { + $members.Count | Should -Be 1 + } - It 'Should have the expected type and additional properties' { - $members[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $members[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Getting team members using TeamSlug' { + Context 'Getting team members using TeamSlug' { + BeforeAll { $members = @(Get-GitHubTeamMember -OrganizationName $organizationName -TeamSlug $team.slug) + } - It 'Should have the expected type number of members' { - $members.Count | Should -Be 1 - } + It 'Should have the expected type number of members' { + $members.Count | Should -Be 1 + } - It 'Should have the expected type and additional properties' { - $members[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $members[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' } + } - Context 'Getting team members using TeamSlug on the pipeline' { + Context 'Getting team members using TeamSlug on the pipeline' { + BeforeAll { $members = @($team | Get-GitHubTeamMember) + } - It 'Should have the expected type number of members' { - $members.Count | Should -Be 1 - } + It 'Should have the expected type number of members' { + $members.Count | Should -Be 1 + } - It 'Should have the expected type and additional properties' { - $members[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } + It 'Should have the expected type and additional properties' { + $members[0].PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } } -finally -{ + +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/Tests/GitHubUsers.tests.ps1 b/Tests/GitHubUsers.tests.ps1 index 837455b6..eca94925 100644 --- a/Tests/GitHubUsers.tests.ps1 +++ b/Tests/GitHubUsers.tests.ps1 @@ -5,126 +5,126 @@ .Synopsis Tests for GitHubIssues.ps1 module #> - [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', - Justification='Suppress false positives in Pester code blocks')] + Justification = 'Suppress false positives in Pester code blocks')] param() -# This is common test code setup logic for all Pester test files -$moduleRootPath = Split-Path -Path $PSScriptRoot -Parent -. (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') - -try -{ - Describe 'Getting a user' { - Context 'Current user when additional properties are enabled' { - BeforeAll { - $currentUser = Get-GitHubUser -Current - } - - It 'Should have the expected type and additional properties' { - $currentUser.UserName | Should -Be $currentUser.login - $currentUser.UserId | Should -Be $currentUser.id - $currentUser.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } - } - - Context 'Current user when additional properties are disabled' { - BeforeAll { - Set-GitHubConfiguration -DisablePipelineSupport - $currentUser = Get-GitHubUser -Current - } - - AfterAll { - Set-GitHubConfiguration -DisablePipelineSupport:$false - } - - It 'Should only have the expected type' { - $currentUser.UserName | Should -BeNullOrEmpty - $currentUser.UserId | Should -BeNullOrEmpty - $currentUser.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } - } - - Context 'Specific user as a parameter' { - BeforeAll { - $user = Get-GitHubUser -UserName $script:ownerName - } - - It 'Should have the expected type and additional properties' { - $user.UserName | Should -Be $user.login - $user.UserId | Should -Be $user.id - $user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } - } - - Context 'Specific user with the pipeline' { - BeforeAll { - $user = $script:ownerName | Get-GitHubUser - } - - It 'Should have the expected type and additional properties' { - $user.UserName | Should -Be $user.login - $user.UserId | Should -Be $user.id - $user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' - } +BeforeAll { + + # This is common test code setup logic for all Pester test files + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') +} + +Describe 'Getting a user' { + Context 'Current user when additional properties are enabled' { + BeforeAll { + $currentUser = Get-GitHubUser -Current + } + + It 'Should have the expected type and additional properties' { + $currentUser.UserName | Should -Be $currentUser.login + $currentUser.UserId | Should -Be $currentUser.id + $currentUser.PSObject.TypeNames[0] | Should -Be 'GitHub.User' } } - Describe 'Getting user context' { + Context 'Current user when additional properties are disabled' { BeforeAll { - $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + Set-GitHubConfiguration -DisablePipelineSupport + $currentUser = Get-GitHubUser -Current } AfterAll { - Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + Set-GitHubConfiguration -DisablePipelineSupport:$false + } + + It 'Should only have the expected type' { + $currentUser.UserName | Should -BeNullOrEmpty + $currentUser.UserId | Should -BeNullOrEmpty + $currentUser.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + Context 'Specific user as a parameter' { + BeforeAll { + $user = Get-GitHubUser -UserName $script:ownerName + } + + It 'Should have the expected type and additional properties' { + $user.UserName | Should -Be $user.login + $user.UserId | Should -Be $user.id + $user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } + + Context 'Specific user with the pipeline' { + BeforeAll { + $user = $script:ownerName | Get-GitHubUser } - Context 'Checking context on a repo' { - It 'Should indicate ownership as a parameter' { - $context = Get-GitHubUserContextualInformation -UserName $script:ownerName -RepositoryId $repo.id - 'Owns this repository' | Should -BeIn $context.contexts.message - } + It 'Should have the expected type and additional properties' { + $user.UserName | Should -Be $user.login + $user.UserId | Should -Be $user.id + $user.PSObject.TypeNames[0] | Should -Be 'GitHub.User' + } + } +} - It 'Should indicate ownership with the repo on the pipeline' { - $context = $repo | Get-GitHubUserContextualInformation -UserName $script:ownerName - 'Owns this repository' | Should -BeIn $context.contexts.message - } +Describe 'Getting user context' { + BeforeAll { + $repo = New-GitHubRepository -RepositoryName ([Guid]::NewGuid().Guid) -AutoInit + } + + AfterAll { + Remove-GitHubRepository -Uri $repo.RepositoryUrl -Confirm:$false + } - It 'Should indicate ownership with the username on the pipeline' { - $context = $script:ownerName | Get-GitHubUserContextualInformation -RepositoryId $repo.id - 'Owns this repository' | Should -BeIn $context.contexts.message - $context.contexts[0].PSObject.TypeNames[0] | Should -Be 'GitHub.UserContextualInformation' - } + Context 'Checking context on a repo' { + It 'Should indicate ownership as a parameter' { + $context = Get-GitHubUserContextualInformation -UserName $script:ownerName -RepositoryId $repo.id + 'Owns this repository' | Should -BeIn $context.contexts.message + } - It 'Should indicate ownership with the user on the pipeline' { - $user = Get-GitHubUser -UserName $script:ownerName - $context = $user | Get-GitHubUserContextualInformation -RepositoryId $repo.id - 'Owns this repository' | Should -BeIn $context.contexts.message - $context.contexts[0].PSObject.TypeNames[0] | Should -Be 'GitHub.UserContextualInformation' - } + It 'Should indicate ownership with the repo on the pipeline' { + $context = $repo | Get-GitHubUserContextualInformation -UserName $script:ownerName + 'Owns this repository' | Should -BeIn $context.contexts.message } - Context 'Checking context on an issue with the pipeline' { + It 'Should indicate ownership with the username on the pipeline' { + $context = $script:ownerName | Get-GitHubUserContextualInformation -RepositoryId $repo.id + 'Owns this repository' | Should -BeIn $context.contexts.message + $context.contexts[0].PSObject.TypeNames[0] | Should -Be 'GitHub.UserContextualInformation' + } + + It 'Should indicate ownership with the user on the pipeline' { + $user = Get-GitHubUser -UserName $script:ownerName + $context = $user | Get-GitHubUserContextualInformation -RepositoryId $repo.id + 'Owns this repository' | Should -BeIn $context.contexts.message + $context.contexts[0].PSObject.TypeNames[0] | Should -Be 'GitHub.UserContextualInformation' + } + } + + Context 'Checking context on an issue with the pipeline' { + BeforeAll { $issue = New-GitHubIssue -Uri $repo.RepositoryUrl -Title ([guid]::NewGuid().Guid) $context = $issue | Get-GitHubUserContextualInformation -UserName $script:ownerName + } - It 'Should indicate the user created the issue' { - $context.contexts[0].octicon | Should -Be 'issue-opened' - $context.contexts[0].IssueId | Should -Be $issue.IssueId - $context.contexts[0].PSObject.TypeNames[0] | Should -Be 'GitHub.UserContextualInformation' - } + It 'Should indicate the user created the issue' { + $context.contexts[0].octicon | Should -Be 'issue-opened' + $context.contexts[0].IssueId | Should -Be $issue.IssueId + $context.contexts[0].PSObject.TypeNames[0] | Should -Be 'GitHub.UserContextualInformation' + } - It 'Should indicate the user owns the repository' { - $context.contexts[1].message | Should -Be 'Owns this repository' - $context.contexts[1].PSObject.TypeNames[0] | Should -Be 'GitHub.UserContextualInformation' - } + It 'Should indicate the user owns the repository' { + $context.contexts[1].message | Should -Be 'Owns this repository' + $context.contexts[1].PSObject.TypeNames[0] | Should -Be 'GitHub.UserContextualInformation' } } } -finally -{ +AfterAll { if (Test-Path -Path $script:originalConfigFile -PathType Leaf) { # Restore the user's configuration to its pre-test state diff --git a/build/pipelines/templates/run-unitTests.yaml b/build/pipelines/templates/run-unitTests.yaml index 7b2b39fd..ea0e6f85 100644 --- a/build/pipelines/templates/run-unitTests.yaml +++ b/build/pipelines/templates/run-unitTests.yaml @@ -36,7 +36,7 @@ steps: workingDirectory: '$(System.DefaultWorkingDirectory)' targetType: 'inline' script: | - Install-Module -Name Pester -Repository PSGallery -Scope CurrentUser -AllowClobber -SkipPublisherCheck -RequiredVersion 4.10.1 -Force -Verbose + Install-Module -Name Pester -Repository PSGallery -Scope CurrentUser -AllowClobber -SkipPublisherCheck -MinimumVersion 5.3.3 -Force -Verbose - task: PowerShell@2 displayName: 'Run Unit Tests via Pester' @@ -46,8 +46,23 @@ steps: workingDirectory: '$(System.DefaultWorkingDirectory)' targetType: 'inline' script: | - $null = New-Item -Path ..\ -Name Pester -ItemType Directory -Force - Invoke-Pester -CodeCoverage .\*.ps*1 -CodeCoverageOutputFile ../Pester/coverage.xml -CodeCoverageOutputFileFormat JaCoCo -EnableExit -Strict -OutputFile ../Pester/test-results.xml -OutputFormat NUnitXml + # Import the module, otherwise GitHubCore.tests.ps1 has problems since it's testing things in module scope. + Import-Module -Global ./PowerShellForGitHub.psd1 + + $null = New-Item -Path ../ -Name Pester -ItemType Directory -Force + + $pesterConfig = New-PesterConfiguration + $pesterConfig.CodeCoverage.Enabled = $true + $pesterConfig.CodeCoverage.Path = @('.\*.ps*1') + $pesterConfig.CodeCoverage.OutputPath = '../Pester/coverage.xml' + $pesterConfig.CodeCoverage.OutputFormat = 'JaCoCo' + $pesterConfig.Run.Exit = $true + $pesterConfig.TestResult.Enabled = $true + $pesterConfig.TestResult.OutputPath = '../Pester/test-results.xml' + $pesterConfig.TestResult.OutputFormat = 'NUnitXml' + $pesterConfig.Output.CIFormat = 'AzureDevops' + + Invoke-Pester -Configuration $pesterConfig env: ciAccessToken: ${{ parameters.gitHubAccessToken }} ciOwnerName: ${{ parameters.gitHubOwnerName }} From 3ccee43287e053a4ad9f9729a943e75ad12ce904 Mon Sep 17 00:00:00 2001 From: Neil White Date: Sun, 26 Feb 2023 12:10:01 -0800 Subject: [PATCH 39/51] Added Discussions support (#382) Allow the user to enable Discussions in Github repositories. Fixes #378 --- GitHubRepositories.ps1 | 12 ++++++++++++ Tests/GitHubRepositories.tests.ps1 | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index 464f4856..fc8c46bd 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -68,6 +68,9 @@ filter New-GitHubRepository .PARAMETER NoWiki By default, this repository will have a Wiki. Specify this to disable the Wiki. + .PARAMETER HasDiscussions + By default, this repository will not have Discussions. Specify this to enable Discussions. + .PARAMETER AutoInit Specify this to create an initial commit with an empty README. @@ -152,6 +155,8 @@ filter New-GitHubRepository [switch] $NoWiki, + [switch] $HasDiscussions, + [switch] $AutoInit, [switch] $DisallowSquashMerge, @@ -201,6 +206,7 @@ filter New-GitHubRepository if ($PSBoundParameters.ContainsKey('NoIssues')) { $hashBody['has_issues'] = (-not $NoIssues.ToBool()) } if ($PSBoundParameters.ContainsKey('NoProjects')) { $hashBody['has_projects'] = (-not $NoProjects.ToBool()) } if ($PSBoundParameters.ContainsKey('NoWiki')) { $hashBody['has_wiki'] = (-not $NoWiki.ToBool()) } + if ($PSBoundParameters.ContainsKey('HasDiscussions')) { $hashBody['has_discussions'] = ( $HasDiscussions.ToBool()) } if ($PSBoundParameters.ContainsKey('AutoInit')) { $hashBody['auto_init'] = $AutoInit.ToBool() } if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } @@ -1045,6 +1051,9 @@ filter Set-GitHubRepository .PARAMETER NoWiki By default, this repository will have a Wiki. Specify this to disable the Wiki. + .PARAMETER HasDiscussions + By default, this repository will not have Discussions. Specify this to enable Discussions. + .PARAMETER DisallowSquashMerge By default, squash-merging pull requests will be allowed. Specify this to disallow. @@ -1153,6 +1162,8 @@ filter Set-GitHubRepository [switch] $NoWiki, + [switch] $HasDiscussions, + [switch] $DisallowSquashMerge, [switch] $DisallowMergeCommit, @@ -1200,6 +1211,7 @@ filter Set-GitHubRepository if ($PSBoundParameters.ContainsKey('NoIssues')) { $hashBody['has_issues'] = (-not $NoIssues.ToBool()) } if ($PSBoundParameters.ContainsKey('NoProjects')) { $hashBody['has_projects'] = (-not $NoProjects.ToBool()) } if ($PSBoundParameters.ContainsKey('NoWiki')) { $hashBody['has_wiki'] = (-not $NoWiki.ToBool()) } + if ($PSBoundParameters.ContainsKey('HasDiscussions')) { $hashBody['has_discussions'] = ( $HasDiscussions.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 0d5e5d8d..910b73d3 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -51,6 +51,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.has_issues | Should -BeTrue $repo.has_projects | Should -BeTrue $repo.has_Wiki | Should -BeTrue + $repo.has_discussions | Should -BeFalse $repo.allow_squash_merge | Should -BeTrue $repo.allow_merge_commit | Should -BeTrue $repo.allow_rebase_merge | Should -BeTrue @@ -88,6 +89,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.has_issues | Should -BeTrue $repo.has_projects | Should -BeTrue $repo.has_Wiki | Should -BeTrue + $repo.has_discussions | Should -BeFalse $repo.allow_squash_merge | Should -BeTrue $repo.allow_merge_commit | Should -BeTrue $repo.allow_rebase_merge | Should -BeTrue @@ -116,6 +118,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { NoIssues = $true NoProjects = $true NoWiki = $true + HasDiscussions = $true DisallowSquashMerge = $true DisallowMergeCommit = $true DisallowRebaseMerge = $false @@ -139,6 +142,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.has_issues | Should -BeFalse $repo.has_projects | Should -BeFalse $repo.has_Wiki | Should -BeFalse + $repo.has_discussions | Should -BeTrue $repo.allow_squash_merge | Should -BeFalse $repo.allow_merge_commit | Should -BeFalse $repo.allow_rebase_merge | Should -BeTrue @@ -235,6 +239,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.has_issues | Should -BeTrue $repo.has_projects | Should -BeTrue $repo.has_Wiki | Should -BeTrue + $repo.has_discussions | Should -BeFalse $repo.allow_squash_merge | Should -BeTrue $repo.allow_merge_commit | Should -BeTrue $repo.allow_rebase_merge | Should -BeTrue @@ -725,6 +730,7 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { NoIssues = $true NoProjects = $true NoWiki = $true + HasDiscussions = $true DisallowSquashMerge = $true DisallowMergeCommit = $true DisallowRebaseMerge = $false @@ -747,6 +753,7 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { $updatedRepo.has_issues | Should -BeFalse $updatedRepo.has_projects | Should -BeFalse $updatedRepo.has_Wiki | Should -BeFalse + $updatedRepo.has_discussions | Should -BeTrue $updatedRepo.allow_squash_merge | Should -BeFalse $updatedRepo.allow_merge_commit | Should -BeFalse $updatedRepo.allow_rebase_merge | Should -BeTrue From b976e9515cd42d521bd3f4d7ab6fb2b870cd98ed Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Mon, 27 Feb 2023 00:48:55 +0000 Subject: [PATCH 40/51] New/Set-GitHubRepository: Add AllowAutoMerge Parameter Adds the `AllowAutoMerge` parameter to the `New-GitHubRepository` and `Set-GitHubRepository` functions. Fixes #357 References: - https://docs.github.com/en/rest/repos/repos#create-an-organization-repository - https://docs.github.com/en/rest/repos/repos#update-a-repository --- GitHubRepositories.ps1 | 12 +++++++ Tests/GitHubRepositories.tests.ps1 | 50 ++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index fc8c46bd..e245b501 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -86,6 +86,9 @@ filter New-GitHubRepository By default, rebase-merge pull requests will be allowed. Specify this to disallow. + .PARAMETER AllowAutoMerge + Specifies whether to allow auto-merge on pull requests. + .PARAMETER DeleteBranchOnMerge Specifies the automatic deleting of head branches when pull requests are merged. @@ -165,6 +168,8 @@ filter New-GitHubRepository [switch] $DisallowRebaseMerge, + [switch] $AllowAutoMerge, + [switch] $DeleteBranchOnMerge, [switch] $IsTemplate, @@ -211,6 +216,7 @@ filter New-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } + if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } @@ -1066,6 +1072,9 @@ filter Set-GitHubRepository By default, rebase-merge pull requests will be allowed. Specify this to disallow. + .PARAMETER AllowAutoMerge + Specifies whether to allow auto-merge on pull requests. + .PARAMETER DeleteBranchOnMerge Specifies the automatic deleting of head branches when pull requests are merged. @@ -1170,6 +1179,8 @@ filter Set-GitHubRepository [switch] $DisallowRebaseMerge, + [switch] $AllowAutoMerge, + [switch] $DeleteBranchOnMerge, [switch] $IsTemplate, @@ -1215,6 +1226,7 @@ filter Set-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } + if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } if ($PSBoundParameters.ContainsKey('Archived')) { $hashBody['archived'] = $Archived.ToBool() } diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 910b73d3..fa124070 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -105,7 +105,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { } } - Context -Name 'When creating a repository with all possible settings' -Fixture { + Context -Name 'When creating a public repository with all possible settings' -Fixture { BeforeAll -ScriptBlock { $repoName = ([Guid]::NewGuid().Guid) $testGitIgnoreTemplate = (Get-GitHubGitIgnore)[0] @@ -122,6 +122,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { DisallowSquashMerge = $true DisallowMergeCommit = $true DisallowRebaseMerge = $false + AllowAutoMerge = $true DeleteBranchOnMerge = $true GitIgnoreTemplate = $testGitIgnoreTemplate LicenseTemplate = $testLicenseTemplate @@ -146,6 +147,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.allow_squash_merge | Should -BeFalse $repo.allow_merge_commit | Should -BeFalse $repo.allow_rebase_merge | Should -BeTrue + $repo.allow_auto_merge | Should -BeTrue $repo.delete_branch_on_merge | Should -BeTrue $repo.is_template | Should -BeTrue } @@ -166,7 +168,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { } } - Context -Name 'When creating a repository with alternative Merge settings' -Fixture { + Context -Name 'When creating a public repository with alternative Merge settings' -Fixture { BeforeAll -ScriptBlock { $repoName = ([Guid]::NewGuid().Guid) $newGitHubRepositoryParms = @{ @@ -174,6 +176,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { DisallowSquashMerge = $true DisallowMergeCommit = $false DisallowRebaseMerge = $true + AllowAutoMerge = $false } $repo = New-GitHubRepository @newGitHubRepositoryParms } @@ -187,6 +190,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.allow_squash_merge | Should -BeFalse $repo.allow_merge_commit | Should -BeTrue $repo.allow_rebase_merge | Should -BeFalse + $repo.allow_auto_merge | Should -BeFalse } AfterAll -ScriptBlock { @@ -719,6 +723,48 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { $repo = New-GitHubRepository -RepositoryName $repoName } + Context -Name 'When updating a public repository with auto-merge set to true' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + AllowAutoMerge = $true + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_auto_merge | Should -BeTrue + } + } + + Context -Name 'When updating a public repository with auto-merge set to false' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + AllowAutoMerge = $false + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_auto_merge | Should -BeFalse + } + } + Context -Name 'When updating a repository with all possible settings' { BeforeAll -ScriptBlock { $updateGithubRepositoryParms = @{ From 9baf54e44cee7fb79dee74ae54306b1edbe6e7d0 Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Mon, 27 Feb 2023 05:09:25 +0000 Subject: [PATCH 41/51] New/Set-GitHubRepository: Add Support for 'Allow Update Branch' Option Adds the `AllowUpdateBranch` parameter to the `New-GitHubRepository` and `Set-GitHubRepository` functions. Fixes #386 References: - https://docs.github.com/en/rest/repos/repos#create-an-organization-repository - https://docs.github.com/en/rest/repos/repos#update-a-repository --- GitHubRepositories.ps1 | 14 ++++++++++++++ Tests/GitHubRepositories.tests.ps1 | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index e245b501..74f9f41d 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -89,6 +89,10 @@ filter New-GitHubRepository .PARAMETER AllowAutoMerge Specifies whether to allow auto-merge on pull requests. + .PARAMETER AllowUpdateBranch + Specifies whether to always allow a pull request head branch that is behind its base branch + to be updated even if it is not required to be up-to-date before merging. + .PARAMETER DeleteBranchOnMerge Specifies the automatic deleting of head branches when pull requests are merged. @@ -170,6 +174,8 @@ filter New-GitHubRepository [switch] $AllowAutoMerge, + [switch] $AllowUpdateBranch, + [switch] $DeleteBranchOnMerge, [switch] $IsTemplate, @@ -217,6 +223,7 @@ filter New-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } + if ($PSBoundParameters.ContainsKey('AllowUpdateBranch')) { $hashBody['allow_update_branch'] = $AllowUpdateBranch.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } @@ -1075,6 +1082,10 @@ filter Set-GitHubRepository .PARAMETER AllowAutoMerge Specifies whether to allow auto-merge on pull requests. + .PARAMETER AllowUpdateBranch + Specifies whether to always allow a pull request head branch that is behind its base branch + to be updated even if it is not required to be up-to-date before merging. + .PARAMETER DeleteBranchOnMerge Specifies the automatic deleting of head branches when pull requests are merged. @@ -1181,6 +1192,8 @@ filter Set-GitHubRepository [switch] $AllowAutoMerge, + [switch] $AllowUpdateBranch, + [switch] $DeleteBranchOnMerge, [switch] $IsTemplate, @@ -1227,6 +1240,7 @@ filter Set-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } + if ($PSBoundParameters.ContainsKey('AllowUpdateBranch')) { $hashBody['allow_update_branch'] = $AllowUpdateBranch.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } if ($PSBoundParameters.ContainsKey('Archived')) { $hashBody['archived'] = $Archived.ToBool() } diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index fa124070..a573b72b 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -123,6 +123,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { DisallowMergeCommit = $true DisallowRebaseMerge = $false AllowAutoMerge = $true + AllowUpdateBranch = $true DeleteBranchOnMerge = $true GitIgnoreTemplate = $testGitIgnoreTemplate LicenseTemplate = $testLicenseTemplate @@ -148,6 +149,7 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.allow_merge_commit | Should -BeFalse $repo.allow_rebase_merge | Should -BeTrue $repo.allow_auto_merge | Should -BeTrue + $repo.allow_update_branch | Should -BeTrue $repo.delete_branch_on_merge | Should -BeTrue $repo.is_template | Should -BeTrue } @@ -780,6 +782,7 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { DisallowSquashMerge = $true DisallowMergeCommit = $true DisallowRebaseMerge = $false + AllowUpdateBranch = $true DeleteBranchOnMerge = $true IsTemplate = $true } @@ -803,6 +806,7 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { $updatedRepo.allow_squash_merge | Should -BeFalse $updatedRepo.allow_merge_commit | Should -BeFalse $updatedRepo.allow_rebase_merge | Should -BeTrue + $updatedRepo.allow_update_branch | Should -BeTrue $updatedRepo.delete_branch_on_merge | Should -BeTrue $updatedRepo.is_template | Should -BeTrue } From 516be0b4cafafb334bca5951c057af0885e6976f Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Mon, 27 Feb 2023 05:12:19 +0000 Subject: [PATCH 42/51] Set-GitHubRepository: Add Support for 'Web Commit Signoff Required' Option Adds the `WebCommitSignoffRequired` parameter to the `Set-GitHubRepository` function. Fixes #388 References: - https://docs.github.com/en/rest/repos/repos#update-a-repository --- GitHubRepositories.ps1 | 6 ++++++ Tests/GitHubRepositories.tests.ps1 | 2 ++ 2 files changed, 8 insertions(+) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index 74f9f41d..e06d41bf 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -1092,6 +1092,9 @@ filter Set-GitHubRepository .PARAMETER IsTemplate Specifies whether the repository is made available as a template. + .PARAMETER WebCommitSignoffRequired + Specifies whether to require contributors to sign off on web-based commits. + .PARAMETER Archived Specify this to archive this repository. NOTE: You cannot unarchive repositories through the API / this module. @@ -1198,6 +1201,8 @@ filter Set-GitHubRepository [switch] $IsTemplate, + [switch] $WebCommitSignoffRequired, + [switch] $Archived, [switch] $Force, @@ -1243,6 +1248,7 @@ filter Set-GitHubRepository if ($PSBoundParameters.ContainsKey('AllowUpdateBranch')) { $hashBody['allow_update_branch'] = $AllowUpdateBranch.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } if ($PSBoundParameters.ContainsKey('IsTemplate')) { $hashBody['is_template'] = $IsTemplate.ToBool() } + if ($PSBoundParameters.ContainsKey('WebCommitSignoffRequired')) { $hashBody['web_commit_signoff_required'] = $WebCommitSignoffRequired.ToBool() } if ($PSBoundParameters.ContainsKey('Archived')) { $hashBody['archived'] = $Archived.ToBool() } if ($Force -and (-not $Confirm)) diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index a573b72b..22b36fc1 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -785,6 +785,7 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { AllowUpdateBranch = $true DeleteBranchOnMerge = $true IsTemplate = $true + WebCommitSignoffRequired = $true } $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru @@ -809,6 +810,7 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { $updatedRepo.allow_update_branch | Should -BeTrue $updatedRepo.delete_branch_on_merge | Should -BeTrue $updatedRepo.is_template | Should -BeTrue + $updatedRepo.web_commit_signoff_required | Should -BeTrue } } From d5094a0fc87122b07e4a2ad08fefe172493108e5 Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Fri, 21 Apr 2023 01:20:35 +0100 Subject: [PATCH 43/51] Remove has_wiki check (#404) Remove the `has_wiki` property check from the private repositories unit tests as Wikis are no longer supported on the GitHub free tier. Fixes #403 --- Tests/GitHubRepositories.tests.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 22b36fc1..076953d0 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -88,7 +88,6 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.homepage | Should -BeNullOrEmpty $repo.has_issues | Should -BeTrue $repo.has_projects | Should -BeTrue - $repo.has_Wiki | Should -BeTrue $repo.has_discussions | Should -BeFalse $repo.allow_squash_merge | Should -BeTrue $repo.allow_merge_commit | Should -BeTrue @@ -284,7 +283,6 @@ Describe 'GitHubRepositories\New-GitHubRepository' { $repo.homepage | Should -BeNullOrEmpty $repo.has_issues | Should -BeTrue $repo.has_projects | Should -BeTrue - $repo.has_Wiki | Should -BeTrue $repo.allow_squash_merge | Should -BeTrue $repo.allow_merge_commit | Should -BeTrue $repo.allow_rebase_merge | Should -BeTrue From 43d5392642cce2ec3d45fbbb1066f7b2efc3b8c4 Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Sat, 29 Apr 2023 19:54:04 +0100 Subject: [PATCH 44/51] Set-GitHubRepository: Add Support for 'Secret Scanning' Option (#391) Adds the `SecretScanning` parameter to the `Set-GitHubRepository` function. > The parameter was implemented using the `Enabled, Disabled` parameter validate set rather than a switch to mirror the pattern used by the GitHub API. Fixes #390 #### References - https://docs.github.com/en/rest/repos/repos#update-a-repository --- GitHubRepositories.ps1 | 14 ++++++++++++++ Tests/GitHubRepositories.tests.ps1 | 21 +++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index e06d41bf..e6f387c8 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -1049,6 +1049,9 @@ filter Set-GitHubRepository .PARAMETER DefaultBranch Update the default branch for this repository. + .PARAMETER SecretScanning + Specifies whether to enable or disable secret scanning for the repository. + .PARAMETER Private Specify this to make the repository private. To change a repository to be public, specify -Private:$false @@ -1177,6 +1180,9 @@ filter Set-GitHubRepository [string] $DefaultBranch, + [ValidateSet('Enabled', 'Disabled')] + [string] $SecretScanning, + [switch] $Private, [switch] $NoIssues, @@ -1251,6 +1257,14 @@ filter Set-GitHubRepository if ($PSBoundParameters.ContainsKey('WebCommitSignoffRequired')) { $hashBody['web_commit_signoff_required'] = $WebCommitSignoffRequired.ToBool() } if ($PSBoundParameters.ContainsKey('Archived')) { $hashBody['archived'] = $Archived.ToBool() } + $securityAndAnalysis = @{} + if ($PSBoundParameters.ContainsKey('SecretScanning')) { + $securityAndAnalysis['secret_scanning'] = @{ 'status' = $SecretScanning.ToLower()} + } + if ($securityAndAnalysis.Count -ne 0) { + $hashBody['security_and_analysis'] = $securityAndAnalysis + } + if ($Force -and (-not $Confirm)) { $ConfirmPreference = 'None' diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 076953d0..5c8fe9a1 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -723,6 +723,27 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { $repo = New-GitHubRepository -RepositoryName $repoName } + Context -Name 'When updating a public repository with Secret Scanning' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + SecretScanning = 'Enabled' + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.security_and_analysis.secret_scanning.status | Should -Be 'enabled' + } + } + Context -Name 'When updating a public repository with auto-merge set to true' { BeforeAll -ScriptBlock { $updateGithubRepositoryParms = @{ From dd844e5e4a2224e092c8d247f889f6ebabda1767 Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Sun, 30 Apr 2023 19:33:42 +0100 Subject: [PATCH 45/51] API Coverage: Add Support for Deployment Environments (#395) Adds the following new cmdlets for managing GitHub Deployment Environments: - `New-GitHubDeploymentEnvironment` - `Get-GitHubDeploymentEnvironment` - `Set-GitHubDeploymentEnvironment` - `Remove-GitHubDeploymentEnvironment` Fixes #394 #### References - [Deployment Environments](https://docs.github.com/en/rest/deployments/environments) --- Formatters/GitHubDeployments.Format.ps1xml | 26 + GitHubDeployments.ps1 | 616 +++++++++++++++++++++ PowerShellForGitHub.psd1 | 7 + README.md | 1 + Tests/GitHubDeployments.tests.ps1 | 215 +++++++ USAGE.md | 29 + 6 files changed, 894 insertions(+) create mode 100644 Formatters/GitHubDeployments.Format.ps1xml create mode 100644 GitHubDeployments.ps1 create mode 100644 Tests/GitHubDeployments.tests.ps1 diff --git a/Formatters/GitHubDeployments.Format.ps1xml b/Formatters/GitHubDeployments.Format.ps1xml new file mode 100644 index 00000000..d97b982e --- /dev/null +++ b/Formatters/GitHubDeployments.Format.ps1xml @@ -0,0 +1,26 @@ + + + + + + GitHub.DeploymentEnvironment + + GitHub.DeploymentEnvironment + + + + + + + RepositoryUrl + + + EnvironmentName + + + + + + + + diff --git a/GitHubDeployments.ps1 b/GitHubDeployments.ps1 new file mode 100644 index 00000000..bdb9ef54 --- /dev/null +++ b/GitHubDeployments.ps1 @@ -0,0 +1,616 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +@{ + GitHubDeploymentEnvironmentTypeName = 'GitHub.DeploymentEnvironment' +}.GetEnumerator() | ForEach-Object { + Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value +} + +filter New-GitHubDeploymentEnvironment +{ + <# + .SYNOPSIS + Creates or updates a deployment environment on a GitHub repository. + + .DESCRIPTION + Creates or updates a deployment environment on a GitHub repository. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER EnvironmentName + The name of the environment. + + .PARAMETER WaitTimer + The amount of time to delay a job after the job is initially triggered. + The time (in minutes) must be an integer between 0 and 43,200 (30 days). + + .PARAMETER DeploymentBranchPolicy + Whether only branches with branch protection rules or that match the specified name patterns + can deploy to this environment. + + .PARAMETER ReviewerTeamId + The teams that may review jobs that reference the environment. + You can list up to six users and/or teams as reviewers. + The reviewers must have at least read access to the repository. + Only one of the required reviewers needs to approve the job for it to proceed. + + .PARAMETER ReviewerUserId + The users that may review jobs that reference the environment. + You can list up to six users and/or teams as reviewers. + The reviewers must have at least read access to the repository. + Only one of the required reviewers needs to approve the job for it to proceed. + + .PARAMETER PassThru + Returns the updated environment. By default, the Set-GitHubDeploymentEnvironment cmdlet + does not generate any output. + You can use "Set-GitHubConfiguration -DefaultPassThru" to control the default behavior + of this switch. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.DeploymentEnvironment + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .OUTPUTS + GitHub.DeploymentEnvironment + + .EXAMPLE + New-GitHubDeploymentEnvironment -OwnerName microsoft -RepositoryName PowerShellForGitHub -EnvironmentName 'Test' + + Creates or updates a deployment environment called 'Test' for the specified repo. +#> + [CmdletBinding( + SupportsShouldProcess, + DefaultParameterSetName = 'Elements')] + [OutputType({ $script:GitHubDeploymentEnvironmentTypeName })] + [Alias('Set-GitHubDeploymentEnvironment')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter(ParameterSetName = 'Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName = 'Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string] $EnvironmentName, + + [ValidateRange(0, 43200)] + [int32] $WaitTimer, + + [ValidateSet('ProtectedBranches', 'CustomBranchPolicies', 'None')] + [string] $DeploymentBranchPolicy, + + [int64[]] $ReviewerTeamId, + + [int64[]] $ReviewerUserId, + + [switch] $PassThru, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + if ($MyInvocation.InvocationName -eq 'Set-GitHubDeploymentEnvironment') + { + $shouldProcessMessage = "Update GitHub Deployment Environment '$EnvironmentName'" + } + else + { + $shouldProcessMessage = "Create GitHub Deployment Environment '$EnvironmentName'" + } + + $hashBody = @{} + + if ($PSBoundParameters.ContainsKey('WaitTimer')) { $hashBody['wait_timer'] = $WaitTimer } + if ($PSBoundParameters.ContainsKey('DeploymentBranchPolicy')) { + $deploymentBranchPolicyHash = @{} + switch ($DeploymentBranchPolicy) { + 'ProtectedBranches' { + $deploymentBranchPolicyHash['protected_branches'] = $true + $deploymentBranchPolicyHash['custom_branch_policies'] = $false + } + 'CustomBranchPolicies' { + $deploymentBranchPolicyHash['protected_branches'] = $false + $deploymentBranchPolicyHash['custom_branch_policies'] = $true + } + 'None' { + $deploymentBranchPolicyHash = $null + } + } + $hashBody['deployment_branch_policy'] = $deploymentBranchPolicyHash + } + if ($PSBoundParameters.ContainsKey('ReviewerTeamId') -or + $PSBoundParameters.ContainsKey('ReviewerUserId')) + { + $reviewers = @() + foreach ($teamId in $ReviewerTeamId) { + $reviewers += @{ 'type' = 'Team'; 'id' = $teamId} + } + foreach ($userId in $ReviewerUserId) { + $reviewers += @{ 'type' = 'User'; 'id' = $userId} + } + $hashBody['reviewers'] = $reviewers + } + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/environments/$EnvironmentName" + 'Body' = (ConvertTo-Json -InputObject $hashBody) + 'Method' = 'Put' + 'Description' = "Creating Deployment Environment $EnvironmentName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + } + + Write-Debug -Message ('UriFragment: ' + $params.UriFragment) + Write-Debug -Message ('Body: ' + $params.Body) + + if (-not $PSCmdlet.ShouldProcess($RepositoryName, $shouldProcessMessage)) + { + return + } + + $result = (Invoke-GHRestMethod @params | Add-GitHubDeploymentEnvironmentAdditionalProperties) + + if (($MyInvocation.InvocationName -eq 'New-GitHubDeploymentEnvironment') -or + (Resolve-ParameterWithDefaultConfigurationValue -Name PassThru -ConfigValueName DefaultPassThru)) + { + return $result + } +} + +filter Remove-GitHubDeploymentEnvironment +{ +<# + .SYNOPSIS + Removes a deployment environment from a GitHub repository. + + .DESCRIPTION + Removes a deployment environment from a GitHub repository. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER EnvironmentName + The name of the deployment environment to remove. + + .PARAMETER Force + If this switch is specified, you will not be prompted for confirmation of command execution. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.DeploymentEnvironment + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .EXAMPLE + Remove-GitHubDeploymentEnvironment -OwnerName You -RepositoryName RepoName -EnvironmentName EnvToDelete + + .EXAMPLE + Remove-GitHubDeploymentEnvironment -Uri https://github.com/You/YourRepo -EnvironmentName EnvToDelete + + .EXAMPLE + Remove-GitHubDeploymentEnvironment -Uri https://github.com/You/YourRepo -EnvironmentName EnvToDelete -Confirm:$false + + Remove the deployment environment from the repository without prompting for confirmation. + + .EXAMPLE + Remove-GitHubDeploymentEnvironment -Uri https://github.com/You/YourRepo -EnvironmentName EnvToDelete -Force + + Remove the deployment environment from the repository without prompting for confirmation. + + .EXAMPLE + $repo = Get-GitHubRepository -Uri https://github.com/You/YourRepo + $repo | Remove-GitHubDeploymentEnvironment -EnvironmentName EnvToDelete -Force + + You can also pipe in a repo that was returned from a previous command. +#> + [CmdletBinding( + SupportsShouldProcess, + DefaultParameterSetName='Elements', + ConfirmImpact = 'High')] + [Alias('Delete-GitHubDeploymentEnvironment')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter(ParameterSetName='Elements')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string] $EnvironmentName, + + [switch] $Force, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + $params = @{ + 'UriFragment' = "repos/$OwnerName/$RepositoryName/environments/$EnvironmentName" + 'Method' = 'Delete' + 'Description' = "Deleting $EnvironmentName from $RepositoryName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + } + + Write-Debug -Message ('UriFragment: ' + $params.UriFragment) + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + if (-not $PSCmdlet.ShouldProcess($RepositoryName, "Remove Deployment Environment '$EnvironmentName'")) + { + return + } + + return Invoke-GHRestMethod @params +} + +filter Get-GitHubDeploymentEnvironment +{ +<# + .SYNOPSIS + Retrieves information about a deployment environment or list of deployment environments on GitHub. + + .DESCRIPTION + Retrieves information about a deployment environment or list of deployment environments on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the repository. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER EnvironmentName + The name of the deployment environment. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.DeploymentEnvironment + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Reaction + GitHub.Release + GitHub.ReleaseAsset + GitHub.Repository + + .OUTPUTS + GitHub.DeploymentEnvironment + + .EXAMPLE + Get-GitHubDeploymentEnvironment -OwnerName microsoft -RepositoryName PowerShellForGitHub + + Gets details of all of the deployment environments for the specified repository. + + .EXAMPLE + Get-GitHubDeploymentEnvironment -OwnerName microsoft -RepositoryName PowerShellForGitHub -EnvironmentName Test + + Gets details of the Test deployment environment for the specified repository. +#> +[CmdletBinding(DefaultParameterSetName = 'Elements')] + [OutputType({$script:GitHubRepositoryTypeName})] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1.")] + param( + [Parameter( + ValueFromPipelineByPropertyName, + ParameterSetName='Elements')] + [Alias('UserName')] + [string] $OwnerName, + + [Parameter(ParameterSetName='Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName='Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [string] $EnvironmentName, + + [string] $AccessToken + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties = @{ + 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) + 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) + } + + if ($PSBoundParameters.ContainsKey('EnvironmentName')) + { + $uriFragment = "repos/$OwnerName/$RepositoryName/environments/$EnvironmentName" + } + else + { + $uriFragment = "repos/$OwnerName/$RepositoryName/environments" + } + + $params = @{ + 'UriFragment' = $uriFragment + 'Method' = 'Get' + 'Description' = "Getting $EnvironmentName from $RepositoryName" + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + } + + Write-Debug -Message ('UriFragment: ' + $params.UriFragment) + + $result = Invoke-GHRestMethod @params + + if ($PSBoundParameters.ContainsKey('EnvironmentName')) + { + return ($result | Add-GitHubDeploymentEnvironmentAdditionalProperties) + } + else + { + return ($result.environments | Add-GitHubDeploymentEnvironmentAdditionalProperties) + } +} + +filter Add-GitHubDeploymentEnvironmentAdditionalProperties +{ +<# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Deployment Environment + objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .PARAMETER OwnerName + Owner of the repository. This information might be obtainable from InputObject, so this + is optional based on what InputObject contains. + + .PARAMETER RepositoryName + Name of the repository. This information might be obtainable from InputObject, so this + is optional based on what InputObject contains. + + .INPUTS + [PSCustomObject] + + .OUTPUTS + GitHub.Repository +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Internal helper that is definitely adding more than one property.")] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubDeploymentEnvironmentTypeName, + + [string] $OwnerName, + + [string] $RepositoryName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + $repositoryUrl = [String]::Empty + if ([String]::IsNullOrEmpty($item.html_url)) + { + if ($PSBoundParameters.ContainsKey('OwnerName') -and + $PSBoundParameters.ContainsKey('RepositoryName')) + { + $repositoryUrl = (Join-GitHubUri -OwnerName $OwnerName -RepositoryName $RepositoryName) + } + } + else + { + $elements = Split-GitHubUri -Uri $item.html_url + $repositoryUrl = Join-GitHubUri @elements + } + + if (-not [String]::IsNullOrEmpty($repositoryUrl)) + { + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force + } + } + + Add-Member -InputObject $item -Name 'EnvironmentName' -Value $item.name -MemberType NoteProperty -Force + + # Add additional properties for any user or team reviewers + if ($null -ne $item.protection_rules) + { + foreach ($protectionRule in $item.protection_rules) + { + if ($protectionRule.type -eq 'required_reviewers') + { + $reviewerUser = @() + $reviewerTeam = @() + + foreach ($reviewer in $protectionRule.reviewers) + { + if ($reviewer.type -eq 'User') + { + $reviewerUser += Add-GitHubUserAdditionalProperties -InputObject $reviewer.reviewer + } + if ($reviewer.type -eq 'Team') + { + $reviewerTeam += Add-GitHubTeamAdditionalProperties -InputObject $reviewer.reviewer + } + } + + if ($reviewerUser.count -gt 0) + { + Add-Member -InputObject $item -Name 'ReviewerUser' -Value $reviewerUser -MemberType NoteProperty -Force + } + + if ($reviewerTeam.count -gt 0) + { + Add-Member -InputObject $item -Name 'ReviewerTeam' -Value $reviewerTeam -MemberType NoteProperty -Force + } + } + + if ($protectionRule.type -eq 'wait_timer') + { + Add-Member -InputObject $item -Name 'WaitTimer' -Value $protectionRule.wait_timer -MemberType NoteProperty -Force + } + } + } + + if ($null -eq $item.deployment_branch_policy) + { + $deploymentBranchPolicy = 'None' + } + elseif ($item.deployment_branch_policy.protected_branches -eq $true) + { + $deploymentBranchPolicy = 'ProtectedBranches' + } + elseif ($item.deployment_branch_policy.custom_branch_policies -eq $true) + { + $deploymentBranchPolicy = 'CustomBranchPolicies' + } + Add-Member -InputObject $item -Name 'DeploymentBranchPolicy' -Value $deploymentBranchPolicy -MemberType NoteProperty -Force + + Write-Output $item + } +} diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 44369427..a7027f96 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -16,6 +16,7 @@ # Format files (.ps1xml) to be loaded when importing this module FormatsToProcess = @( 'Formatters/GitHubBranches.Format.ps1xml', + 'Formatters/GitHubDeployments.Format.ps1xml', 'Formatters/GitHubGistComments.Format.ps1xml', 'Formatters/GitHubGists.Format.ps1xml', 'Formatters/GitHubReleases.Format.ps1xml' @@ -56,6 +57,7 @@ 'GitHubRepositoryTraffic.ps1', 'GitHubTeams.ps1', 'GitHubUsers.ps1', + 'GitHubDeployments.ps1', 'Telemetry.ps1', 'UpdateCheck.ps1') @@ -80,6 +82,7 @@ 'Get-GitHubCodeOfConduct', 'Get-GitHubConfiguration', 'Get-GitHubContent', + 'Get-GitHubDeploymentEnvironment', 'Get-GitHubEmoji', 'Get-GitHubEvent', 'Get-GitHubGist', @@ -131,6 +134,7 @@ 'Move-GitHubProjectCard', 'Move-GitHubProjectColumn', 'Move-GitHubRepositoryOwnership', + 'New-GitHubDeploymentEnvironment', 'New-GitHubGist', 'New-GitHubGistComment', 'New-GitHubIssue', @@ -152,6 +156,7 @@ 'New-GitHubTeam', 'Remove-GitHubAssignee', 'Remove-GitHubComment', + 'Remove-GitHubDeploymentEnvironment' 'Remove-GitHubGist', 'Remove-GitHubGistComment', 'Remove-GitHubGistFile', @@ -215,6 +220,7 @@ 'Delete-GitHubAsset', 'Delete-GitHubBranch', 'Delete-GitHubComment', + 'Delete-GitHubDeploymentEnvironment', 'Delete-GitHubGist', 'Delete-GitHubGistComment', 'Delete-GitHubGistFile', @@ -246,6 +252,7 @@ 'Remove-GitHubComment', 'Set-GitHubAsset', 'Set-GitHubComment', + 'Set-GitHubDeploymentEnvironment', 'Star-GitHubGist', 'Transfer-GitHubRepositoryOwnership' 'Unstar-GitHubGist' diff --git a/README.md b/README.md index 0d06c3b2..b549931a 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ At present, this module can: as well as gist comments. * Query, edit and remove [reactions](https://developer.github.com/v3/reactions/) on Issues and Pull Requests. +* Query, create, edit and remove [Deployment Environments](https://docs.github.com/en/rest/deployments/environments) * Miscellaneous functionality: * Get all [Codes of Conduct](https://developer.github.com/v3/codes_of_conduct/) as well as that of a specific repo. diff --git a/Tests/GitHubDeployments.tests.ps1 b/Tests/GitHubDeployments.tests.ps1 new file mode 100644 index 00000000..325b583b --- /dev/null +++ b/Tests/GitHubDeployments.tests.ps1 @@ -0,0 +1,215 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# +.Synopsis + Tests for GitHubDeployments.ps1 module +#> + +[CmdletBinding()] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', + Justification = 'Suppress false positives in Pester code blocks')] +param() + +Set-StrictMode -Version 1.0 + +# This is common test code setup logic for all Pester test files +BeforeAll { + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') + + $repoName = ([Guid]::NewGuid().Guid) + $newGitHubRepositoryParms = @{ + RepositoryName = $repoName + OrganizationName = $script:organizationName + Private = $false + } + $repo = New-GitHubRepository @newGitHubRepositoryParms + + $team1Name = [Guid]::NewGuid().Guid + $team2Name = [Guid]::NewGuid().Guid + $description = 'Team Description' + $privacy = 'closed' + $maintainerName = $script:ownerName + + $newGithubTeamParms = @{ + OrganizationName = $script:organizationName + Description = $description + Privacy = $privacy + MaintainerName = $MaintainerName + } + + $reviewerTeam1 = New-GitHubTeam @newGithubTeamParms -TeamName $team1Name + $reviewerTeam2 = New-GitHubTeam @newGithubTeamParms -TeamName $team2Name + $reviewerTeamId = $reviewerTeam1.TeamId, $reviewerTeam2.TeamId + $reviewerUser = Get-GitHubUser -UserName $script:ownerName + + $repo | Set-GitHubRepositoryTeamPermission -TeamSlug $reviewerTeam1.TeamSlug -Permission Push + $repo | Set-GitHubRepositoryTeamPermission -TeamSlug $reviewerTeam2.TeamSlug -Permission Push +} + +Describe 'GitHubDeployments\New-GitHubDeploymentEnvironment' { + Context -Name 'When creating a new deployment environment' -Fixture { + BeforeAll -ScriptBlock { + $environmentName = [Guid]::NewGuid().Guid + $waitTimer = 50 + $deploymentBranchPolicy = 'ProtectedBranches' + + $newGitHubDeploymentEnvironmentParms = @{ + EnvironmentName = $environmentName + WaitTimer = $waitTimer + DeploymentBranchPolicy = $deploymentBranchPolicy + ReviewerTeamId = $reviewerTeamId + ReviewerUserId = $reviewerUser.UserId + } + $environment = $repo | New-GitHubDeploymentEnvironment @newGitHubDeploymentEnvironmentParms + } + + It 'Should return an object of the correct type' { + $environment.PSObject.TypeNames[0] | Should -Be 'GitHub.DeploymentEnvironment' + } + + It 'Should return the correct properties' { + $environment.name | Should -Be $environmentName + $environment.RepositoryUrl | Should -Be $repo.RepositoryUrl + $environment.EnvironmentName | Should -Be $environmentName + $environment.ReviewerUser[0].UserName | Should -Be $reviewerUser.UserName + $environment.ReviewerUser[0].UserId | Should -Be $reviewerUser.UserId + $environment.ReviewerTeam.count | Should -Be $reviewerTeamId.count + $environment.ReviewerTeam[0].TeamName | Should -Be $reviewerTeam1.TeamName + $environment.ReviewerTeam[0].TeamId | Should -Be $reviewerTeam1.TeamId + $environment.ReviewerTeam[1].TeamName | Should -Be $reviewerTeam2.TeamName + $environment.ReviewerTeam[1].TeamId | Should -Be $reviewerTeam2.TeamId + $environment.WaitTimer | Should -Be $waitTimer + $environment.DeploymentBranchPolicy | Should -Be $deploymentBranchPolicy + } + } +} + +Describe 'GitHubDeployments\Set-GitHubDeploymentEnvironment' { + Context -Name 'When updating a deployment environment' -Fixture { + BeforeAll -ScriptBlock { + $environmentName = [Guid]::NewGuid().Guid + $waitTimer = 50 + $deploymentBranchPolicy = 'ProtectedBranches' + + $environment = $repo | New-GitHubDeploymentEnvironment -EnvironmentName $environmentName + + $setGitHubDeploymentEnvironmentParms = @{ + EnvironmentName = $environmentName + WaitTimer = $waitTimer + DeploymentBranchPolicy = $deploymentBranchPolicy + ReviewerTeamId = $reviewerTeam1.TeamId, $reviewerTeam2.TeamId + ReviewerUserId = $reviewerUser.UserId + PassThru = $true + } + $updatedEnvironment = $environment | Set-GitHubDeploymentEnvironment @setGitHubDeploymentEnvironmentParms + } + + It 'Should return an object of the correct type' { + $updatedEnvironment.PSObject.TypeNames[0] | Should -Be 'GitHub.DeploymentEnvironment' + } + + It 'Should return the correct properties' { + $updatedEnvironment.name | Should -Be $environmentName + $updatedEnvironment.RepositoryUrl | Should -Be $repo.RepositoryUrl + $updatedEnvironment.EnvironmentName | Should -Be $environmentName + $updatedenvironment.ReviewerUser[0].UserName | Should -Be $reviewerUser.UserName + $updatedenvironment.ReviewerUser[0].UserId | Should -Be $reviewerUser.UserId + $updatedenvironment.ReviewerTeam.count | Should -Be $reviewerTeamId.count + $updatedenvironment.ReviewerTeam[0].TeamName | Should -Be $reviewerTeam1.TeamName + $updatedenvironment.ReviewerTeam[0].TeamId | Should -Be $reviewerTeam1.TeamId + $updatedenvironment.ReviewerTeam[1].TeamName | Should -Be $reviewerTeam2.TeamName + $updatedenvironment.ReviewerTeam[1].TeamId | Should -Be $reviewerTeam2.TeamId + $updatedenvironment.WaitTimer | Should -Be $waitTimer + $updatedenvironment.DeploymentBranchPolicy | Should -Be $deploymentBranchPolicy + } + } +} + +Describe 'GitHubDeployments\Get-GitHubDeploymentEnvironment' { + + Context -Name 'When getting a deployment environment' -Fixture { + BeforeAll -ScriptBlock { + $environmentName = [Guid]::NewGuid().Guid + $waitTimer = 50 + $deploymentBranchPolicy = 'ProtectedBranches' + + $newGitHubDeploymentEnvironmentParms = @{ + EnvironmentName = $environmentName + WaitTimer = $waitTimer + DeploymentBranchPolicy = $deploymentBranchPolicy + ReviewerTeamId = $reviewerTeamId + ReviewerUserId = $reviewerUser.UserId + } + $repo | New-GitHubDeploymentEnvironment @newGitHubDeploymentEnvironmentParms | Out-Null + + $environment = $repo | Get-GitHubDeploymentEnvironment -EnvironmentName $environmentName + } + + It 'Should return an object of the correct type' { + $environment.PSObject.TypeNames[0] | Should -Be 'GitHub.DeploymentEnvironment' + } + + It 'Should return the correct properties' { + $environment.name | Should -Be $environmentName + $environment.RepositoryUrl | Should -Be $repo.RepositoryUrl + $environment.EnvironmentName | Should -Be $environmentName + $environment.ReviewerUser[0].UserName | Should -Be $reviewerUser.UserName + $environment.ReviewerUser[0].UserId | Should -Be $reviewerUser.UserId + $environment.ReviewerTeam.count | Should -Be $reviewerTeamId.count + $environment.ReviewerTeam[0].TeamName | Should -Be $reviewerTeam1.TeamName + $environment.ReviewerTeam[0].TeamId | Should -Be $reviewerTeam1.TeamId + $environment.ReviewerTeam[1].TeamName | Should -Be $reviewerTeam2.TeamName + $environment.ReviewerTeam[1].TeamId | Should -Be $reviewerTeam2.TeamId + $environment.WaitTimer | Should -Be $waitTimer + $environment.DeploymentBranchPolicy | Should -Be $deploymentBranchPolicy + } + } +} + +Describe 'GitHubDeployments\Remove-GitHubDeploymentEnvironment' { + + Context -Name 'When removing a deployment environment' -Fixture { + BeforeAll -ScriptBlock { + $environmentName = [Guid]::NewGuid().Guid + $waitTimer = 50 + $deploymentBranchPolicy = 'ProtectedBranches' + + $newGitHubDeploymentEnvironmentParms = @{ + EnvironmentName = $environmentName + WaitTimer = $waitTimer + DeploymentBranchPolicy = $deploymentBranchPolicy + ReviewerTeamId = $reviewerTeam1.id + ReviewerUserId = $reviewerUser.UserId + } + $environment = $repo | New-GitHubDeploymentEnvironment @newGitHubDeploymentEnvironmentParms + } + + It 'Should not throw an exception' { + { $environment | Remove-GitHubDeploymentEnvironment -Confirm:$false } | Should -Not -Throw + } + + It 'Should have removed the deployment environment' { + { $repo | Get-GitHubDeploymentEnvironment -EnvironmentName $environmentName } | ` + Should -Throw '*Not Found*' + } + } +} + +AfterAll -ScriptBlock { + if ($repo) + { + $repo | Remove-GitHubRepository -Confirm:$false + } + + if ($reviewerTeam1) + { + $reviewerTeam1 | Remove-GitHubTeam -Confirm:$false + } + + if ($reviewerTeam2) + { + $reviewerTeam2 | Remove-GitHubTeam -Confirm:$false + } +} diff --git a/USAGE.md b/USAGE.md index 1edffac6..a3acb876 100644 --- a/USAGE.md +++ b/USAGE.md @@ -134,6 +134,11 @@ * [Adding a gist comment](#adding-a-gist-comment) * [Changing a gist comment](#changing-a-gist-comment) * [Removing a gist comment](#removing-a-gist-comment) + * [Deployments Environments](#deployment-environments) + * [Adding a new environment](#adding-a-new-environment) + * [Getting details of an environment](#getting-details-of-an-environment) + * [Updating an environment](#updating-an-environment) + * [Removing an environment](#removing-an-environment) * [Advanced](#advanced) * [Migrating blog comments to GitHub issues](#migrating-blog-comments-to-github-issues) @@ -1241,6 +1246,30 @@ Get-GitHubGist -Gist $gistId -Comment $commentId | Remove-GitHubGistComment -For ---------- +### Deployment Environments + +#### Adding a new environment +```powershell +New-GitHubDeploymentEnvironment -OwnerName microsoft -RepositoryName TestRepo -Environment Test +``` + +#### Getting details of an environment +```powershell +Get-GitHubDeploymentEnvironment -OwnerName microsoft -RepositoryName TestRepo -Environment Test +``` + +#### Updating an environment +```powershell +Set-GitHubDeploymentEnvironment -OwnerName microsoft -RepositoryName TestRepo -Environment Test -DeploymentBranchPolicy ProtectedBranches +``` + +#### Removing an environment +```powershell +Remove-GitHubDeploymentEnvironment -OwnerName microsoft -RepositoryName TestRepo -Environment Test +``` + +---------- + ### Advanced #### Migrating blog comments to GitHub issues From 6f94a9b0a37ee466c2fb457299c78de1bd371f95 Mon Sep 17 00:00:00 2001 From: Simon Heather <32168619+X-Guardian@users.noreply.github.com> Date: Tue, 2 May 2023 02:12:49 +0100 Subject: [PATCH 46/51] New/Set-GitHubRepository: Add Support for Merge Commit Title and Message Options (#385) Adds merge commit message and title parameters to the `New-GitHubRepository` and `Set-GitHubRepository` functions. Fixes #384 #### References - https://docs.github.com/en/rest/repos/repos#create-an-organization-repository - https://docs.github.com/en/rest/repos/repos#update-a-repository --- GitHubRepositories.ps1 | 107 ++++++++ Tests/GitHubRepositories.tests.ps1 | 399 +++++++++++++++++++++++++++++ 2 files changed, 506 insertions(+) diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index e6f387c8..403fddf5 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -11,6 +11,25 @@ GitHubRepositoryLanguageTypeName = 'GitHub.RepositoryLanguage' GitHubRepositoryTagTypeName = 'GitHub.RepositoryTag' GitHubRepositoryTeamPermissionTypeName = 'GitHub.RepositoryTeamPermission' + SquashMergeCommitTitleConversion = @{ + 'PRTitle' = 'PR_TITLE' + 'CommitOrPRTitle' = 'COMMIT_OR_PR_TITLE' + 'MergeMessage' = 'MERGE_MESSAGE' + } + SquashMergeCommitMessageConversion = @{ + 'PRBody' = 'PR_BODY' + 'CommitMessages' = 'COMMIT_MESSAGES' + 'Blank' = 'BLANK' + } + MergeCommitTitleConversion = @{ + 'PRTitle' = 'PR_TITLE' + 'MergeMessage' = 'MERGE_MESSAGE' + } + MergeCommitMessageConversion = @{ + 'PRTitle' = 'PR_TITLE' + 'PRBody' = 'PR_BODY' + 'Blank' = 'BLANK' + } }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } @@ -86,6 +105,34 @@ filter New-GitHubRepository By default, rebase-merge pull requests will be allowed. Specify this to disallow. + .PARAMETER SquashMergeCommitTitle + Specifies the default value for a squash merge commit title. This can be one of the + following values: + - 'PRTitle' - default to the pull request's title. + - 'CommitOrPRTitle' - default to the commit's title (if only one commit) or the pull + request's title (when more than one commit). + + .PARAMETER SquashMergeCommitMessage + Specifies the default value for a squash merge commit message. This can be one of the + following values: + - 'PRBody' - default to the pull request's body. + - 'CommitMessages' - default to the branch's commit messages. + - Blank - default to a blank commit message. + + .PARAMETER MergeCommitTitle + Specifies the default value for a merge commit title. This can be one of the + following values: + - 'PRTitle' - default to the pull request's title. + - 'MergeMessage' - default to the classic title for a merge message (e.g., Merge pull request + #123 from branch-name). + + .PARAMETER MergeCommitMessage + Specifies the default vaule for a merge commit message. This can be one of the + following values: + - 'PRTitle' - default to the pull request's title. + - 'PRBody' - default to the pull request's body. + - 'Blank' - default to a blank commit message. + .PARAMETER AllowAutoMerge Specifies whether to allow auto-merge on pull requests. @@ -172,6 +219,18 @@ filter New-GitHubRepository [switch] $DisallowRebaseMerge, + [ValidateSet('PRTitle', 'CommitOrPRTitle')] + [string] $SquashMergeCommitTitle, + + [ValidateSet('PRBody', 'CommitMessages', 'Blank')] + [string] $SquashMergeCommitMessage, + + [ValidateSet('PRTitle', 'MergeMessage')] + [string] $MergeCommitTitle, + + [ValidateSet('PRTitle', 'PRBody', 'Blank')] + [string] $MergeCommitMessage, + [switch] $AllowAutoMerge, [switch] $AllowUpdateBranch, @@ -222,6 +281,10 @@ filter New-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } + if ($PSBoundParameters.ContainsKey('SquashMergeCommitTitle')) { $hashBody['squash_merge_commit_title'] = $script:SquashMergeCommitTitleConversion.$SquashMergeCommitTitle } + if ($PSBoundParameters.ContainsKey('SquashMergeCommitMessage')) { $hashBody['squash_merge_commit_message'] = $script:SquashMergeCommitMessageConversion.$SquashMergeCommitMessage } + if ($PSBoundParameters.ContainsKey('MergeCommitTitle')) { $hashBody['merge_commit_title'] = $script:MergeCommitTitleConversion.$MergeCommitTitle } + if ($PSBoundParameters.ContainsKey('MergeCommitMessage')) { $hashBody['merge_commit_message'] = $script:MergeCommitMessageConversion.$MergeCommitMessage } if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } if ($PSBoundParameters.ContainsKey('AllowUpdateBranch')) { $hashBody['allow_update_branch'] = $AllowUpdateBranch.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } @@ -1082,6 +1145,34 @@ filter Set-GitHubRepository By default, rebase-merge pull requests will be allowed. Specify this to disallow. + .PARAMETER SquashMergeCommitTitle + Specifies the default value for a squash merge commit title. This can be one of the + following values: + - PRTitle - default to the pull request's title. + - CommitOrPRTitle - default to the commit's title (if only one commit) or the pull + request's title (when more than one commit). + + .PARAMETER SquashMergeCommitMessage + Specifies the default value for a squash merge commit message. This can be one of the + following values: + - PRBody - default to the pull request's body. + - CommitMessages - default to the branch's commit messages. + - Blank - default to a blank commit message. + + .PARAMETER MergeCommitTitle + Specifies the default value for a merge commit title. This can be one of the + following values: + - PRTitle - default to the pull request's title. + - MergeMessage - default to the classic title for a merge message (e.g., Merge pull request + #123 from branch-name). + + .PARAMETER MergeCommitMessage + Specifies the default vaule for a merge commit message. This can be one of the + following values: + - PRTitle - default to the pull request's title. + - PRBody - default to the pull request's body. + - Blank - default to a blank commit message. + .PARAMETER AllowAutoMerge Specifies whether to allow auto-merge on pull requests. @@ -1199,6 +1290,18 @@ filter Set-GitHubRepository [switch] $DisallowRebaseMerge, + [ValidateSet('PRTitle', 'CommitOrPRTitle')] + [string] $SquashMergeCommitTitle, + + [ValidateSet('PRBody', 'CommitMessages', 'Blank')] + [string] $SquashMergeCommitMessage, + + [ValidateSet('PRTitle', 'MergeMessage')] + [string] $MergeCommitTitle, + + [ValidateSet('PRTitle', 'PRBody', 'Blank')] + [string] $MergeCommitMessage, + [switch] $AllowAutoMerge, [switch] $AllowUpdateBranch, @@ -1250,6 +1353,10 @@ filter Set-GitHubRepository if ($PSBoundParameters.ContainsKey('DisallowSquashMerge')) { $hashBody['allow_squash_merge'] = (-not $DisallowSquashMerge.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowMergeCommit')) { $hashBody['allow_merge_commit'] = (-not $DisallowMergeCommit.ToBool()) } if ($PSBoundParameters.ContainsKey('DisallowRebaseMerge')) { $hashBody['allow_rebase_merge'] = (-not $DisallowRebaseMerge.ToBool()) } + if ($PSBoundParameters.ContainsKey('SquashMergeCommitTitle')) { $hashBody['squash_merge_commit_title'] = $script:SquashMergeCommitTitleConversion.$SquashMergeCommitTitle } + if ($PSBoundParameters.ContainsKey('SquashMergeCommitMessage')) { $hashBody['squash_merge_commit_message'] = $script:SquashMergeCommitMessageConversion.$SquashMergeCommitMessage } + if ($PSBoundParameters.ContainsKey('MergeCommitTitle')) { $hashBody['merge_commit_title'] = $script:MergeCommitTitleConversion.$MergeCommitTitle } + if ($PSBoundParameters.ContainsKey('MergeCommitMessage')) { $hashBody['merge_commit_message'] = $script:MergeCommitMessageConversion.$MergeCommitMessage } if ($PSBoundParameters.ContainsKey('AllowAutoMerge')) { $hashBody['allow_auto_merge'] = $AllowAutoMerge.ToBool() } if ($PSBoundParameters.ContainsKey('AllowUpdateBranch')) { $hashBody['allow_update_branch'] = $AllowUpdateBranch.ToBool() } if ($PSBoundParameters.ContainsKey('DeleteBranchOnMerge')) { $hashBody['delete_branch_on_merge'] = $DeleteBranchOnMerge.ToBool() } diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 5c8fe9a1..ee477fd7 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -202,6 +202,230 @@ Describe 'GitHubRepositories\New-GitHubRepository' { } } + Context -Name 'When creating a repository with Squash Merge Commit PR Title' { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + DisallowSquashMerge = $false + SquashMergeCommitTitle = 'PRTitle' + SquashMergeCommitMessage = 'Blank' + } + + $repo = New-GitHubRepository @newGithubRepositoryParms + } + + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.allow_squash_merge | Should -BeTrue + $repo.squash_merge_commit_title | Should -Be 'PR_TITLE' + $repo.squash_merge_commit_message | Should -Be 'BLANK' + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + + Context -Name 'When creating a repository with Squash Merge Commit PR Title and Commit details' { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + DisallowSquashMerge = $false + SquashMergeCommitTitle = 'PRTitle' + SquashMergeCommitMessage = 'CommitMessages' + } + + $repo = New-GitHubRepository @newGithubRepositoryParms + } + + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.allow_squash_merge | Should -BeTrue + $repo.squash_merge_commit_title | Should -Be 'PR_TITLE' + $repo.squash_merge_commit_message | Should -Be 'COMMIT_MESSAGES' + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + + Context -Name 'When creating a repository with Squash Merge Commit PR Title and Description' { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + DisallowSquashMerge = $false + SquashMergeCommitTitle = 'PRTitle' + SquashMergeCommitMessage = 'PRBody' + } + + $repo = New-GitHubRepository @newGithubRepositoryParms + } + + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.allow_squash_merge | Should -BeTrue + $repo.squash_merge_commit_title | Should -Be 'PR_TITLE' + $repo.squash_merge_commit_message | Should -Be 'PR_BODY' + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + + Context -Name 'When creating a repository with Squash Merge Commit default message' { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + DisallowSquashMerge = $false + SquashMergeCommitTitle = 'CommitOrPRTitle' + SquashMergeCommitMessage = 'CommitMessages' + } + + $repo = New-GitHubRepository @newGithubRepositoryParms + } + + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.allow_squash_merge | Should -BeTrue + $repo.squash_merge_commit_title | Should -Be 'COMMIT_OR_PR_TITLE' + $repo.squash_merge_commit_message | Should -Be 'COMMIT_MESSAGES' + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + + Context -Name 'When creating a repository with Merge Commit PR Title' { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + DisallowMergeCommit = $false + MergeCommitTitle = 'PRTitle' + MergeCommitMessage = 'Blank' + } + + $repo = New-GitHubRepository @newGithubRepositoryParms + } + + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.allow_merge_commit | Should -BeTrue + $repo.merge_commit_title | Should -Be 'PR_TITLE' + $repo.merge_commit_message | Should -Be 'BLANK' + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + + Context -Name 'When creating a repository with Merge Commit PR Title and Description' { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + DisallowMergeCommit = $false + MergeCommitTitle = 'PRTitle' + MergeCommitMessage = 'PRBody' + } + + $repo = New-GitHubRepository @newGithubRepositoryParms + } + + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.allow_merge_commit | Should -BeTrue + $repo.merge_commit_title | Should -Be 'PR_TITLE' + $repo.merge_commit_message | Should -Be 'PR_BODY' + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + + Context -Name 'When creating a repository with Merge Commit default message' { + BeforeAll -ScriptBlock { + $repoName = ([Guid]::NewGuid().Guid) + $newGithubRepositoryParms = @{ + RepositoryName = $repoName + DisallowMergeCommit = $false + MergeCommitTitle = 'MergeMessage' + MergeCommitMessage = 'PRTitle' + } + + $repo = New-GitHubRepository @newGithubRepositoryParms + } + + It 'Should return an object of the correct type' { + $repo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $repo.name | Should -Be $repoName + $repo.allow_merge_commit | Should -BeTrue + $repo.merge_commit_title | Should -Be 'MERGE_MESSAGE' + $repo.merge_commit_message | Should -Be 'PR_TITLE' + } + + AfterAll -ScriptBlock { + if ($repo) + { + Remove-GitHubRepository -Uri $repo.svn_url -Confirm:$false + } + } + } + Context -Name 'When a TeamID is specified' -Fixture { BeforeAll -ScriptBlock { $repoName = ([Guid]::NewGuid().Guid) @@ -858,6 +1082,181 @@ Describe 'GitHubRepositories\Set-GitHubRepository' { } } + Context -Name 'When updating a repository with Squash Merge Commit PR Title' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + DisallowSquashMerge = $false + SquashMergeCommitTitle = 'PRTitle' + SquashMergeCommitMessage = 'Blank' + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_squash_merge | Should -BeTrue + $updatedRepo.squash_merge_commit_title | Should -Be 'PR_TITLE' + $updatedRepo.squash_merge_commit_message | Should -Be 'BLANK' + } + } + + Context -Name 'When updating a repository with Squash Merge Commit PR Title and Commit details' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + DisallowSquashMerge = $false + SquashMergeCommitTitle = 'PRTitle' + SquashMergeCommitMessage = 'CommitMessages' + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_squash_merge | Should -BeTrue + $updatedRepo.squash_merge_commit_title | Should -Be 'PR_TITLE' + $updatedRepo.squash_merge_commit_message | Should -Be 'COMMIT_MESSAGES' + } + } + + Context -Name 'When updating a repository with Squash Merge Commit PR Title and Description' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + DisallowSquashMerge = $false + SquashMergeCommitTitle = 'PRTitle' + SquashMergeCommitMessage = 'PRBody' + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_squash_merge | Should -BeTrue + $updatedRepo.squash_merge_commit_title | Should -Be 'PR_TITLE' + $updatedRepo.squash_merge_commit_message | Should -Be 'PR_BODY' + } + } + + Context -Name 'When updating a repository with Squash Merge Commit default message' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + DisallowSquashMerge = $false + SquashMergeCommitTitle = 'CommitOrPRTitle' + SquashMergeCommitMessage = 'CommitMessages' + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_squash_merge | Should -BeTrue + $updatedRepo.squash_merge_commit_title | Should -Be 'COMMIT_OR_PR_TITLE' + $updatedRepo.squash_merge_commit_message | Should -Be 'COMMIT_MESSAGES' + } + } + + Context -Name 'When updating a repository with Merge Commit PR Title' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + DisallowMergeCommit = $false + MergeCommitTitle = 'PRTitle' + MergeCommitMessage = 'Blank' + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_merge_commit | Should -BeTrue + $updatedRepo.merge_commit_title | Should -Be 'PR_TITLE' + $updatedRepo.merge_commit_message | Should -Be 'BLANK' + } + } + + Context -Name 'When updating a repository with Merge Commit PR Title and Description' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + DisallowMergeCommit = $false + MergeCommitTitle = 'PRTitle' + MergeCommitMessage = 'PRBody' + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_merge_commit | Should -BeTrue + $updatedRepo.merge_commit_title | Should -Be 'PR_TITLE' + $updatedRepo.merge_commit_message | Should -Be 'PR_BODY' + } + } + + Context -Name 'When updating a repository with Merge Commit default message' { + BeforeAll -ScriptBlock { + $updateGithubRepositoryParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $repoName + DisallowMergeCommit = $false + MergeCommitTitle = 'MergeMessage' + MergeCommitMessage = 'PRTitle' + } + + $updatedRepo = Set-GitHubRepository @updateGithubRepositoryParms -PassThru + } + + It 'Should return an object of the correct type' { + $updatedRepo | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $updatedRepo.name | Should -Be $repoName + $updatedRepo.allow_merge_commit | Should -BeTrue + $updatedRepo.merge_commit_title | Should -Be 'MERGE_MESSAGE' + $updatedRepo.merge_commit_message | Should -Be 'PR_TITLE' + } + } + Context -Name 'When updating a repository with the Archive setting' { BeforeAll -ScriptBlock { $updateGithubRepositoryParms = @{ From 2233b86601bae63413e55a51932d3449cfca90df Mon Sep 17 00:00:00 2001 From: "microsoft-github-policy-service[bot]" <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> Date: Fri, 23 Jun 2023 12:05:38 -0700 Subject: [PATCH 47/51] Onboarding to GitOps.ResourceManagement (#408) * Add prIssueManagement.yml to onboard repo to GitOps.ResourceManagement as FabricBot replacement * Deleting fabricbot.json --------- Co-authored-by: microsoft-github-policy-service[bot] <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> --- .github/fabricbot.json | 491 ------------------------ .github/policies/resourceManagement.yml | 136 +++++++ 2 files changed, 136 insertions(+), 491 deletions(-) delete mode 100644 .github/fabricbot.json create mode 100644 .github/policies/resourceManagement.yml diff --git a/.github/fabricbot.json b/.github/fabricbot.json deleted file mode 100644 index 2bb23948..00000000 --- a/.github/fabricbot.json +++ /dev/null @@ -1,491 +0,0 @@ -{ - "version": "1.0", - "tasks": [ - { - "taskType": "trigger", - "capabilityId": "CodeFlowLink", - "subCapability": "CodeFlowLink", - "version": "1.0", - "config": { - "taskName": "Add a CodeFlow link to new pull requests" - }, - "id": "YDkZFvdXmD3", - "disabled": true - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestReviewResponder", - "version": "1.0", - "config": { - "taskName": "Add needs author feedback label to pull requests when changes are requested", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "submitted" - } - }, - { - "name": "isReviewState", - "parameters": { - "state": "changes_requested" - } - } - ] - }, - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "needs-author-feedback" - } - } - ], - "eventType": "pull_request", - "eventNames": [ - "pull_request_review" - ] - }, - "id": "r_flUYyQmXt" - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "taskName": "Remove needs author feedback label when the author responds to a pull request", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "operator": "not", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "closed" - } - } - ] - }, - { - "name": "hasLabel", - "parameters": { - "label": "needs-author-feedback" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "needs-author-feedback" - } - } - ], - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ] - }, - "id": "oXVx60lgowd" - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestCommentResponder", - "version": "1.0", - "config": { - "taskName": "Remove needs author feedback label when the author comments on a pull request", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "needs-author-feedback" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "needs-author-feedback" - } - } - ], - "eventType": "pull_request", - "eventNames": [ - "issue_comment" - ] - }, - "id": "6DLGYbk_2cF" - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestReviewResponder", - "version": "1.0", - "config": { - "taskName": "Remove needs author feedback label when the author responds to a pull request review comment", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "needs-author-feedback" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "needs-author-feedback" - } - } - ], - "eventType": "pull_request", - "eventNames": [ - "pull_request_review" - ] - }, - "id": "hE72Sl_8OtC" - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "taskName": "Remove no recent activity label from pull requests", - "conditions": { - "operator": "and", - "operands": [ - { - "operator": "not", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "closed" - } - } - ] - }, - { - "name": "hasLabel", - "parameters": { - "label": "status-no-recent-activity" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status-no-recent-activity" - } - } - ], - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ] - }, - "id": "OMHGEo10a0W" - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestCommentResponder", - "version": "1.0", - "config": { - "taskName": "Remove no recent activity label when a pull request is commented on", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "status-no-recent-activity" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status-no-recent-activity" - } - } - ], - "eventType": "pull_request", - "eventNames": [ - "issue_comment" - ] - }, - "id": "wTrzllHtIDZ" - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestReviewResponder", - "version": "1.0", - "config": { - "taskName": "Remove no recent activity label when a pull request is reviewed", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "status-no-recent-activity" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status-no-recent-activity" - } - } - ], - "eventType": "pull_request", - "eventNames": [ - "pull_request_review" - ] - }, - "id": "Sg7hkGEr5kG" - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "Close stale pull requests", - "frequency": [ - { - "weekDay": 0, - "hours": [ - 8 - ], - "timezoneOffset": -7 - } - ], - "searchTerms": [ - { - "name": "isPr", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "needs-author-feedback" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status-no-recent-activity" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 14 - } - } - ], - "actions": [ - { - "name": "closeIssue", - "parameters": {} - }, - { - "name": "addLabel", - "parameters": { - "label": "auto-closed-unmerged" - } - }, - { - "name": "addReply", - "parameters": { - "comment": "This pull request has been automatically closed due to a lack of activity from the author. We understand. Life happens and other things likely came up. We would still love to see your contribution get merged in. Now that it has been closed, a different community member may wish to pick up where you left off. If so, they should speak up by commenting below. If _you're_ still interested in completing this yourself, just respond back and let us know." - } - } - ] - }, - "id": "t1vGBS8FEhE" - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "Add no recent activity label to pull requests", - "frequency": [ - { - "weekDay": 0, - "hours": [ - 8 - ], - "timezoneOffset": -7 - }, - { - "weekDay": 1, - "hours": [ - 8 - ], - "timezoneOffset": -7 - }, - { - "weekDay": 2, - "hours": [ - 8 - ], - "timezoneOffset": -7 - }, - { - "weekDay": 3, - "hours": [ - 8 - ], - "timezoneOffset": -7 - }, - { - "weekDay": 4, - "hours": [ - 8 - ], - "timezoneOffset": -7 - }, - { - "weekDay": 5, - "hours": [ - 8 - ], - "timezoneOffset": -7 - }, - { - "weekDay": 6, - "hours": [ - 8 - ], - "timezoneOffset": -7 - } - ], - "searchTerms": [ - { - "name": "isPr", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "needs-author-feedback" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 7 - } - }, - { - "name": "noLabel", - "parameters": { - "label": "status-no-recent-activity" - } - } - ], - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "status-no-recent-activity" - } - }, - { - "name": "addReply", - "parameters": { - "comment": "This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **7 days**. It will be closed if no further activity occurs **within 14 days of this comment**." - } - } - ] - }, - "id": "xdjknroafok" - }, - { - "taskType": "trigger", - "capabilityId": "AutoMerge", - "subCapability": "AutoMerge", - "version": "1.0", - "config": { - "taskName": "Automatically merge pull requests", - "label": "auto-merge", - "silentMode": false, - "minMinutesOpen": 480, - "mergeType": "squash", - "allowAutoMergeInstructionsWithoutLabel": true, - "removeLabelOnPush": true, - "requireAllStatuses": false, - "usePrDescriptionAsCommitMessage": true - }, - "id": "6GIyYgxEaBW", - "disabled": false - } - ], - "userGroups": [] -} diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml new file mode 100644 index 00000000..2c9defd7 --- /dev/null +++ b/.github/policies/resourceManagement.yml @@ -0,0 +1,136 @@ +id: +name: GitOps.PullRequestIssueManagement +description: GitOps.PullRequestIssueManagement primitive +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + scheduledSearches: + - description: + frequencies: + - weekday: + day: Sunday + time: 8:0 + filters: + - isPullRequest + - isOpen + - hasLabel: + label: needs-author-feedback + - hasLabel: + label: status-no-recent-activity + - noActivitySince: + days: 14 + actions: + - closeIssue + - addLabel: + label: auto-closed-unmerged + - addReply: + reply: This pull request has been automatically closed due to a lack of activity from the author. We understand. Life happens and other things likely came up. We would still love to see your contribution get merged in. Now that it has been closed, a different community member may wish to pick up where you left off. If so, they should speak up by commenting below. If _you're_ still interested in completing this yourself, just respond back and let us know. + - description: + frequencies: + - daily: + time: 8:0 + filters: + - isPullRequest + - isOpen + - hasLabel: + label: needs-author-feedback + - noActivitySince: + days: 7 + - isNotLabeledWith: + label: status-no-recent-activity + actions: + - addLabel: + label: status-no-recent-activity + - addReply: + reply: This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **7 days**. It will be closed if no further activity occurs **within 14 days of this comment**. + eventResponderTasks: + - if: + - payloadType: Pull_Request_Review + - isAction: + action: Submitted + - isReviewState: + reviewState: Changes_requested + then: + - addLabel: + label: needs-author-feedback + description: + - if: + - payloadType: Pull_Request + - isActivitySender: + issueAuthor: True + - not: + isAction: + action: Closed + - hasLabel: + label: needs-author-feedback + then: + - removeLabel: + label: needs-author-feedback + description: + - if: + - payloadType: Issue_Comment + - isActivitySender: + issueAuthor: True + - hasLabel: + label: needs-author-feedback + then: + - removeLabel: + label: needs-author-feedback + description: + - if: + - payloadType: Pull_Request_Review + - isActivitySender: + issueAuthor: True + - hasLabel: + label: needs-author-feedback + then: + - removeLabel: + label: needs-author-feedback + description: + - if: + - payloadType: Pull_Request + - not: + isAction: + action: Closed + - hasLabel: + label: status-no-recent-activity + then: + - removeLabel: + label: status-no-recent-activity + description: + - if: + - payloadType: Issue_Comment + - hasLabel: + label: status-no-recent-activity + then: + - removeLabel: + label: status-no-recent-activity + description: + - if: + - payloadType: Pull_Request_Review + - hasLabel: + label: status-no-recent-activity + then: + - removeLabel: + label: status-no-recent-activity + description: + - if: + - payloadType: Pull_Request + - hasLabel: + label: auto-merge + then: + - enableAutoMerge: + mergeMethod: Squash + description: + - if: + - payloadType: Pull_Request + - labelRemoved: + label: auto-merge + then: + - disableAutoMerge + description: +onFailure: +onSuccess: From 482fe2331732a24ed779b140c3f38c8a156271e1 Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Tue, 22 Aug 2023 10:41:46 -0700 Subject: [PATCH 48/51] Remove static analysis warning for using a module alias being referenced in a test (#414) I generally don't like aliases being used (neither does PSScriptAnalyzer), but in this case, `New-GitHubDeploymentEnvironment` was writting to be able to behave as `Set-GitHubDeploymentEnvironment` as well, and we should be testing it the way that a user would likely be calling it. --- Tests/GitHubDeployments.tests.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/GitHubDeployments.tests.ps1 b/Tests/GitHubDeployments.tests.ps1 index 325b583b..8a781db6 100644 --- a/Tests/GitHubDeployments.tests.ps1 +++ b/Tests/GitHubDeployments.tests.ps1 @@ -9,6 +9,8 @@ [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppress false positives in Pester code blocks')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '', + Justification = 'Using Set-GitHubDeploymentEnvironment the way a user would.')] param() Set-StrictMode -Version 1.0 From 9ec863b14277a524aa8f2931b742bb3dfed10d5a Mon Sep 17 00:00:00 2001 From: Jason Vercellone Date: Tue, 29 Aug 2023 12:21:13 -0500 Subject: [PATCH 49/51] Add support for codespaces (#407) Adds initial support for GitHub Codespaces. #### References Endpoints ~~excluded~~ below will be added in subsequent PRs **[Codespaces/codespaces](https://docs.github.com/en/rest/codespaces/codespaces)** - [x] [List codespaces in a repository for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#list-codespaces-in-a-repository-for-the-authenticated-user) - [x] [Create a codespace in a repository](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-in-a-repository) ~~[List devcontainer configurations in a repository for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#list-devcontainer-configurations-in-a-repository-for-the-authenticated-user)~~ ~~[Get default attributes for a codespace](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#get-default-attributes-for-a-codespace)~~ - [x] [Create a codespace from a pull request](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-from-a-pull-request) - [x] [List codespaces for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#list-codespaces-for-the-authenticated-user) - [x] [Create a codespace for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-for-the-authenticated-user) - [x] [Get a codespace for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#get-a-codespace-for-the-authenticated-user) ~~[Update a codespace for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#update-a-codespace-for-the-authenticated-user)~~ - [x] [Delete a codespace for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#delete-a-codespace-for-the-authenticated-user) ~~[Export a codespace for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#export-a-codespace-for-the-authenticated-user)~~ ~~[Get details about a codespace export](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#get-details-about-a-codespace-export)~~ ~~[Create a repository from an unpublished codespace](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-repository-from-an-unpublished-codespace)~~ - [x] [Start a codespace for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#start-a-codespace-for-the-authenticated-user) - [x] [Stop a codespace for the authenticated user](https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#stop-a-codespace-for-the-authenticated-user) **[Codespaces/organizations](https://docs.github.com/en/rest/codespaces/organizations)** - [x] [List codespaces for the organization](https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#list-codespaces-for-the-organization) ~~[Manage access control for organization codespaces](https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#manage-access-control-for-organization-codespaces)~~ ~~[Add users to Codespaces billing for an organization](https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#add-users-to-codespaces-billing-for-an-organization)~~ ~~[Removes users from Codespaces billing for an organization](https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#removes-users-from-codespaces-billing-for-an-organization)~~ - [x] [List codespaces for a user in organization](https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#list-codespaces-for-a-user-in-organization) - [x] [Delete a codespace from the organization](https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#delete-a-codespace-from-the-organization) ~~[Stop a codespace for an organization user](https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#stop-a-codespace-for-an-organization-user)~~ --- CONTRIBUTING.md | 1 + Formatters/GitHubCodespaces.Format.ps1xml | 38 + GitHubCodespaces.ps1 | 964 ++++++++++++++++++++++ GitHubCore.ps1 | 1 + PowerShellForGitHub.psd1 | 7 + Tests/GitHubCodespaces.tests.ps1 | 450 ++++++++++ USAGE.md | 117 +++ 7 files changed, 1578 insertions(+) create mode 100644 Formatters/GitHubCodespaces.Format.ps1xml create mode 100644 GitHubCodespaces.ps1 create mode 100644 Tests/GitHubCodespaces.tests.ps1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5f373b04..c326deeb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -624,6 +624,7 @@ Thank you to all of our contributors, no matter how big or small the contributio - **[Simon Heather (@X-Guardian)](https://github.com/X-Guardian)** - **[Neil White (@variableresistor)](https://github.com/variableresistor)** - **[Mark Curole(@tigerfansga)](https://github.com/tigerfansga)** +- **[Jason Vercellone(@vercellone)](https://github.com/vercellone)** ---------- diff --git a/Formatters/GitHubCodespaces.Format.ps1xml b/Formatters/GitHubCodespaces.Format.ps1xml new file mode 100644 index 00000000..256de388 --- /dev/null +++ b/Formatters/GitHubCodespaces.Format.ps1xml @@ -0,0 +1,38 @@ + + + + + + GitHub.Codespace + + GitHub.Codespace + + + + + + + id + + + name + + + display_name + + + state + + + created_at + + + updated_at + + + + + + + + diff --git a/GitHubCodespaces.ps1 b/GitHubCodespaces.ps1 new file mode 100644 index 00000000..ff322485 --- /dev/null +++ b/GitHubCodespaces.ps1 @@ -0,0 +1,964 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +@{ + GitHubCodespaceTypeName = 'GitHub.Codespace' +}.GetEnumerator() | ForEach-Object { + Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value +} + +filter Get-GitHubCodespace +{ + <# + .SYNOPSIS + Retrieves information about a Codespace or list of codespaces on GitHub. + + .DESCRIPTION + Retrieves information about a Codespace or list of codespaces on GitHub. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the Codespace. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the Codespace. + The OwnerName and CodespaceName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER OrganizationName + Name of the Organization. + + .PARAMETER UserName + The handle for the GitHub user account. + + .PARAMETER CodespaceName + Name of the Codespace. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Codespace + GitHub.Project + GitHub.Repository + GitHub.User + + .OUTPUTS + GitHub.Codespace + + .EXAMPLE + Get-GitHubCodespace + + Gets all codespaces for the current authenticated user. + + .EXAMPLE + Get-GitHubCodespace -OwnerName octocat + + Gets all of the codespaces for the user octocat + + .EXAMPLE + Get-GitHubUser -UserName octocat | Get-GitHubCodespace + + Gets all of the codespaces for the user octocat + + .EXAMPLE + Get-GitHubCodespace -Uri https://github.com/microsoft/PowerShellForGitHub + + Gets information about the microsoft/PowerShellForGitHub Codespace. + + .EXAMPLE + $repo | Get-GitHubCodespace + + You can pipe in a previous Codespace to get its refreshed information. + + .EXAMPLE + Get-GitHubCodespace -OrganizationName PowerShell + + Gets all of the codespaces in the PowerShell organization. + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#get-a-codespace-for-the-authenticated-user + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#list-codespaces-in-a-repository-for-the-authenticated-user + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#list-codespaces-for-the-authenticated-user + + .LINK + https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#list-codespaces-for-the-organization + + .LINK + https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#list-codespaces-for-a-user-in-organization +#> + [CmdletBinding(DefaultParameterSetName = 'AuthenticatedUser')] + [OutputType({ $script:GitHubCodespaceTypeName })] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1.')] + param( + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Elements')] + [string] $OwnerName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Elements')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Organization')] + [string] $OrganizationName, + + [Parameter( + ValueFromPipelineByPropertyName, + ParameterSetName = 'Organization')] + [ValidateNotNullOrEmpty()] + [String] $UserName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'CodespaceName')] + [string] $CodespaceName, + + [string] $AccessToken + ) + + Write-InvocationLog + + $telemetryProperties = @{ + UsageType = $PSCmdlet.ParameterSetName + } + + $uriFragment = [String]::Empty + $description = [String]::Empty + switch ($PSCmdlet.ParameterSetName) + { + 'AuthenticatedUser' + { + $uriFragment = 'user/codespaces' + $description = 'Getting codespaces for current authenticated user' + + break + } + + 'CodespaceName' + { + $telemetryProperties['CodespaceName'] = Get-PiiSafeString -PlainText $CodespaceName + + $uriFragment = "user/codespaces/$CodespaceName" + $description = "Getting user/codespaces/$CodespaceName" + + break + } + + 'Organization' + { + $telemetryProperties['OrganizationName'] = Get-PiiSafeString -PlainText $OrganizationName + if ([string]::IsNullOrWhiteSpace($UserName)) + { + $uriFragment = "orgs/$OrganizationName/codespaces" + $description = "Getting codespaces for $OrganizationName" + } + else + { + $telemetryProperties['UserName'] = Get-PiiSafeString -PlainText $UserName + $uriFragment = "orgs/$OrganizationName/members/$UserName/codespaces" + $description = "Getting codespaces for $OrganizationName" + } + + break + } + + { $_ -in ('Elements', 'Uri') } + { + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties['OwnerName'] = Get-PiiSafeString -PlainText $OwnerName + $telemetryProperties['RepositoryName'] = Get-PiiSafeString -PlainText $RepositoryName + + $uriFragment = "repos/$OwnerName/$RepositoryName/codespaces" + $description = "Getting $OwnerName/$RepositoryName/codespaces" + + break + } + } + + $params = @{ + UriFragment = $uriFragment + Description = $description + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + $result = Invoke-GHRestMethodMultipleResult @params + if ($null -ne $result.codespaces) + { + $result = $result.codespaces + } + + return ($result | Add-GitHubCodespaceAdditionalProperties) +} + +function New-GitHubCodespace +{ + <# + .SYNOPSIS + Creates a codespace. + + .DESCRIPTION + Creates a codespace. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the Codespace. + If not supplied here, the DefaultOwnerName configuration property value will be used. + + .PARAMETER RepositoryName + Name of the repository. + If not supplied here, the DefaultRepositoryName configuration property value will be used. + + .PARAMETER Uri + Uri for the Codespace. + The OwnerName and CodespaceName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER PullRequest + The pull request number for this codespace. + + .PARAMETER RepositoryId + The ID for a Repository. Only applicable when creating a codespace for the current authenticated user. + + .PARAMETER Ref + Git ref (typically a branch name) for this codespace + + .PARAMETER ClientIp + IP for geo auto-detection when proxying a request. + + .PARAMETER DevContainerPath + Path to devcontainer.json config to use for this codespace. + + .PARAMETER DisplayName + Display name for this codespace + + .PARAMETER Geo + The geographic area for this codespace. + Assigned by IP if not provided. + + .PARAMETER Machine + Machine type to use for this codespace. + + .PARAMETER NoMultipleRepoPermissions + Whether to authorize requested permissions to other repos from devcontainer.json. + + .PARAMETER IdleRetentionPeriodMinutes + Duration in minutes (up to 30 days) after codespace has gone idle in which it will be deleted. + + .PARAMETER TimeoutMinutes + Time in minutes before codespace stops from inactivity. + + .PARAMETER WorkingDirectory + Working directory for this codespace. + + .PARAMETER Wait + If present will wait for the codespace to be available. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Codespace + GitHub.Project + GitHub.PullRequest + GitHub.Repository + + .OUTPUTS + GitHub.Codespace + + .EXAMPLE + New-GitHubCodespace -RepositoryId 582779513 + + Creates a new codespace for the current authenticated user in the specified repository. + + .EXAMPLE + New-GitHubCodespace -RepositoryId 582779513 -PullRequest 508 + + Creates a new codespace for the current authenticated user in the specified repository from a pull request. + + .EXAMPLE + New-GitHubCodespace -OwnerName marykay -RepositoryName one + + Creates a codespace owned by the authenticated user in the specified repository. + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-for-the-authenticated-user + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-in-a-repository + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#create-a-codespace-from-a-pull-request +#> + [CmdletBinding( + SupportsShouldProcess, + DefaultParameterSetName = 'AuthenticatedUser')] + [OutputType({ $script:GitHubCodespaceTypeName })] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'The Uri parameter is only referenced by Resolve-RepositoryElements which get access to it from the stack via Get-Variable -Scope 1, and most of the others get dynamically accessed via $propertyMap.')] + param( + [Parameter( + Mandatory, + ParameterSetName = 'Elements')] + [Parameter( + Mandatory, + ParameterSetName = 'ElementsPullRequest')] + [string] $OwnerName, + + [Parameter( + Mandatory, + ParameterSetName = 'Elements')] + [Parameter( + Mandatory, + ParameterSetName = 'ElementsPullRequest')] + [string] $RepositoryName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Uri')] + [Alias('RepositoryUrl')] + [Alias('PullRequestUrl')] + [string] $Uri, + + [Parameter(ParameterSetName = 'AuthenticatedUser')] + [Parameter( + Mandatory, + ParameterSetName = 'ElementsPullRequest')] + [Alias('PullRequestNumber')] + [int64] $PullRequest, + + [Parameter( + Mandatory, + ParameterSetName = 'AuthenticatedUser')] + [Int64] $RepositoryId, + + [Parameter(ParameterSetName = 'AuthenticatedUser')] + [Parameter(ParameterSetName = 'Elements')] + [string] $Ref, + + [string] $ClientIp, + + [string] $DevContainerPath, + + [string] $DisplayName, + + [ValidateSet('EuropeWest', 'SoutheastAsia', 'UsEast', 'UsWest')] + [string] $Geo, + + [string] $Machine, + + [switch] $NoMultipleRepoPermissions, + + [ValidateRange(0, 43200)] + [int] $IdleRetentionPeriodMinutes, + + [ValidateRange(5, 240)] + [int] $TimeoutMinutes, + + [string] $WorkingDirectory, + + [switch] $Wait, + + [string] $AccessToken + ) + + begin + { + Write-InvocationLog + + $propertyMap = @{ + ClientIp = 'client_ip' + DevContainerPath = 'devcontainer_path' + DisplayName = 'display_name' + Geo = 'geo' + Machine = 'machine' + Ref = 'ref' + IdleRetentionPeriodMinutes = 'retention_period_minutes' + TimeoutMinutes = 'idle_timeout_minutes' + WorkingDirectory = 'working_directory' + } + } + + process + { + $telemetryProperties = @{ + UsageType = $PSCmdlet.ParameterSetName + Wait = $Wait.IsPresent + } + + $uriFragment = [String]::Empty + $description = [String]::Empty + if ($PSCmdlet.ParameterSetName -eq 'AuthenticatedUser') + { + $uriFragment = 'user/codespaces' + $description = 'Create a codespace for current authenticated user' + } + else + { + # ParameterSets: Elements, ElementsPullRequest, Uri + # ElementsPullRequest prevents Ref for /repos/{owner}/{repo}/pulls/{pull_number}/codespaces + $elements = Resolve-RepositoryElements + $OwnerName = $elements.ownerName + $RepositoryName = $elements.repositoryName + + $telemetryProperties['OwnerName'] = Get-PiiSafeString -PlainText $OwnerName + $telemetryProperties['RepositoryName'] = Get-PiiSafeString -PlainText $RepositoryName + + if ($PSCmdlet.ParameterSetName -eq 'ElementsPullRequest') + { + $description = "Create a codespace from $OwnerName/$RepositoryName/pulls/$PullRequest" + $telemetryProperties['PullRequest'] = $PullRequest + $uriFragment = "repos/$OwnerName/$RepositoryName/pulls/$PullRequest/codespaces" + } + else + { + $description = "Create a codepace in $OwnerName/$RepositoryName" + $uriFragment = "repos/$OwnerName/$RepositoryName/codespaces" + } + } + + $hashBody = @{ + multi_repo_permissions_opt_out = $NoMultipleRepoPermissions.IsPresent + } + + # Map params to hashBody properties + foreach ($p in $PSBoundParameters.GetEnumerator()) + { + if ($propertyMap.ContainsKey($p.Key) -and (-not [string]::IsNullOrWhiteSpace($p.Value))) + { + $hashBody.Add($propertyMap[$p.Key], $p.Value) + } + } + + if ($PSCmdlet.ParameterSetName -eq 'AuthenticatedUser') + { + if ($PSBoundParameters.ContainsKey('PullRequest')) + { + $hashBody.Add('pull_request', + [PSCustomObject]@{ + pull_request_number = $PullRequest + repository_id = $RepositoryId + } + ) + } + else + { + $hashBody.Add('repository_id', $RepositoryId) + } + } + + $params = @{ + UriFragment = $uriFragment + Body = (ConvertTo-Json -InputObject $hashBody -Depth 5) + Method = 'Post' + Description = $description + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + if (-not $PSCmdlet.ShouldProcess($RepositoryName, 'Create GitHub Codespace')) + { + return + } + + $result = (Invoke-GHRestMethod @params | Add-GitHubCodespaceAdditionalProperties) + + if ($Wait.IsPresent) + { + $waitParams = @{ + CodespaceName = $result.CodespaceName + AccessToken = $AccessToken + } + + $result = Wait-GitHubCodespaceAction @waitParams + } + + return $result + } +} + +filter Remove-GitHubCodespace +{ + <# + .SYNOPSIS + Remove a Codespace. + + .DESCRIPTION + Remove a Codespace. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OrganizationName + Name of the Organization. + + .PARAMETER UserName + The handle for the GitHub user account. + + .PARAMETER CodespaceName + Name of the Codespace. + + .PARAMETER Force + If this switch is specified, you will not be prompted for confirmation of command execution. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Codespace + + .OUTPUTS + None + + .EXAMPLE + Get-GitHubCodespace -Name vercellone-effective-goggles-qrv997q6j9929jx8 | Remove-GitHubCodespace + + .EXAMPLE + Remove-GitHubCodespace -Name vercellone-effective-goggles-qrv997q6j9929jx8 + + .EXAMPLE + Remove-GitHubCodespace -OrganizationName myorg -UserName jetsong -Name jetsong-button-masher-zzz788y6j8288xp1 + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#delete-a-codespace-for-the-authenticated-user + + .LINK + https://docs.github.com/en/rest/codespaces/organizations?apiVersion=2022-11-28#delete-a-codespace-from-the-organization +#> + [CmdletBinding( + DefaultParameterSetName = 'AuthenticatedUser', + SupportsShouldProcess, + ConfirmImpact = 'High')] + [Alias('Delete-GitHubCodespace')] + param( + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Organization')] + [string] $OrganizationName, + + [Parameter( + Mandatory, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Organization')] + [ValidateNotNullOrEmpty()] + [String] $UserName, + + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [string] $CodespaceName, + + [switch] $Force, + + [string] $AccessToken + ) + + Write-InvocationLog + + $telemetryProperties = @{ + CodespaceName = Get-PiiSafeString -PlainText $CodespaceName + } + + $uriFragment = [String]::Empty + if ($PSCmdlet.ParameterSetName -eq 'AuthenticatedUser') + { + $uriFragment = "user/codespaces/$CodespaceName" + } + else + { + $uriFragment = "orgs/$OrganizationName/members/$UserName/codespaces/$CodespaceName" + } + + $params = @{ + UriFragment = $uriFragment + Method = 'Delete' + Description = "Remove Codespace $CodespaceName" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + if ($Force -and (-not $Confirm)) + { + $ConfirmPreference = 'None' + } + + if (-not $PSCmdlet.ShouldProcess($CodespaceName, "Remove Codespace $CodespaceName")) + { + return + } + + Invoke-GHRestMethod @params | Out-Null +} + +filter Start-GitHubCodespace +{ + <# + .SYNOPSIS + Start a Codespace for the currently authenticated user. + + .DESCRIPTION + Start a Codespace for the currently authenticated user. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER CodespaceName + Name of the Codespace. + + .PARAMETER Wait + If present will wait for the codespace to start. + + .PARAMETER PassThru + Returns the start action result. By default, this cmdlet does not generate any output. + You can use "Set-GitHubConfiguration -DefaultPassThru" to control the default behavior + of this switch. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Codespace + + .OUTPUTS + GitHub.Codespace + + .EXAMPLE + Start-GitHubCodespace -Name vercellone-effective-goggles-qrv997q6j9929jx8 + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#start-a-codespace-for-the-authenticated-user + + .NOTES + You must authenticate using an access token with the codespace scope to use this endpoint. + GitHub Apps must have write access to the codespaces_lifecycle_admin repository permission to use this endpoint. +#> + [CmdletBinding( + SupportsShouldProcess, + ConfirmImpact = 'Low')] + [OutputType({ $script:GitHubCodespaceTypeName })] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'PassThru is accessed indirectly via Resolve-ParameterWithDefaultConfigurationValue')] + param( + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [string] $CodespaceName, + + [switch] $Wait, + + [switch] $PassThru, + + [string] $AccessToken + ) + + Write-InvocationLog + + $telemetryProperties = @{ + CodespaceName = Get-PiiSafeString -PlainText $CodespaceName + Wait = $Wait.IsPresent + } + + $params = @{ + UriFragment = "user/codespaces/$CodespaceName/start" + Method = 'Post' + Description = "Start Codespace $CodespaceName" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + if (-not $PSCmdlet.ShouldProcess($CodespaceName, "Start Codespace $CodespaceName")) + { + return + } + + $result = (Invoke-GHRestMethod @params | Add-GitHubCodespaceAdditionalProperties) + + if ($Wait.IsPresent) + { + $waitParams = @{ + CodespaceName = $CodespaceName + AccessToken = $AccessToken + } + + $result = Wait-GitHubCodespaceAction @waitParams + } + + if (Resolve-ParameterWithDefaultConfigurationValue -Name PassThru -ConfigValueName DefaultPassThru) + { + return $result + } +} + +filter Stop-GitHubCodespace +{ + <# + .SYNOPSIS + Stop a Codespace for the currently authenticated user. + + .DESCRIPTION + Stop a Codespace for the currently authenticated user. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER CodespaceName + Name of the Codespace. + + .PARAMETER Wait + If present will wait for the codespace to stop. + + .PARAMETER PassThru + Returns the updated GitHub Issue. By default, this cmdlet does not generate any output. + You can use "Set-GitHubConfiguration -DefaultPassThru" to control the default behavior + of this switch. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Codespace + + .OUTPUTS + GitHub.Codespace + + .EXAMPLE + Stop-GitHubCodespace -Name vercellone-effective-goggles-qrv997q6j9929jx8 + + .LINK + https://docs.github.com/en/rest/codespaces/codespaces?apiVersion=2022-11-28#stop-a-codespace-for-the-authenticated-user + + .NOTES + You must authenticate using an access token with the codespace scope to use this endpoint. + GitHub Apps must have write access to the codespaces_lifecycle_admin repository permission to use this endpoint. +#> + [CmdletBinding( + SupportsShouldProcess, + ConfirmImpact = 'Low')] + [OutputType({ $script:GitHubCodespaceTypeName })] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'PassThru is accessed indirectly via Resolve-ParameterWithDefaultConfigurationValue')] + param( + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [string] $CodespaceName, + + [switch] $Wait, + + [switch] $PassThru, + + [string] $AccessToken + ) + + Write-InvocationLog + + $telemetryProperties = @{ + CodespaceName = Get-PiiSafeString -PlainText $CodespaceName + Wait = $Wait.IsPresent + } + + $params = @{ + UriFragment = "user/codespaces/$CodespaceName/stop" + Method = 'Post' + Description = "Stop Codespace $CodespaceName" + AccessToken = $AccessToken + TelemetryEventName = $MyInvocation.MyCommand.Name + TelemetryProperties = $telemetryProperties + } + + if (-not $PSCmdlet.ShouldProcess($CodespaceName, "Stop Codespace $CodespaceName")) + { + return + } + + $result = (Invoke-GHRestMethod @params | Add-GitHubCodespaceAdditionalProperties) + + if ($Wait.IsPresent) + { + $waitParams = @{ + CodespaceName = $CodespaceName + AccessToken = $AccessToken + } + + $result = Wait-GitHubCodespaceAction @waitParams + } + + if (Resolve-ParameterWithDefaultConfigurationValue -Name PassThru -ConfigValueName DefaultPassThru) + { + return $result + } +} + +function Wait-GitHubCodespaceAction +{ + <# + .SYNOPSIS + Wait for a Codespace start or stop action. + + .PARAMETER CodespaceName + Name of the Codespace. + + .PARAMETER AccessToken + If provided, this will be used as the AccessToken for authentication with the + REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. + + .INPUTS + GitHub.Codespace + + .OUTPUTS + GitHub.Codespace + + .EXAMPLE + Wait-GitHubCodespace -Name vercellone-effective-goggles-qrv997q6j9929jx8 + + .NOTES + Internal-only helper method. +#> + [CmdletBinding()] + [OutputType({ $script:GitHubCodespaceTypeName })] + param( + [Parameter( + Mandatory, + ValueFromPipeline, + ValueFromPipelineByPropertyName)] + [string] $CodespaceName, + + [string] $AccessToken + ) + + begin + { + $sleepSeconds = $(Get-GitHubConfiguration -Name 'StateChangeDelaySeconds') + + # 2s minimum + if ($sleepSeconds -lt 2) + { + $sleepSeconds = 2 + } + } + + process + { + Write-InvocationLog + + # Expected states for happy paths: + # Shutdown > Queued > Starting > Available + # Available > Queued > ShuttingDown > ShutDown + # + # To allow for unexpected results, loop until the state is something other than Queued or *ing + # All known states: + # *ings: Awaiting, Exporting, Provisioning, Rebuilding, ShuttingDown, Starting, Updating + # Other: Archived, Available, Created, Deleted, Failed, Moved, Queued, Shutdown, Unavailable, Unknown + do + { + Start-Sleep -Seconds $sleepSeconds + $codespace = (Get-GitHubCodespace @PSBoundParameters) + Write-Log -Message "[$CodespaceName] state is $($codespace.state)" -Level Verbose + } + until ($codespace.state -notmatch 'Queued|ing') + + return $codespace + } +} + +filter Add-GitHubCodespaceAdditionalProperties +{ + <# + .SYNOPSIS + Adds type name and additional properties to ease pipelining to GitHub Repository objects. + + .PARAMETER InputObject + The GitHub object to add additional properties to. + + .PARAMETER TypeName + The type that should be assigned to the object. + + .INPUTS + [PSCustomObject] + + .OUTPUTS + GitHub.Codespace +#> + [CmdletBinding()] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification = "Internal helper that is definitely adding more than one property.")] + param( + [Parameter( + Mandatory, + ValueFromPipeline)] + [AllowNull()] + [AllowEmptyCollection()] + [PSCustomObject[]] $InputObject, + + [ValidateNotNullOrEmpty()] + [string] $TypeName = $script:GitHubCodespaceTypeName + ) + + foreach ($item in $InputObject) + { + $item.PSObject.TypeNames.Insert(0, $TypeName) + + if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) + { + if ($item.name) + { + Add-Member -InputObject $item -Name 'CodespaceUrl' -Value "user/codespaces/$($item.name)" -MemberType NoteProperty -Force + Add-Member -InputObject $item -Name 'CodespaceName' -Value $item.name -MemberType NoteProperty -Force + } + + if ($null -ne $item.billable_owner) + { + $null = Add-GitHubUserAdditionalProperties -InputObject $item.billable_owner + } + + if ($null -ne $item.owner) + { + $null = Add-GitHubUserAdditionalProperties -InputObject $item.owner + } + + if ($null -ne $item.repository) + { + $null = Add-GitHubRepositoryAdditionalProperties -InputObject $item.repository + Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $item.repository.RepositoryUrl -MemberType NoteProperty -Force + } + } + + Write-Output $item + } +} diff --git a/GitHubCore.ps1 b/GitHubCore.ps1 index 686458ea..f869c4dc 100644 --- a/GitHubCore.ps1 +++ b/GitHubCore.ps1 @@ -997,6 +997,7 @@ $script:datePropertyNames = @( 'due_on', 'last_edited_at', 'last_read_at', + 'last_used_at', 'merged_at', 'published_at', 'pushed_at', diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index a7027f96..8d3e1cac 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -16,6 +16,7 @@ # Format files (.ps1xml) to be loaded when importing this module FormatsToProcess = @( 'Formatters/GitHubBranches.Format.ps1xml', + 'Formatters/GitHubCodespaces.Format.ps1xml', 'Formatters/GitHubDeployments.Format.ps1xml', 'Formatters/GitHubGistComments.Format.ps1xml', 'Formatters/GitHubGists.Format.ps1xml', @@ -34,6 +35,7 @@ 'GitHubAnalytics.ps1', 'GitHubAssignees.ps1', 'GitHubBranches.ps1', + 'GitHubCodespaces.ps1', 'GitHubCore.ps1', 'GitHubContents.ps1', 'GitHubEvents.ps1', @@ -80,6 +82,7 @@ 'Get-GitHubAssignee', 'Get-GitHubCloneTraffic', 'Get-GitHubCodeOfConduct', + 'Get-GitHubCodespace', 'Get-GitHubConfiguration', 'Get-GitHubContent', 'Get-GitHubDeploymentEnvironment', @@ -134,6 +137,7 @@ 'Move-GitHubProjectCard', 'Move-GitHubProjectColumn', 'Move-GitHubRepositoryOwnership', + 'New-GitHubCodespace', 'New-GitHubDeploymentEnvironment', 'New-GitHubGist', 'New-GitHubGistComment', @@ -155,6 +159,7 @@ 'New-GitHubRepositoryFork', 'New-GitHubTeam', 'Remove-GitHubAssignee', + 'Remove-GitHubCodespace', 'Remove-GitHubComment', 'Remove-GitHubDeploymentEnvironment' 'Remove-GitHubGist', @@ -207,6 +212,8 @@ 'Set-GitHubRepositoryTopic', 'Set-GitHubTeam', 'Split-GitHubUri', + 'Start-GitHubCodespace', + 'Stop-GitHubCodespace', 'Test-GitHubAssignee', 'Test-GitHubAuthenticationConfigured', 'Test-GitHubGistStar', diff --git a/Tests/GitHubCodespaces.tests.ps1 b/Tests/GitHubCodespaces.tests.ps1 new file mode 100644 index 00000000..57f6a663 --- /dev/null +++ b/Tests/GitHubCodespaces.tests.ps1 @@ -0,0 +1,450 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# +.Synopsis + Tests for GitHubCodespaces.ps1 module +#> + +[CmdletBinding()] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', + Justification = 'Suppress false positives in Pester code blocks')] +param() + +# This is common test code setup logic for all Pester test files +BeforeAll { + $moduleRootPath = Split-Path -Path $PSScriptRoot -Parent + . (Join-Path -Path $moduleRootPath -ChildPath 'Tests\Common.ps1') + + # Define Script-scoped, readonly, hidden variables. + @{ + defaultRepositoryName = ([Guid]::NewGuid().Guid) + }.GetEnumerator() | ForEach-Object { + Set-Variable -Force -Scope Script -Option ReadOnly -Visibility Private -Name $_.Key -Value $_.Value + } + + $newGitHubRepositoryParms = @{ + AutoInit = $true + Private = $true + RepositoryName = $defaultRepositoryName + OrganizationName = $script:organizationName + } + $repo = New-GitHubRepository @newGitHubRepositoryParms + # Get the main/master branch name + $mainBranchName = $repo | Get-GitHubRepositoryBranch | Select-Object -ExpandProperty name -First 1 +} + +Describe 'GitHubCodespaces\Delete-GitHubCodespace' { + Context 'When deleting a codespace for the authenticated user' { + BeforeEach { + # Suppress HTTP 202 warning for codespace creation + # TODO: Suppression is not working as intended here. + $WarningPreference = 'SilentlyContinue' + + $newGitHubCodespaceParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $defaultRepositoryName + } + $codespace = New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + It 'Should get no content using -Confirm:$false' { + # Also asserts pipeline input + $codespace | Remove-GitHubCodespace -Confirm:$false + { Get-GitHubCodespace -CodespaceName $codespace.name } | Should -Throw + } + + It 'Should get no content using -Force' { + # Also assert CodespaceName input + Remove-GitHubCodespace -CodespaceName $codespace.name -Force + { Get-GitHubCodespace -CodespaceName $codespace.name } | Should -Throw + } + } +} + +Describe 'GitHubCodespaces\Get-GitHubCodespace' { + BeforeAll { + # Suppress HTTP 202 warning for codespace creation + $WarningPreference = 'SilentlyContinue' + + $newGitHubCodespaceParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $defaultRepositoryName + } + $null = New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + Context 'When getting codespaces for the authenticated user' { + BeforeAll { + $codespaces = Get-GitHubCodespace | + Where-Object { $_.repository.name -eq $defaultRepositoryName } + } + + It 'Should return objects of the correct type' { + $codespaces[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Codespace' + } + + It 'Should return one or more results' { + @($codespaces | Where-Object { $_ }).Count | Should -BeGreaterOrEqual 1 + } + + It 'Should return the correct properties' { + foreach ($codespace in $codespaces) + { + $codespace.owner.login | Should -Be $script:OwnerName + $codespace.repository.name | Should -Be $newGitHubCodespaceParms.RepositoryName + } + } + } + + Context 'When getting a codespace for a specified owner and repository' { + BeforeAll { + $codespaces = Get-GitHubCodespace @newGitHubCodespaceParms + } + + It 'Should return objects of the correct type' { + $codespaces[0].PSObject.TypeNames[0] | Should -Be 'GitHub.Codespace' + } + + It 'Should return one or more results' { + @($codespaces | Where-Object { $_ }).Count | Should -BeGreaterOrEqual 1 + } + + It 'Should return the correct properties' { + foreach ($codespace in $codespaces) + { + $codespace.owner.login | Should -Be $script:OwnerName + $codespace.repository.name | Should -Be $newGitHubCodespaceParms.RepositoryName + } + } + } + + Context 'When getting a codespace for a specified organization user' { + BeforeAll { + $codespaces = Get-GitHubCodespace -OrganizationName $script:organizationName + $userCodespaces = Get-GitHubCodespace -OrganizationName $script:organizationName -UserName $script:OwnerName + } + + It 'Should have results for the organization user' { + $userCodespaces.name | Should -BeIn $codespaces.name + } + + It 'Should return the correct properties' { + foreach ($codespace in $userCodespaces) + { + $codespace.owner.login | Should -Be $script:OwnerName + } + } + } + + Context 'When getting a codespace for a specified codespace name' { + BeforeAll { + $codespaces = Get-GitHubCodespace + $codespace = Get-GitHubCodespace -CodespaceName $codespaces[0].name + } + + It 'Should return objects of the correct type' { + $codespace.PSObject.TypeNames[0] | Should -Be 'GitHub.Codespace' + } + + It 'Should return the correct properties' { + $codespace.owner.login | Should -Be $script:OwnerName + } + } + + Context 'When specifiying the Uri parameter' { + BeforeAll { + $codespace = Get-GitHubCodespace -Uri $repo.RepositoryUrl + } + + It 'Should return objects of the correct type' { + $codespace.PSObject.TypeNames[0] | Should -Be 'GitHub.Codespace' + } + + It 'Should return the correct properties' { + $codespace.owner.login | Should -Be $script:OwnerName + $codespace.repository.name | Should -Be $repo.name + } + } + + Context "When specifiying the Uri parameter from the pipeline" { + BeforeAll { + $codespace = $repo | Get-GitHubCodespace + } + + It 'Should return objects of the correct type' { + $codespace.PSObject.TypeNames[0] | Should -Be 'GitHub.Codespace' + } + + It 'Should return the correct properties' { + $codespace.repository.name | Should -Be $repo.name + } + } + + AfterAll { + Get-GitHubCodespace @newGitHubCodespaceParms | Remove-GitHubCodespace -Confirm:$false -Force + } +} + + +Describe 'GitHubCodespaces\New-GitHubCodespace' { + Context -Name 'When creating a repository for the authenticated user' { + Context -Name 'When creating a codespace with default settings with RepositoryId' { + BeforeAll { + $newGitHubCodespaceParms = @{ + RepositoryId = $repo.Id + } + $codespace = New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + It 'Should return an object of the correct type' { + $codespace | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $codespace.display_name | Should -Not -BeNullOrEmpty + $codespace.repository.name | Should -Be $repo.name + $codespace.owner.UserName | Should -Be $script:OwnerName + $codespace.template | Should -BeNullOrEmpty + } + + AfterAll { + if ($codespace) + { + Remove-GitHubCodespace -CodespaceName $codespace.name -Confirm:$false + } + } + } + + Context -Name 'When creating a codespace with default settings with Ref' { + BeforeAll { + $prBranchName = 'testCodespaceByRef' + $prBranch = $repo | New-GitHubRepositoryBranch -BranchName $mainBranchName -TargetBranchName $prBranchName + $setContentParms = @{ + Path = 'README.md' + Content = 'When creating a codespace with default settings with Ref' + CommitMessage = $prBranchName + BranchName = $prBranchName + } + $repo | Set-GitHubContent @setContentParms + $pullRequest = $prBranch | New-GitHubPullRequest -Title $prBranchName -Head $prBranchName -Base $mainBranchName + + $newGitHubCodespaceParms = @{ + Ref = $pullRequest.head.ref + RepositoryId = $repo.Id + } + $codespace = New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + It 'Should return an object of the correct type' { + $codespace | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $codespace.display_name | Should -Not -BeNullOrEmpty + $codespace.git_status.ref | Should -Be $pullRequest.head.ref + $codespace.repository.name | Should -Be $repo.name + $codespace.owner.UserName | Should -Be $script:OwnerName + $codespace.template | Should -BeNullOrEmpty + } + + AfterAll { + if ($codespace) + { + Remove-GitHubCodespace -CodespaceName $codespace.name -Confirm:$false + } + } + } + + Context -Name 'When creating a codespace with default settings from a PullRequest' { + BeforeAll { + $prBranchName = 'testCodespaceFromPR' + $prBranch = $repo | New-GitHubRepositoryBranch -BranchName $mainBranchName -TargetBranchName $prBranchName + $setContentParms = @{ + Path = 'README.md' + Content = 'When creating a codespace with default settings from a PullRequest' + CommitMessage = $prBranchName + BranchName = $prBranchName + } + $repo | Set-GitHubContent @setContentParms + $pullRequest = $prBranch | New-GitHubPullRequest -Title $prBranchName -Head $prBranchName -Base $mainBranchName + + $newGitHubCodespaceParms = @{ + PullRequest = $pullRequest.number + RepositoryId = $repo.Id + } + $codespace = New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + It 'Should return an object of the correct type' { + $codespace | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $codespace.display_name | Should -Not -BeNullOrEmpty + $codespace.repository.name | Should -Be $repo.name + $codespace.owner.UserName | Should -Be $script:OwnerName + $codespace.pulls_url | Should -Be $pullRequest.url + $codespace.template | Should -BeNullOrEmpty + } + + AfterAll { + if ($codespace) + { + Remove-GitHubCodespace -CodespaceName $codespace.name -Confirm:$false + } + } + } + + Context -Name 'When creating a codespace with all possible settings' { + BeforeAll { + $newGitHubCodespaceParms = @{ + # ClientIp = 'TODO ???? - should be instead of rather than in addition to Geo, perhaps add some param validation to the function' + # DevContainerPath = 'Will add to test in the future when Get-GitHubDevContainer is implemented and the test repo includes one' + DisplayName = 'PowerShellForGitHub pester test' + Geo = 'UsWest' # location was deprecated in favor of Geo + Machine = 'basicLinux32gb' + NoMultipleRepoPermissions = $true # Not sure how to assert this, but this proves it accepts the switch without error + IdleRetentionPeriodMinutes = 10 + TimeoutMinutes = 5 + # WorkingDirectory = 'TODO ???? - not sure how to handle this' + } + $codespace = $repo | New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + It 'Should return an object of the correct type' { + $codespace | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + # $codespace.devcontainer_path | Should -Be + $codespace.display_name | Should -Be $newGitHubCodespaceParms.DisplayName + $codespace.idle_timeout_minutes | Should -Be $newGitHubCodespaceParms.TimeoutMinutes + $codespace.location | Should -Match 'WestUs' # location should align with our requested Geo + $codespace.machine.name | Should -Be $newGitHubCodespaceParms.Machine + $codespace.owner.UserName | Should -Be $script:OwnerName + $codespace.repository.name | Should -Be $repo.name + $codespace.retention_period_minutes | Should -Be $newGitHubCodespaceParms.IdleRetentionPeriodMinutes + $codespace.template | Should -BeNullOrEmpty + } + + AfterAll { + if ($codespace) + { + Remove-GitHubCodespace -CodespaceName $codespace.name -Confirm:$false + } + } + } + + Context -Name 'When creating a codespace with default settings with Repository Elements' { + BeforeAll { + $newGitHubCodespaceParms = @{ + RepositoryName = $repo.name + OwnerName = $repo.owner.login + } + $codespace = New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + It 'Should return an object of the correct type' { + $codespace | Should -BeOfType PSCustomObject + } + + It 'Should return the correct properties' { + $codespace.display_name | Should -Not -BeNullOrEmpty + $codespace.repository.name | Should -Be $repo.name + $codespace.owner.UserName | Should -Be $script:OwnerName + $codespace.template | Should -BeNullOrEmpty + } + + AfterAll { + if ($codespace) + { + Remove-GitHubCodespace -CodespaceName $codespace.name -Confirm:$false + } + } + } + } +} + +Describe 'GitHubCodespaces\Start-GitHubCodespace' { + BeforeAll { + # Suppress HTTP 202 warning for codespace creation + $WarningPreference = 'SilentlyContinue' + + $newGitHubCodespaceParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $defaultRepositoryName + } + $null = New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + Context 'When starting a codespace for the authenticated user' { + BeforeAll { + $codespace = Get-GitHubCodespace @newGitHubCodespaceParms | Select-Object -First 1 + } + + It 'Should not throw' { + # Also asserts pipeline input + { $codespace | Start-GitHubCodespace } | Should -Not -Throw + } + + It 'Should become Available' { + # Also asserts Wait and PassThru + $result = $codespace | Start-GitHubCodespace -Wait -PassThru + $result.State | Should -Be 'Available' + } + } + + AfterAll { + Get-GitHubCodespace @newGitHubCodespaceParms | Remove-GitHubCodespace -Confirm:$false -Force + } +} + +Describe 'GitHubCodespaces\Stop-GitHubCodespace' { + BeforeAll { + # Suppress HTTP 202 warning for codespace creation + $WarningPreference = 'SilentlyContinue' + + $newGitHubCodespaceParms = @{ + OwnerName = $repo.owner.login + RepositoryName = $defaultRepositoryName + } + $null = New-GitHubCodespace @newGitHubCodespaceParms -Wait + } + + Context 'When stopping a codespace for the authenticated user' { + BeforeAll { + $codespace = Get-GitHubCodespace @newGitHubCodespaceParms | Select-Object -First 1 + } + + It 'Should not throw' { + # Also asserts pipeline input + { $codespace | Stop-GitHubCodespace } | Should -Not -Throw + } + + It 'Should become Shutdown' { + # Also asserts Wait and PassThru + $result = $codespace | Stop-GitHubCodespace -Wait -PassThru + $result.State | Should -Be 'Shutdown' + } + } + + AfterAll { + Get-GitHubCodespace @newGitHubCodespaceParms | Remove-GitHubCodespace -Confirm:$false -Force + } +} + +AfterAll { + if (Get-Variable -Name repo -ErrorAction SilentlyContinue) + { + # Should delete any corresponding codespaces along with it + $repo | Remove-GitHubRepository -Confirm:$false + } + + if (Test-Path -Path $script:originalConfigFile -PathType Leaf) + { + # Restore the user's configuration to its pre-test state + Restore-GitHubConfiguration -Path $script:originalConfigFile + $script:originalConfigFile = $null + } +} diff --git a/USAGE.md b/USAGE.md index a3acb876..1fb5f916 100644 --- a/USAGE.md +++ b/USAGE.md @@ -141,6 +141,17 @@ * [Removing an environment](#removing-an-environment) * [Advanced](#advanced) * [Migrating blog comments to GitHub issues](#migrating-blog-comments-to-github-issues) + aces + * [Codespaces](#codespaces) + * [Getting codespaces](#getting-codespaces) + * [Creating a codespace](#creating-a-codespace) + * [Removing a codespace](#removing-a-codespace) + * [Starting a codespace](#starting-a-codespace) + * [Stopping a codespace](#stopping-a-codespace) + * [Codespaces](#codespaces-organizations) + * [Getting codespaces](#getting-organization-codespaces) + * [Removing a codespace](#removing-an-organization-codespace) + * [Stopping a codespace](#stopping-an-organization-codespace) ---------- @@ -1288,3 +1299,109 @@ $issue | New-GitHubIssueComment -Body $CommentBody # Close issue $issue | Set-GitHubIssue -State Closed ``` + +---------- + +### Codespaces + +#### Getting codespaces +```powershell +# Get all codespaces for the current authenticated user +Get-GitHubCodespace + +# Get all codespaces for the current authenticated user in a repository +Get-GitHubCodespace -OwnerName microsoft -RepositoryName TestRepo + +# Get a codespace by name +Get-GitHubCodespace -CodespaceName 'microsoft-symmetrical-chainsaw-7q4vp6v7q3pwqq' +``` + +#### Create a codespace +```powershell +# Create a codespace in the specified repository by id +New-GitHubCodespace -RepositoryId 582779513 + +# Create a codespace in the specified repository by name +New-GitHubCodespace -OwnerName microsoft -RepositoryName TestRepo + +# Create a codespace in the specified repository by id from a pull request +New-GitHubCodespace -RepositoryId 582779513 -PullRequest 508 + +# Create a codespace in the specified repository by name from a pull request +New-GitHubCodespace -OwnerName microsoft -RepositoryName TestRepo -PullRequest 42 + +# Create a codespace in repository from pipeline +$repo = Get-GitHubRepository -OwnerName microsoft -RepositoryName TestRepo +$repo | New-GitHubCodespace + +# Create a codespace in repository from pipeline with options +$newGitHubCodespaceParms = @{ + DisplayName = 'PowerShellForGitHub usage' + Geo = 'UsWest' + Machine = 'basicLinux32gb' + NoMultipleRepoPermissions = $true + IdleRetentionPeriodMinutes = 10 + TimeoutMinutes = 5 +} +$codespace = $repo | New-GitHubCodespace @newGitHubCodespaceParms +``` + +#### Removing a codespace +```powershell +$codespaceName = 'microsoft-symmetrical-chainsaw-7q4vp6v7q3pwqq' + +# Remove a codespace for the current authenticated user +Remove-GitHubCodespace -CodespaceName $codespaceName +``` + +#### Starting a codespace +```powershell +$codespaceName = 'microsoft-symmetrical-chainsaw-7q4vp6v7q3pwqq' + +# Starting a codespace (asynchronous) +Start-GithubCodespace -CodespaceName $codespaceName + +# Starting a codespace (wait for Available) +Start-GithubCodespace -CodespaceName $codespaceName -Wait +``` + +#### Stopping a codespace +```powershell +$codespaceName = 'microsoft-symmetrical-chainsaw-7q4vp6v7q3pwqq' + +# Stopping a codespace (asynchronous) +Stop-GithubCodespace -CodespaceName $codespaceName + +# Stopping a codespace (wait for Shutdown) +Stop-GithubCodespace -CodespaceName $codespaceName -Wait +``` + +---------- + +### Codespaces organizations + +#### Getting organization Codespaces +```powershell + +# Get all codespaces for an Organization +Get-GitHubCodespace -OrganizationName microsoft + +# Get all codespaces for a specific organization user +Get-GitHubCodespace -OrganizationName microsoft -UserName octocat +``` + +#### Removing an organization Codespace +```powershell +$codespaceName = 'microsoft-symmetrical-chainsaw-7q4vp6v7q3pwqq' + +# Remove a codespace for an organization user +Remove-GitHubCodespace -OrganizationName microsoft -UserName octocat -CodespaceName $codespaceName +``` + +#### Stopping an organization Codespace +```powershell +$codespaceName = 'microsoft-symmetrical-chainsaw-7q4vp6v7q3pwqq' + +# Stopping a codespace (wait for Shutdown) +Stop-GithubCodespace -OrganizationName microsoft -UserName octocat -CodespaceName $codespaceName -Wait +``` \ No newline at end of file From 356350b22f47acf55e72380442c630e6c9591fbc Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:36:18 -0800 Subject: [PATCH 50/51] Replace `BinaryFormatter` with `PSSerializer` (#415) Replace `BinaryFormatter` with `PSSerializer` Since the former has been removed from PowerShell 7.4 (because it was removed from .NET 7) and the latter can accomplish the same thing. The default depth is 1, so we need to specify. Best I could find was that the prior implementation defaulted to a depth of 64, so we're going with that. --- CONTRIBUTING.md | 5 +++-- Helpers.ps1 | 10 ++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c326deeb..2591dab2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -422,7 +422,7 @@ Pester can also be used to test code-coverage, like so: ```powershell $pesterConfig = New-PesterConfiguration -$pesterConfig.CodeCoverage.Path = @("$root\GitHubLabels.ps1") +$pesterConfig.CodeCoverage.Path = @("$root\GitHubLabels.ps1") $pesterConfig.CodeCoverage.Enabled = $true Invoke-Pester -Configuration $pesterConfig @@ -435,7 +435,7 @@ The code-coverage object can be captured and interacted with, like so: ```powershell $pesterConfig = New-PesterConfiguration -$pesterConfig.CodeCoverage.Path = @("$root\GitHubLabels.ps1") +$pesterConfig.CodeCoverage.Path = @("$root\GitHubLabels.ps1") $pesterConfig.CodeCoverage.Enabled = $true $pesterConfig.Run.PassThru = $true @@ -625,6 +625,7 @@ Thank you to all of our contributors, no matter how big or small the contributio - **[Neil White (@variableresistor)](https://github.com/variableresistor)** - **[Mark Curole(@tigerfansga)](https://github.com/tigerfansga)** - **[Jason Vercellone(@vercellone)](https://github.com/vercellone)** +- **[Andy Jordan (@andyleejordan)](https://github.com/andyleejordan)** ---------- diff --git a/Helpers.ps1 b/Helpers.ps1 index d915140c..3a3023cd 100644 --- a/Helpers.ps1 +++ b/Helpers.ps1 @@ -394,14 +394,8 @@ function DeepCopy-Object [PSCustomObject] $InputObject ) - $memoryStream = New-Object System.IO.MemoryStream - $binaryFormatter = New-Object System.Runtime.Serialization.Formatters.Binary.BinaryFormatter - $binaryFormatter.Serialize($memoryStream, $InputObject) - $memoryStream.Position = 0 - $DeepCopiedObject = $binaryFormatter.Deserialize($memoryStream) - $memoryStream.Close() - - return $DeepCopiedObject + $serialData = [System.Management.Automation.PSSerializer]::Serialize($InputObject, 64) + return [System.Management.Automation.PSSerializer]::Deserialize($serialData) } function New-TemporaryDirectory From fd4fa65f23ca30f18f85312a85348e660c287a9c Mon Sep 17 00:00:00 2001 From: Howard Wolosky Date: Mon, 20 Nov 2023 17:32:05 -0800 Subject: [PATCH 51/51] Update module to 0.17.0 (#424) --- CHANGELOG.md | 84 ++++++++++++++++++++++++++++++++++++++++ PowerShellForGitHub.psd1 | 2 +- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3688003..92218368 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,90 @@ # PowerShellForGitHub PowerShell Module # Changelog +## [0.17.0](https://github.com/PowerShell/PowerShellForGitHub/tree/0.17.0) - (2021/11/20) + +### Features + ++ Add support for `Invoke-GHGraphQl` which then allowed support for + `Get-GitHubRepositoryBranchPatternProtectionRule`, `New-GitHubRepositoryBranchPatternProtectionRule`, + and `Remove-GitHubRepositoryBranchPatternProtectionRule` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/313) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/f7efc4a03640cf292b0e6a256d6713a6f15145b2) + ++ Updated `Invoke-GHRestMethod` (and `Invoke-GHRestMethodMultipleResult`) to support versioned API's + with the new (optional) `ApiVersion` parameter + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/379) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/938896738c7a8c8b6d3b7b798c761798e4fce651) + ++ Added the `HasDiscussions` switch to `New-GitHubRepository` and `Set-GitHubRepository` to allow + the control of whether discussions are supported in a repository + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/382) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/3ccee43287e053a4ad9f9729a943e75ad12ce904) + ++ Added the `AllowAutoMerge` switch to `New-GitHubRepository` and `Set-GitHubRepository` (which is + currently only supported on public repositories). + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/383) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/b976e9515cd42d521bd3f4d7ab6fb2b870cd98ed) + ++ Added the `AllowUpdateBranch` switch to `New-GitHubRepository` and `Set-GitHubRepository`, which + specifies whether to always allow a pull request head branch that is behind its base branch + to be updated even if it is not required to be up-to-date before merging. + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/387) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/9baf54e44cee7fb79dee74ae54306b1edbe6e7d0) + ++ Added the `WebCommitSignoffRequired` switch to `Set-GitHubRepository`, which + specifies whether to require contributors to sign off on web-based commits. + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/389) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/516be0b4cafafb334bca5951c057af0885e6976f) + ++ Added the `SecretScanning` parameter to `Set-GitHubRepository`, which + specifies whether to enable or disable secret scanning for the repository. + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/391) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/43d5392642cce2ec3d45fbbb1066f7b2efc3b8c4) + ++ Added support for Deployment environments with `New-GitHubDeploymentEnvironment`, + `Get-GitHubDeploymentEnvironment`, `Set-GitHubDeploymentEnvironment` and + `Remove-GitHubDeploymentEnvironment` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/395) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/dd844e5e4a2224e092c8d247f889f6ebabda1767) + ++ Added the ability to control how the title and message of a commit are handled during a merge + and a squash merge with the new `SquashMergeCommitTitle`, `SquashMergeCommitMessage`, + `MergeCommitTitle`, and `MergeCommitMessage` parameters on `New-GitHubRepository` and + `Set-GitHubRepository` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/385) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/6f94a9b0a37ee466c2fb457299c78de1bd371f95) + ++ Added base support for GitHub Codespaces with `Get-GitHubCodespace`, `New-GitHubCodespace`, + `Remove-GitHubCodespace`, `Start-GitHubCodespace` and `Stop-GitHubCodespace` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/407) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/9ec863b14277a524aa8f2931b742bb3dfed10d5a) + +### Fixes + ++ Fixed a documentation error with `DefaultRepositoryName` in `Set-GitHubConfiguration` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/341) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/8b46226ba5347155470c2d789ef2356e4aef118a) + ++ Fixed a bug that caused Telemetry to stop working when a PowerShell session was open for longer + than a day + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/355) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/4b48946d81924a8508be2b16c28d9842da7d5b37) + ++ Improved the error message displayed when an API returns with a 404 error code + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/363) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/1466f1656b85e256917bc3057ba6dd6d1579a652) + ++ Was not properly forwarding the `AccessToken` to sub-commands for + `Get-GitHubRepositoryTeamPermission`, `Set-GitHubRepositoryTeamPermission`, and + `Remove-GitHubRepositoryTeamPermission` + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/362) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/4d7667bcaf66523bf3b0194d847d8bfc3c6325f1) + ++ Fixed the logic that determined the simplified explanation of Team permissions exposed by a + repository object + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/361) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/d8ee50a7ad0fa1b12e3b5d7745aeed348a340708) + ++ Fixed support for PowerShell 7.4+ which removed support for `BinaryFormatter`. + [[pr]](https://github.com/PowerShell/PowerShellForGitHub/pull/415) | [[cl]](https://github.com/microsoft/PowerShellForGitHub/commit/356350b22f47acf55e72380442c630e6c9591fbc) + +### Authors + ++ [**@HowardWolosky**](https://github.com/HowardWolosky) ++ [**@X-Guardian**](https://github.com/X-Guardian) ++ [**@matt9ucci**](https://github.com/matt9ucci) ++ [**@variableresistor**](https://github.com/variableresistor) ++ [**@vercellone**](https://github.com/vercellone) ++ [**@andyleejordan**](https://github.com/andyleejordan) + +------ + ## [0.16.1](https://github.com/PowerShell/PowerShellForGitHub/tree/0.16.1) - (2021/05/26) ### Features diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 8d3e1cac..f53a71ff 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -7,7 +7,7 @@ CompanyName = 'Microsoft Corporation' Copyright = 'Copyright (C) Microsoft Corporation. All rights reserved.' - ModuleVersion = '0.16.1' + ModuleVersion = '0.17.0' Description = 'PowerShell wrapper for GitHub API' # Script module or binary module file associated with this manifest.