diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f3e2d01f..3195ab63 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -554,6 +554,7 @@ Thank you to all of our contributors, no matter how big or small the contributio - **[Jess Pomfret (@jpomfret)](https://github.com/jpomfret)** - **[Giuseppe Campanelli (@themilanfan)](https://github.com/themilanfan)** - **[Christoph Bergmeister (@bergmeister)](https://github.com/bergmeister)** +- **[Simon Heather (@X-Guardian)](https://github.com/X-Guardian)** ---------- diff --git a/GitHubRepositories.ps1 b/GitHubRepositories.ps1 index dcb2fc92..50849b7a 100644 --- a/GitHubRepositories.ps1 +++ b/GitHubRepositories.ps1 @@ -227,6 +227,175 @@ filter New-GitHubRepository return (Invoke-GHRestMethod @params | Add-GitHubRepositoryAdditionalProperties) } +filter New-GitHubRepositoryFromTemplate +{ +<# + .SYNOPSIS + Creates a new repository on GitHub from a template repository. + + .DESCRIPTION + Creates a new repository on GitHub from a template repository. + + The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub + + .PARAMETER OwnerName + Owner of the template repository. + If no value is specified, the DefaultOwnerName configuration property value will be used, + and if there is no configuration value defined, the current authenticated user will be used. + + .PARAMETER RepositoryName + Name of the template repository. + + .PARAMETER Uri + Uri for the repository. + The OwnerName and RepositoryName will be extracted from here instead of needing to provide + them individually. + + .PARAMETER TargetOwnerName + The organization or person who will own the new repository. + To create a new repository in an organization, the authenticated user must be a member + of the specified organization. + + .PARAMETER TargetRepositoryName + Name of the repository to be created. + + .PARAMETER Description + A short description of the repository. + + .PARAMETER Private + By default, this repository will created Public. Specify this to create a private + 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. + + .PARAMETER NoStatus + If this switch is specified, long-running commands will run on the main thread + with no commandline status update. When not specified, those commands run in + the background, enabling the command prompt to provide status information. + If not supplied here, the DefaultNoStatus configuration property value will be used. + + .INPUTS + GitHub.Branch + GitHub.Content + GitHub.Event + GitHub.Issue + GitHub.IssueComment + GitHub.Label + GitHub.Milestone + GitHub.PullRequest + GitHub.Project + GitHub.ProjectCard + GitHub.ProjectColumn + GitHub.Release + GitHub.Repository + + .OUTPUTS + GitHub.Repository + + .NOTES + The authenticated user must own or be a member of an organization that owns the repository. + + To check if a repository is available to use as a template, call `Get-GitHubRepository` on the + repository in question and check that the is_template property is $true. + + .EXAMPLE + New-GitHubRepositoryFromTemplate -OwnerName MyOrg -RepositoryName MyTemplateRepo -TargetRepositoryName MyNewRepo -TargetOwnerName Me + + Creates a new GitHub repository from the specified template repository. + + .EXAMPLE + $repo = Get-GitHubRepository -OwnerName MyOrg -RepositoryName MyTemplateRepo + $repo | New-GitHubRepositoryFromTemplate -TargetRepositoryName MyNewRepo -TargetOwnerName Me + + You can also pipe in a repo that was returned from a previous command. +#> + [CmdletBinding( + SupportsShouldProcess, + PositionalBinding = $false)] + [OutputType({$script:GitHubRepositoryTypeName})] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", + Justification="Methods called within here make use of PSShouldProcess, and the switch is + passed on to them inherently.")] + param( + [Parameter(ParameterSetName = 'Elements')] + [string] $OwnerName, + + [Parameter( + Mandatory, + Position = 1, + ParameterSetName = 'Elements')] + [ValidateNotNullOrEmpty()] + [string] $RepositoryName, + + [Parameter( + Mandatory, + Position = 2, + ValueFromPipelineByPropertyName, + ParameterSetName = 'Uri')] + [Alias('RepositoryUrl')] + [string] $Uri, + + [Parameter( + Mandatory, + Position = 3)] + [ValidateNotNullOrEmpty()] + [string] $TargetOwnerName, + + [Parameter( + Mandatory, + Position = 4)] + [ValidateNotNullOrEmpty()] + [string] $TargetRepositoryName, + + [string] $Description, + + [switch] $Private, + + [string] $AccessToken, + + [switch] $NoStatus + ) + + Write-InvocationLog + + $elements = Resolve-RepositoryElements -BoundParameters $PSBoundParameters + $OwnerName = $elements.ownerName + + $telemetryProperties = @{ + RepositoryName = (Get-PiiSafeString -PlainText $RepositoryName) + OwnerName = (Get-PiiSafeString -PlainText $OwnerName) + TargetRepositoryName = (Get-PiiSafeString -PlainText $TargetRepositoryName) + TargetOwnerName = (Get-PiiSafeString -PlainText $TargetOwnerName) + } + + $uriFragment = "repos/$OwnerName/$RepositoryName/generate" + + $hashBody = @{ + owner = $TargetOwnerName + name = $TargetRepositoryName + } + + if ($PSBoundParameters.ContainsKey('Description')) { $hashBody['description'] = $Description } + if ($PSBoundParameters.ContainsKey('Private')) { $hashBody['private'] = $Private.ToBool() } + + $params = @{ + 'UriFragment' = $uriFragment + 'Body' = (ConvertTo-Json -InputObject $hashBody) + 'Method' = 'Post' + 'Description' = "Creating $TargetRepositoryName from Template" + 'AcceptHeader' = $script:baptisteAcceptHeader + 'AccessToken' = $AccessToken + 'TelemetryEventName' = $MyInvocation.MyCommand.Name + 'TelemetryProperties' = $telemetryProperties + 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue ` + -BoundParameters $PSBoundParameters -Name NoStatus -ConfigValueName DefaultNoStatus) + } + + return (Invoke-GHRestMethod @params | Add-GitHubRepositoryAdditionalProperties) +} + filter Remove-GitHubRepository { <# diff --git a/PowerShellForGitHub.psd1 b/PowerShellForGitHub.psd1 index 96397359..3504bf7c 100644 --- a/PowerShellForGitHub.psd1 +++ b/PowerShellForGitHub.psd1 @@ -114,6 +114,7 @@ 'New-GitHubProjectColumn', 'New-GitHubPullRequest', 'New-GitHubRepository', + 'New-GitHubRepositoryFromTemplate', 'New-GitHubRepositoryFork', 'Remove-GitHubAssignee', 'Remove-GitHubIssueComment', diff --git a/Tests/GitHubRepositories.tests.ps1 b/Tests/GitHubRepositories.tests.ps1 index 04aa8e01..6575f249 100644 --- a/Tests/GitHubRepositories.tests.ps1 +++ b/Tests/GitHubRepositories.tests.ps1 @@ -290,6 +290,84 @@ try } } + 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 '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 + } + + $repo = New-GitHubRepositoryFromTemplate @newGitHubRepositoryFromTemplateParms + } + + It 'Should support pipeline input for the uri parameter' { + $newGitHubRepositoryFromTemplateParms = @{ + TargetOwnerName = $ownerName + TargetRepositoryName = $repoName + } + + { $templateRepo | New-GitHubRepositoryFromTemplate @newGitHubRepositoryFromTemplateParms -WhatIf } | + Should -Not -Throw + } + + 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 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) + { + 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 'Getting repositories' { Context 'For authenticated user' { BeforeAll -Scriptblock { diff --git a/USAGE.md b/USAGE.md index 73c4d5f1..2b275c61 100644 --- a/USAGE.md +++ b/USAGE.md @@ -29,7 +29,11 @@ * [Updating the current authenticated user](#updating-the-current-authenticated-user) * [Getting any user](#getting-any-user) * [Getting all users](#getting-all-users) - * [Repositories](#repositories) + * [Repositories](#repositories]) + * [Create a repository](#Create-a-repository) + * [Create a repository in an organization](#Create-a-repository-in-an-organization) + * [Create a repository in an organization and grant access to a team](#Create-a-repository-in-an-organization-and-grant-access-to-a-team) + * [Create a repository from a template repository](#Create-a-repository-from-a-template-repository) * [Get repository vulnerability alert status](#get-repository-vulnerability-alert-status) * [Enable repository vulnerability alerts](#enable-repository-vulnerability-alerts) * [Disable repository vulnerability alerts](#disable-repository-vulnerability-alerts) @@ -108,7 +112,9 @@ The logging is affected by configuration properties (which can be checked with different log file for each PowerShell process. An easy way to view the filtered entries for a session is (replacing `PID` with the PID that you are interested in): - Get-Content -Path -Encoding UTF8 | Where { $_ -like '*[[]PID[]]*' } +```powershell +Get-Content -Path -Encoding UTF8 | Where { $_ -like '*[[]PID[]]*' } +``` ---------- @@ -427,6 +433,30 @@ Get-GitHubUser ### Repositories +#### Create a repository + +```powershell +New-GitHubRepository -RepositoryName TestRepo +``` + +#### Create a repository in an organization + +```powershell +New-GitHubRepository -RepositoryName TestRepo -OrganizationName MyOrg +``` + +#### Create a repository in an organization and grant access to a team + +```powershell +$myTeam = Get-GitHubTeam -OrganizationName MyOrg | Where-Object -Property name -eq MyTeam +New-GitHubRepository -RepositoryName TestRepo -OrganizationName MyOrg -TeamId $myTeam.id +``` + +#### Create a repository from a template repository + +```powershell +New-GitHubRepositoryFromTemplate -OwnerName MyOrg -RepositoryName MyNewRepo-TemplateOwnerName MyOrg -TemplateRepositoryName MyTemplateRepo +======= #### Get repository vulnerability alert status ```powershell