Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support seamless pipelining of related cmdlets #63

Closed
danbelcher-MSFT opened this issue Dec 5, 2018 · 5 comments · Fixed by #242
Closed

Support seamless pipelining of related cmdlets #63

danbelcher-MSFT opened this issue Dec 5, 2018 · 5 comments · Fixed by #242
Labels
enhancement An issue or pull request introducing new functionality to the project. help wanted Anyone in the community is welcome to do this work technical debt Work that was postponed by a previous change. up for grabs Anyone in the community is welcome to do this work

Comments

@danbelcher-MSFT
Copy link

Many related PowerShell cmdlets are designed to operate off of a common datatype in order to support pipelining, e.g.

Get-ChildItem .. | Remove-Item

So Get-ChildItem outputs a [System.IO.FileInfo] object and Remove-Item is designed to populate it's input either from a [System.IO.FileInfo] object or by explicit named parameter.

The cmdlets in this module should support a similar paradigm, so that related cmdlets can be seamlessly piped to each other, as PowerShell users would expect, e.g.

New-GitHubMilestone ... |
    Update-GitHubIssue -Issue 4 -PassThru |
    Update-GitHubIssue -Issue 10

In this example, the OwnerName, RepositoryName, and Milestone can be inferred based on the presence of the Milestone object in the pipeline.

@HowardWolosky HowardWolosky added enhancement An issue or pull request introducing new functionality to the project. up for grabs Anyone in the community is welcome to do this work help wanted Anyone in the community is welcome to do this work technical debt Work that was postponed by a previous change. labels Dec 6, 2018
@Thraka
Copy link

Thraka commented Jan 24, 2019

I'm really surprised this wasn't designed from the ground up to be built like this. I mean, it's PowerShell, that's the whole point 😄

@HowardWolosky
Copy link
Member

It was an oversight at the time when I did a refresh of the module. Luckily, adding-in pipeline support is totally possible (as Daniel described). If you're interested in helping out @Thraka, we'd love any contributions.

@Thraka
Copy link

Thraka commented Jan 25, 2019

I'm not a powershell design expert at all 😄 I still design my powershell like it's C#/.net code

@TylerLeonhardt
Copy link
Member

The reality is, it's hard. This module should try to do the least amount of work as possible over the GitHub API because if that changes, this breaks.

Additionally, I'm sure that @HowardWolosky doesn't want to be in the business of writing types/classes for all the GitHub outputs.

Take a look at how I did pipelining in #193

[Parameter(Mandatory, ParameterSetName='Uri', ValueFromPipelineByPropertyName)]
[Alias("repository_url")]
[string] $Uri,

[Parameter(Mandatory, ParameterSetName='Elements')]
[Parameter(Mandatory, ParameterSetName='Uri', ValueFromPipelineByPropertyName)]
[Alias("number")]
[int64] $Issue,

The idea is, using the power of parameter aliases and ValueFromPipelineByPropertyName to allow the output of some cmdlets to pipe into others.

@HowardWolosky
Copy link
Member

Actually, I started thinking about this some more after having looked at your #193 and @X-Guardian's #205. I think this can be done in a pretty natural way. I started experimenting over here:

HowardWolosky/PowerShellForGitHub@c1e88b6

I think we should be explicitly adding consistently named properties to all objects that we're returning. For instance, if it's an object somehow related to a specific repo, then is should have a RepositorUrl NoteProperty on it. Then we can use your ValueFromPipelineByPropertyName trick with the added [Alias('RepositoryName')] on Uri so that just about any object pipelined into another function can auto-extract the relevant OwnerName/RepositoryName from that Uri. Additionally, if the object being returned has its own ID (like an Issue or Release), then we should be adding an explicit IssueId or ReleaseId property to those objects. That way, the [Alias] for those functions can really be explicit to avoid mistaken casting from a bad pipeline (so, for instance, we wouldn't use number like you do above for Issue.

HowardWolosky added a commit that referenced this issue Jun 18, 2020
# Description

Comprehensively adds pipeline support throughout the entire module

This change required examining every method, and in some cases a few breaking changes (noted below) had to be introduced in order to make support work consistently end-to-end.  UT's were added for every function, which resuled in a few bugs that were identified and fixed (also noted below).

## Breaking changes
### Unavoidable Breaks
 * `Get-GitHubRepositoryBranch`: `Name` parameter is now `BranchName`.
  > A `GitHub.Repository` object has a `name` property which is the name of the repo.  Piping in the repo object to this method would confuse it, making it search for a branch with the name of the repo, as opposed to the desired effect of just listing out all branches in the repo.

 * `*-GitHub*Label`: `Name` parameter is now `Label`.
  > Similar to above.
  > `Name` was too generic and was causing unintended conflicts when passing in certain objects over the pipeline (like a `GitHub.Repository`) which also has a `name` property, making it impossible to pipe in a repository to list all labels (since it was trying to query for a label in that repository named the same as the repo.

 * `*-GitHubLabel`: `Milestone` parameter is now `MilestoneNumber`.
  > A `GitHub.Issue` contains a `milestone` object property, and PowerShell was complaining that there was no way to convert that to an `[int64]` when an Issue was passed in via the pipeline.  The only way to avoid this was to use `MilestoneNumber` which is the name of the property we add to `GitHub.Milestone` objects, and it's what we alias to in all other methods that interact with milestones.

 * `*-GitHubIssue`: `Milestone` parameter is now `MilestoneNumber`.
  > A `GitHub.Issue` contains a `milestone` object property, and PowerShell was complaining that there was no way to convert that to an `[int64]` when an Issue was passed in via the pipeline.  The only way to avoid this was to use `MilestoneNumber` which is the name of the property we add to `GitHub.Milestone` objects, and it's what we alias to in all other methods that interact with milestones.

 * `Get-GitHubLicense`: `Name` parameter is now `Key`.
  > The `key` is what you can query against, but a License object has _both_ a `name` and a `key` property, which caused piped object queries to fail with the existing parameter name.
 
 * `Get-GitHubCodeOfConduct`: `Name` parameter is now `Key`.
  > Similar to above.
  > The `key` is what you can query against, but a Code of Conduct object has _both_ a `name` and a `key` property, which caused piped object queries to fail with the existing parameter name.
 
 * `New-ProjectCard`: Signature has changed.  Instead of specifying `ContentId` and `ContentType`, you now just directly specify either `IssueId` or `PullRequestId`.
  > Pipeline input would not have worked without this change. Additionally, this simply provides a cleaner interface for users in general, requiring one less input.
 
 * `Get-GitHubUserContextualInformation`: Signature has changed.  Instead of specifying `SubjectId` and `SubjectType`, you now just directly specify either `OrganizationId`, `RepositoryId`, `IssueId` or `PullRequestId`.
  > Similar to above.
  > Pipeline input would not have worked without this change. Additionally, this simply provides a cleaner interface for users in general, requiring one less input.
 

### Breaks With Workarounds
 * A number of changes to the Comments functions
    * `GitHubComments.ps1` was renamed to `GitHubIssueComments.ps1` given that there are 5 different types of comments, these functions focus on `Issue` comments, and there doesn't currently appear to be a path forward for creating a single unified API set for all comment types.

    * All of these methods were renamed from `*-GitHubComment` to `*-GitHubIssueComment`, however they were also aliased back to their previous names (for now).  You should really migrate to these new names however.

    * The main parameter was renamed from `CommentId` to `Comment`, however it was aliased back to `CommentId`.

 * `*-GitHubProject`: `ArchivedState` parameter is now `State` (but aliased back to `ArchivedState` to help with migration).

 * `*-GitHubProject`: `Name` parameter is now `ColumnName` (but aliased back to `Name`)

 * `*-GitHubProjectColumn`: `Name` parameter is now `ColumnName` (but aliased back to `Name`)

 * `Move-GitHubProjectCard`: `ColumnId` parameter is now `Column` (but aliased back to `ColumnId` to support pipeline input).

 * `Get-GitHubRelease`: `ReleaseId` parameter is now `Release` (but aliased back to `ReleaseId` to support pipeline input).
 
 * `Rename-GitHubRepository` has been effectively deprectaed.  It was built on top of the same endpoint that `Set-GitHubRepository` uses, but was only modifying a single property (the name).  For now, the function remains, but it now just internally calls into `Set-GitHubRepository` to perform the same action.
 
 * `Set-GitHubRepositoryTopic`: `Name` parameter is now `Topic` (but aliased back to `Name`).
 
 * `Get-GitHubUser`: `User` parameter is now `UserName` (but aliased back to `User` and `Name`).

 * `Get-GitHubUserContextualInformation`: `User` parameter is now `UserName` (but aliased back to `User` and `Name`).

## Bug Fixes:
 * Events had been using a typo'd version of the `sailor-v` AcceptHeader.  This was fixed as part of the migration to using the AcceptHeader constants.
 * `Lock-GitHubIssue` was not correctly providing the `lock_reason` value to the API, so that metadata was getting lost.  This was caught by new UT's and then fixed.
 * `Update-GitHubLabel` was modified to accept colors both with and without a leading # sign, just like `New-GitHubLabel` already supported.
 
## New Features:
 * `Get-GitHubGitIgnore` has a new `RawContent` switch which allows you to directly get back the content of the actual .gitignore file.
 * `Set-GitHubRepository` has been updated to allow users to change the name (rename) the repository at the same time as making any of their other changes.  If a new name has been specified, users will be required to confirm the change, or to specify `-Confirm:$false` and/or `-Force` to avoid the confirmation.
 * `Get-GitHubRepositoryCollaborator` has gained a new parameter `Affiliation` allowing you to filter which collaborators you're interested in querying for.

## Minor updates:
 * Fixed the casing of the "microsoft" OwnerName in any examples
 * Fixed the casing of `GitHub` in the `Assignee` method names (was `Github` intead of `GitHub`
 * Added new configuration property (`DisablePipelineSupport`) to assist with pipeline development
 * All `AcceptHeader` usage has migrated to using script-wide constants
 * `Split-GitHubUri` can now return both components in a single function call if no switch is specified.
 * Added `Join-GitHubUri` which can reverse what `Split-GitHubUri` does, based on the configured `ApiHostName`.
 * Adds type information (via `.OUTPUTS` and `[OutputType()]` for every function.
 * Documentation updates reflecting the new pipeline support.

## Test changes:
 * `Set-StrictMode -Version 1.0` has been specified for all tests to catch access to undeclared variables (which should help catch common typo errors)
 * The workarounds for PSScriptAnalyzer's false complaint for rule `PSUseDeclaredVarsMoreThanAssignments` have been removed, and all test files now suppress that rule.
 * A test file now exists for every module file, and some tests were moved around to the appropriate file (away from GitHubAnalytics.tests.ps1 which had previously been a dumping ground for tests).
 * A _substantial_ number of new tests have been added.  Every function should now be tested with limited exceptions (like for Organizations and Teams where we don't yet have the support in the module to get the account in the appropriate state to be able to query with those existing functions).
  
> Note: These tests fully pass with Pester 4.10.1.  Some additional work may be done prior to merging to get them passing with Pester 5.0, but the priority is to get this merged into master soon in order to unblock the pipeline of existing pull requests that have been waiting on this change.

#### Issues Fixed
- Fixes #63

#### References
[The whole API set](https://developer.github.com/v3/)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement An issue or pull request introducing new functionality to the project. help wanted Anyone in the community is welcome to do this work technical debt Work that was postponed by a previous change. up for grabs Anyone in the community is welcome to do this work
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants