├── ci ├── Publish-Module.ps1 ├── New-ModuleManifest.ps1 ├── Invoke-Tests.ps1 ├── CodeCovIo.psd1 └── CodeCovIo.psm1 ├── .codecov.yml ├── .vscode └── settings.json ├── VSTSPosh.sln ├── appveyor.yml ├── LICENSE ├── README.md ├── Tests ├── WorkItems.tests.ps1 ├── Projects.tests.ps1 ├── Builds.tests.ps1 └── Code.tests.ps1 ├── VSTSPosh.pssproj ├── .gitignore ├── CHANGELOG.md ├── lib ├── Workitems.ps1 ├── Releases.ps1 ├── Projects.ps1 ├── Code.ps1 └── Builds.ps1 ├── VSTS.psm1 └── tests └── Module.tests.ps1 /ci/Publish-Module.ps1: -------------------------------------------------------------------------------- 1 | if ($env:APPVEYOR_REPO_BRANCH -eq 'master'-and $env:APPVEYOR_PULL_REQUEST_NUMBER -eq $null) 2 | { 3 | choco install NuGet.CommandLine 4 | Install-PackageProvider -Name NuGet -Force 5 | Publish-Module -NuGetApiKey $env:ApiKey -Path C:\VSTS -Confirm:$False -Verbose 6 | } 7 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: no 4 | # dev should be the baseline for reporting 5 | branch: dev 6 | 7 | comment: 8 | layout: "reach, diff" 9 | behavior: default 10 | 11 | coverage: 12 | range: 50..80 13 | round: down 14 | precision: 0 15 | 16 | status: 17 | project: 18 | default: 19 | # Set the overall project code coverage requirement to 70% 20 | target: 70 21 | patch: 22 | default: 23 | # Set the pull request requirement to not regress overall coverage by more than 5% 24 | # and let codecov.io set the goal for the code changed in the patch. 25 | target: auto 26 | threshold: 5 27 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "powershell.codeFormatting.openBraceOnSameLine": false, 4 | "powershell.codeFormatting.newLineAfterOpenBrace": false, 5 | "powershell.codeFormatting.newLineAfterCloseBrace": true, 6 | "powershell.codeFormatting.whitespaceBeforeOpenBrace": true, 7 | "powershell.codeFormatting.whitespaceBeforeOpenParen": true, 8 | "powershell.codeFormatting.whitespaceAroundOperator": true, 9 | "powershell.codeFormatting.whitespaceAfterSeparator": true, 10 | "powershell.codeFormatting.ignoreOneLineBlock": false, 11 | "powershell.codeFormatting.preset": "Custom", 12 | "files.trimTrailingWhitespace": true, 13 | "files.insertFinalNewline": true, 14 | "editor.tabSize": 4, 15 | "editor.insertSpaces": true, 16 | "editor.detectIndentation": false 17 | } 18 | -------------------------------------------------------------------------------- /VSTSPosh.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{F5034706-568F-408A-B7B3-4D38C6DB8A32}") = "VSTSPosh", "VSTSPosh.pssproj", "{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | clone_folder: C:\VSTS 2 | 3 | image: WMF 5 4 | 5 | install: 6 | - ps: | 7 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force 8 | Install-Module -Name Pester -Force -Scope CurrentUser 9 | 10 | # Install Nuget.exe to enable package creation 11 | $nugetExePath = Join-Path -Path $ENV:APPVEYOR_BUILD_FOLDER ` 12 | -ChildPath 'nuget.exe' 13 | $Uri = 'https://dist.nuget.org/win-x86-commandline/v3.4.4/NuGet.exe' 14 | Invoke-WebRequest -Uri $Uri -OutFile $nugetExePath 15 | 16 | version: 1.0.{build} 17 | 18 | build_script: 19 | - ps: .\ci\New-ModuleManifest.ps1 20 | 21 | test_script: 22 | - ps: .\ci\Invoke-Tests.ps1 23 | 24 | deploy_script: 25 | - ps: .\ci\Publish-Module.ps1 26 | 27 | environment: 28 | ApiKey: 29 | secure: jv+jb1IJtjQxAxQigSve12KwVeuu7evZk7Ot5PKapLebDyl2LHsQGcqZFQ8VeDxV 30 | VSTSPoshToken: 31 | secure: FynjMo+abZRZQv1RB0UnKzORp7YFmF9+ey17ezNxQ1abYcPzVhU+q4p/bbWA2xmwfyxVFg0xMGDssU6DhW4IJA== 32 | VSTSPoshUserName: 33 | secure: edlf8+6ClMjqoBuBweBkxQ== 34 | VSTSPoshAccount: 35 | secure: edlf8+6ClMjqoBuBweBkxQ== 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Adam Driscoll 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ci/New-ModuleManifest.ps1: -------------------------------------------------------------------------------- 1 | $FunctionsToExport = @( 2 | 'New-VstsSession', 3 | 'Get-VstsProject', 4 | 'New-VstsProject', 5 | 'Remove-VstsProject', 6 | 'Wait-VstsProject', 7 | 'Get-VstsWorkItem', 8 | 'New-VstsWorkItem', 9 | 'Get-VstsWorkItemQuery', 10 | 'Get-VstsCodePolicyConfiguration', 11 | 'New-VstsCodePolicyConfiguration', 12 | 'Get-VstsGitRepository', 13 | 'New-VstsGitRepository', 14 | 'Remove-VstsGitRepository', 15 | 'ConvertTo-VstsGitRepository', 16 | 'New-VstsSession', 17 | 'Get-VstsProcess', 18 | 'Get-VstsBuild', 19 | 'Get-VstsBuildArtifact', 20 | 'New-VstsBuildDefinition', 21 | 'Get-VstsBuildDefinition', 22 | 'Get-VstsBuildQueue', 23 | 'Get-VstsBuildTag', 24 | 'New-VstsReleaseDefinition', 25 | 'Get-VstsRelease', 26 | 'Get-VstsReleaseDefinition' 27 | ) 28 | 29 | $NewModuleManifestParams = @{ 30 | ModuleVersion = $ENV:APPVEYOR_BUILD_VERSION 31 | Path = (Join-Path $PSScriptRoot '.\..\VSTS.psd1') 32 | Author = 'Adam Driscoll' 33 | Company = 'Adam Driscoll' 34 | Description = 'Visual Studio Team Services and Team Foundation Server PowerShell Integration' 35 | RootModule = 'VSTS.psm1' 36 | FunctionsToExport = $FunctionsToExport 37 | ProjectUri = 'https://github.com/adamdriscoll/vstsposh' 38 | Tags = @('VSTS', 'TFS', 'VisualStudioTeamServices', 'TeamFoundationServer', 'VSO') 39 | RequiredAssemblies = 'System.Web' 40 | } 41 | 42 | New-ModuleManifest @NewModuleManifestParams 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerShell Module for Accessing the Visual Studio Team Services (VSTS) REST API 2 | 3 | [Overview of integrating with Visual Studio Team Services](https://www.visualstudio.com/en-us/integrate/api/overview) 4 | 5 | ## Branches 6 | 7 | Branch | Build Status | Code Coverage | Protected 8 | --- | --- | --- | --- 9 | master | [![Master](https://ci.appveyor.com/api/projects/status/2fc84qwbsidtgvfq/branch/master?svg=true)](https://ci.appveyor.com/project/adamdriscoll/vstsposh/branch/master) | [![codecov](https://codecov.io/gh/adamdriscoll/VSTSPosh/branch/master/graph/badge.svg)](https://codecov.io/gh/adamdriscoll/VSTSPosh/branch/master) | Yes 10 | develop | [![Development](https://ci.appveyor.com/api/projects/status/2fc84qwbsidtgvfq/branch/develop?svg=true)](https://ci.appveyor.com/project/adamdriscoll/vstsposh/branch/develop) | [![codecov](https://codecov.io/gh/adamdriscoll/VSTSPosh/branch/develop/graph/badge.svg)](https://codecov.io/gh/adamdriscoll/VSTSPosh/branch/develop) | No 11 | 12 | ## Cmdlets 13 | 14 | - Session 15 | - New-VstsSession 16 | - Projects 17 | - Get-VstsProject 18 | - Wait-VstsProject 19 | - New-VstsProject 20 | - Remove-VstsProject 21 | - Get-VstsProcess 22 | - Work 23 | - Get-VstsWorkItem 24 | - New-VstsWorkItem 25 | - Get-VstsWorkItemQuery 26 | - Build 27 | - Get-VstsBuild 28 | - Get-VstsBuildDefinition 29 | - New-vstsBuild 30 | - Get-VstsBuildArtifacts 31 | - Get-VstsBuildTag 32 | - Code 33 | - Policy 34 | - Get-VstsCodePolicyConfiguration 35 | - New-VstsCodePolicyConfiguration 36 | - Git 37 | - New-VstsGitRepository 38 | - Get-VstsGitRepository 39 | - Remove-VstsGitRepository 40 | - ConvertTo-VstsGitRepository 41 | - Release 42 | - Get-VstsRelease 43 | - Get-VstsReleaseDefinition 44 | - New-VstsRelease 45 | -------------------------------------------------------------------------------- /Tests/WorkItems.tests.ps1: -------------------------------------------------------------------------------- 1 | $userName = $env:VSTSPoshUserName 2 | $token = $env:VSTSPoshToken 3 | $account = $env:VSTSPoshAccount 4 | 5 | function New-ProjectName 6 | { 7 | [Guid]::NewGuid().ToString().Replace('-', '').Substring(10) 8 | } 9 | 10 | $moduleRoot = Split-Path -Path $PSScriptRoot -Parent 11 | $modulePath = Join-Path -Path $moduleRoot -ChildPath 'VSTS.psm1' 12 | Import-Module -Name $modulePath -Force 13 | 14 | Describe 'Code' -Tags 'Unit' { 15 | InModuleScope -ModuleName VSTS { 16 | # All unit tests run in VSTS module scope 17 | 18 | } 19 | } 20 | 21 | Describe 'Work items' -Tags 'Integration' { 22 | BeforeAll { 23 | $projectName = New-ProjectName 24 | $session = New-VSTSSession -AccountName $account -User $userName -Token $token 25 | Write-Verbose -Verbose -Message ('Creating VSTS test project {0}' -f $projectName) 26 | New-VSTSProject -Session $session -Name $projectName 27 | Wait-VSTSProject -Session $session -Name $projectName -Exists -State 'WellFormed' -Attempts 50 -RetryIntervalSec 5 28 | } 29 | 30 | Context "Work item doesn't exist" { 31 | It 'Should create a new work item' { 32 | { $script:workItem = New-VstsWorkItem ` 33 | -Session $session ` 34 | -WorkItemType 'Task' ` 35 | -Project $projectName ` 36 | -PropertyHashtable @{ 37 | 'System.Title' = 'This is a test work item' 38 | 'System.Description' = 'Test' 39 | } ` 40 | -Verbose } | Should Not Throw 41 | $script:workItem.Fields.'System.Title' | Should Be 'This is a test work item' 42 | $script:workItem.Fields.'System.Description' | Should Be 'Test' 43 | } 44 | } 45 | 46 | AfterAll { 47 | Write-Verbose -Verbose -Message ('Deleting VSTS test project {0}' -f $projectName) 48 | Remove-VSTSProject -Session $session -Name $projectName 49 | } 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /VSTSPosh.pssproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | 2.0 6 | 6CAFC0C6-A428-4d30-A9F9-700E829FEA51 7 | Exe 8 | MyApplication 9 | MyApplication 10 | VSTSPosh 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug\ 17 | DEBUG;TRACE 18 | prompt 19 | 4 20 | 21 | 22 | pdbonly 23 | true 24 | bin\Release\ 25 | TRACE 26 | prompt 27 | 4 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /ci/Invoke-Tests.ps1: -------------------------------------------------------------------------------- 1 | if ($PSVersionTable.PSVersion.Major -ge 5) 2 | { 3 | Write-Verbose -Message 'Installing PSScriptAnalyzer' -Verbose 4 | $PSScriptAnalyzerModuleName = 'PSScriptAnalyzer' 5 | $PSScriptAnalyzerModule = Get-Module -Name $PSScriptAnalyzerModuleName -ListAvailable 6 | if (-not $PSScriptAnalyzerModule) 7 | { 8 | Install-PackageProvider -Name NuGet -Force 9 | Install-Module -Name $PSScriptAnalyzerModuleName -Scope CurrentUser -Force 10 | $PSScriptAnalyzerModule = Get-Module -Name $PSScriptAnalyzerModuleName -ListAvailable 11 | 12 | if ($PSScriptAnalyzerModule) 13 | { 14 | # Import the module if it is available 15 | $PSScriptAnalyzerModule | Import-Module -Force 16 | } 17 | else 18 | { 19 | # Module could not/would not be installed - so warn user that tests will fail. 20 | Write-Warning -Message ( @( 21 | "The 'PSScriptAnalyzer' module is not installed. " 22 | "The 'PowerShell modules scriptanalyzer' Pester test will fail." 23 | ) -Join '' ) 24 | } 25 | } 26 | } 27 | else 28 | { 29 | Write-Warning -Message ( @( 30 | "Skipping installation of 'PSScriptAnalyzer' since it requires " 31 | "PSVersion 5.0 or greater. Found PSVersion: $($PSVersionTable.PSVersion.Major)" 32 | ) -Join '' ) 33 | } 34 | 35 | # Always run unit tests first (test pyramid) 36 | $unitTestResultsPath = (Join-Path -Path $env:APPVEYOR_BUILD_FOLDER -ChildPath 'TestsResults.Unit.xml') 37 | $result = Invoke-Pester ` 38 | -Path (Join-Path -Path $env:APPVEYOR_BUILD_FOLDER -ChildPath 'Tests') ` 39 | -OutputFormat NUnitXml ` 40 | -OutputFile $unitTestResultsPath ` 41 | -PassThru ` 42 | -Tag Unit ` 43 | -CodeCoverage @( 44 | (Join-Path -Path $env:APPVEYOR_BUILD_FOLDER -ChildPath '*.psm1') 45 | (Join-Path -Path $env:APPVEYOR_BUILD_FOLDER -ChildPath 'lib\*.ps1') 46 | ) 47 | 48 | if ($env:APPVEYOR -eq $true) 49 | { 50 | Write-Verbose -Message 'Uploading Unit Test results to AppVeyor...' -Verbose 51 | (New-Object "System.Net.WebClient").UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $unitTestResultsPath) 52 | 53 | # Upload code coverage (only for unit tests) 54 | if ($result.CodeCoverage) 55 | { 56 | Write-Verbose -Message 'Uploading CodeCoverage to CodeCov.io...' -Verbose 57 | Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'CodeCovIo.psd1') 58 | $jsonPath = Export-CodeCovIoJson -CodeCoverage $result.CodeCoverage -repoRoot $env:APPVEYOR_BUILD_FOLDER 59 | Invoke-UploadCoveCoveIoReport -Path $jsonPath 60 | } 61 | else 62 | { 63 | Write-Warning -Message 'Could not create CodeCov.io report because pester results object did not contain a CodeCoverage object' 64 | } 65 | } 66 | 67 | if ($result.FailedCount -gt 0) 68 | { 69 | throw "$($result.FailedCount) unit tests failed." 70 | } 71 | 72 | # Run integration tests if not a PR or if run manually 73 | if ($null -eq $env:APPVEYOR_PULL_REQUEST_NUMBER) 74 | { 75 | $integrationTestResultsPath = (Join-Path -Path $env:APPVEYOR_BUILD_FOLDER -ChildPath 'TestsResults.Integration.xml') 76 | $result = Invoke-Pester ` 77 | -Path (Join-Path -Path $env:APPVEYOR_BUILD_FOLDER -ChildPath 'Tests') ` 78 | -OutputFormat NUnitXml ` 79 | -OutputFile $integrationTestResultsPath ` 80 | -PassThru ` 81 | -Tag Integration 82 | 83 | if ($env:APPVEYOR -eq $true) 84 | { 85 | Write-Verbose -Message 'Uploading Integration Test results to AppVeyor...' -Verbose 86 | (New-Object "System.Net.WebClient").UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $integrationTestResultsPath) 87 | } 88 | 89 | if ($result.FailedCount -gt 0) 90 | { 91 | throw "$($result.FailedCount) integration tests failed." 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | ## TODO: Comment the next line if you want to checkin your 137 | ## web deploy settings but do note that will include unencrypted 138 | ## passwords 139 | #*.pubxml 140 | 141 | *.publishproj 142 | 143 | # NuGet Packages 144 | *.nupkg 145 | # The packages folder can be ignored because of Package Restore 146 | **/packages/* 147 | # except build/, which is used as an MSBuild target. 148 | !**/packages/build/ 149 | # Uncomment if necessary however generally it will be regenerated when needed 150 | #!**/packages/repositories.config 151 | 152 | # Windows Azure Build Output 153 | csx/ 154 | *.build.csdef 155 | 156 | # Windows Store app package directory 157 | AppPackages/ 158 | 159 | # Visual Studio cache files 160 | # files ending in .cache can be ignored 161 | *.[Cc]ache 162 | # but keep track of directories ending in .cache 163 | !*.[Cc]ache/ 164 | 165 | # Others 166 | ClientBin/ 167 | [Ss]tyle[Cc]op.* 168 | ~$* 169 | *~ 170 | *.dbmdl 171 | *.dbproj.schemaview 172 | *.pfx 173 | *.publishsettings 174 | node_modules/ 175 | orleans.codegen.cs 176 | 177 | # RIA/Silverlight projects 178 | Generated_Code/ 179 | 180 | # Backup & report files from converting an old project file 181 | # to a newer Visual Studio version. Backup files are not needed, 182 | # because we have git ;-) 183 | _UpgradeReport_Files/ 184 | Backup*/ 185 | UpgradeLog*.XML 186 | UpgradeLog*.htm 187 | 188 | # SQL Server files 189 | *.mdf 190 | *.ldf 191 | 192 | # Business Intelligence projects 193 | *.rdl.data 194 | *.bim.layout 195 | *.bim_*.settings 196 | 197 | # Microsoft Fakes 198 | FakesAssemblies/ 199 | 200 | # Node.js Tools for Visual Studio 201 | .ntvs_analysis.dat 202 | 203 | # Visual Studio 6 build log 204 | *.plg 205 | 206 | # Visual Studio 6 workspace options file 207 | *.opt 208 | 209 | # LightSwitch generated files 210 | GeneratedArtifacts/ 211 | _Pvt_Extensions/ 212 | ModelManifest.xml 213 | 214 | # Test results 215 | testresults.*.xml 216 | -------------------------------------------------------------------------------- /ci/CodeCovIo.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'CodeCovIo' 3 | # 4 | # Generated by: Travis Plunk 5 | # 6 | # Generated on: 01/11/2017 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | # RootModule = '' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.0.0.0' 16 | 17 | # ID used to uniquely identify this module 18 | GUID = '5e90e236-83dd-40cc-9594-c49881b57dfc' 19 | 20 | # Author of this module 21 | Author = 'Microsoft Corporation' 22 | 23 | # Company or vendor of this module 24 | CompanyName = 'Microsoft Corporation' 25 | 26 | # Copyright statement for this module 27 | Copyright = '(c) 2017 Microsoft Corporation. All rights reserved.' 28 | 29 | # Description of the functionality provided by this module 30 | Description = 'This module is used to assist in Code Coverage generation. Developed for use in the DSC Resource Kit.' 31 | 32 | # Minimum version of the Windows PowerShell engine required by this module 33 | PowerShellVersion = '4.0' 34 | 35 | # Name of the Windows PowerShell host required by this module 36 | # PowerShellHostName = '' 37 | 38 | # Minimum version of the Windows PowerShell host required by this module 39 | # PowerShellHostVersion = '' 40 | 41 | # Minimum version of Microsoft .NET Framework required by this module 42 | # DotNetFrameworkVersion = '' 43 | 44 | # Minimum version of the common language runtime (CLR) required by this module 45 | # CLRVersion = '' 46 | 47 | # Processor architecture (None, X86, Amd64) required by this module 48 | # ProcessorArchitecture = '' 49 | 50 | # Modules that must be imported into the global environment prior to importing this module 51 | # RequiredModules = @() 52 | 53 | # Assemblies that must be loaded prior to importing this module 54 | # RequiredAssemblies = @() 55 | 56 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 57 | # ScriptsToProcess = @() 58 | 59 | # Type files (.ps1xml) to be loaded when importing this module 60 | # TypesToProcess = @() 61 | 62 | # Format files (.ps1xml) to be loaded when importing this module 63 | # FormatsToProcess = @() 64 | 65 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 66 | NestedModules = @( 67 | "CodeCovIo.psm1" 68 | ) 69 | 70 | # Functions to export from this module 71 | #FunctionsToExport = '*' 72 | 73 | # Cmdlets to export from this module 74 | CmdletsToExport = @( 75 | "Export-CodeCovIoJson", 76 | "Invoke-UploadCoveCoveIoReport" 77 | ) 78 | 79 | # Variables to export from this module 80 | #VariablesToExport = '*' 81 | 82 | # Aliases to export from this module 83 | #AliasesToExport = '*' 84 | 85 | # List of all modules packaged with this module 86 | # ModuleList = @() 87 | 88 | # List of all files packaged with this module 89 | # FileList = @() 90 | 91 | # HelpInfo URI of this module 92 | # HelpInfoURI = '' 93 | 94 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -prefix. 95 | # DefaultCommandPrefix = '' 96 | 97 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 98 | PrivateData = @{ 99 | 100 | PSData = @{ 101 | 102 | # Tags applied to this module. These help with module discovery in online galleries. 103 | Tags = @() 104 | 105 | # A URL to the license for this module. 106 | LicenseUri = 'https://github.com/PowerShell/DscResource.Tests/blob/master/LICENSE' 107 | 108 | # A URL to the main website for this project. 109 | ProjectUri = 'https://github.com/PowerShell/DscResource.Tests' 110 | 111 | # A URL to an icon representing this module. 112 | # IconUri = '' 113 | 114 | # ReleaseNotes of this module 115 | ReleaseNotes = '' 116 | 117 | } # End of PSData hashtable 118 | 119 | } # End of PrivateData hashtable 120 | } 121 | 122 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## Unreleased 4 | 5 | - Changelog.md: 6 | - Created 7 | - Readme.md: 8 | - Fixed Markdown rule violations. 9 | - Added missing cmdlets. 10 | - Updated branch badges for CodeCov.io to point to mainline 11 | fork. 12 | - Unit Tests: 13 | - Fixed PS Script Analyzer and added support for reporting on 14 | warning-level rules. Copied from Microsoft DSC Resource Kit 15 | test methodology. 16 | - Split the module into lib files to reduce the size of the main 17 | module. 18 | - Visual Studio Code Workspace settings: 19 | - Added to ensure style guidelines matched when using VSCode. 20 | - Improved AppVeyor build to get Pester from PSGallery instead 21 | of Chocolatey so that latest version is used. 22 | - Increased integration test scenarios/stories. 23 | - Added codecov.io support to report on code coverage. 24 | - Moved all functions for continuous integration into `ci` folder. 25 | - Get-VstsEndpointUri Cmdlet: 26 | - Added function to return the VSTS endpoint URI builder object. 27 | - Added unit tests. 28 | - Get-VstsQueryStringParametersFromBound Cmdlet: 29 | - Added function to support additional parameters and queries. 30 | - Added unit tests. 31 | - New-VstsSession Cmdlet: 32 | - Added documentation. 33 | - Style consistency cleanup. 34 | - Added CmdletBinding and other PowerShell best practice changes. 35 | - Added unit tests. 36 | - Added parameter sets for VSTS and TFS. 37 | - Invoke-VstsEndpoint Cmdlet: 38 | - Added documentation. 39 | - Added support for alternate endpoint names to support VSRM 40 | API endpoint. 41 | - Added support for extended query parameters to support 42 | parameters pre-pended with `$`, such as `top`. 43 | - Added CmdletBinding and other PowerShell best practice changes. 44 | - Get-VstsAuthorization Cmdlet: 45 | - Added documentation. 46 | - Added CmdletBinding and other PowerShell best practice changes. 47 | - Added unit tests. 48 | - Get-VstsProject Cmdlet: 49 | - Added documentation. 50 | - Style consistency cleanup. 51 | - Added CmdletBinding and other PowerShell best practice changes. 52 | - Added StateFilter parameter for querying on StateFilter. 53 | - Added Top and Skip parameter for limiting result set. 54 | - Wait-VSTSProject Cmdlet: 55 | - Added documentation. 56 | - Style consistency cleanup. 57 | - Added CmdletBinding and other PowerShell best practice changes. 58 | - Added RetryIntervalSec parameter to support controlling test 59 | frequency. 60 | - Added AccountName, User and Token parameters. 61 | - Added State parameter to enable waiting for a project to enter 62 | a specific state. 63 | - Refactored to improve verbose logging and edge case handling. 64 | - New-VSTSProject Cmdlet: 65 | - Added documentation. 66 | - Style consistency cleanup. 67 | - Added CmdletBinding and other PowerShell best practice changes. 68 | - Changed Wait parameter to wait for a project to enter the 69 | WellFormed state. 70 | - Remove-VSTSProject Cmdlet: 71 | - Added documentation. 72 | - Style consistency cleanup. 73 | - Added CmdletBinding and other PowerShell best practice changes. 74 | - Suppress output of REST API from being placed into pipeline. 75 | - Get-VstsProcess Cmdlet: 76 | - Added documentation. 77 | - Style consistency cleanup. 78 | - Added CmdletBinding and other PowerShell best practice changes. 79 | - Added Id parameter to allow querying a specific Id. 80 | - Added AccountName, User and Token parameters. 81 | - Get-VstsBuildArtifact Cmdlet: 82 | - Added documentation. 83 | - Style consistency cleanup. 84 | - Added CmdletBinding and other PowerShell best practice changes. 85 | - Get-VstsReleaseDefinition Cmdlet: 86 | - Added cmdlet to get a specific release definitions or all 87 | release definitions. 88 | - Get-VstsRelease Cmdlet: 89 | - Added cmdlet to get a list of releases by query or all 90 | releases. 91 | - New-VstsRelease Cmdlet: 92 | - Added cmdlet to create a new release. 93 | - Get-VstsCodePolicyConfiguration Cmdlet: 94 | - BREAKING: Renamed from Get-VstsCodePolicy to match actual purpose. 95 | - Added documentation. 96 | - Style consistency cleanup. 97 | - Added CmdletBinding and other PowerShell best practice changes. 98 | - Added Top and Skip parameter for limiting result set. 99 | - New-VstsCodePolicyConfiguration Cmdlet: 100 | - BREAKING: Renamed from New-VstsCodePolicy to match actual purpose. 101 | - Added documentation. 102 | - Style consistency cleanup. 103 | - Added CmdletBinding and other PowerShell best practice changes. 104 | - Get-VstsWorkItem Cmdlet: 105 | - Added documentation. 106 | - Style consistency cleanup. 107 | - Added CmdletBinding and other PowerShell best practice changes. 108 | - Added additional query options to improve work item lookup. 109 | - New-VstsWorkItem Cmdlet: 110 | - Added documentation. 111 | - Style consistency cleanup. 112 | - Added CmdletBinding and other PowerShell best practice changes. 113 | - Fixed bugs that prevented cmdlet from creating work item. 114 | - Test-Guid Cmdlet: 115 | - Added documentation. 116 | - Style consistency cleanup. 117 | - Added CmdletBinding and other PowerShell best practice changes. 118 | - Added unit tests. 119 | - Changed Input parameter name to Guid because Input is a reserved 120 | word. 121 | - Get-VstsGitRepository Cmdlet: 122 | - Added documentation. 123 | - Style consistency cleanup. 124 | - Added CmdletBinding and other PowerShell best practice changes. 125 | - Added repository parameter to filter on repository id or name. 126 | - Unit tests completed. 127 | - New-VstsGitRepository Cmdlet: 128 | - Added documentation. 129 | - Style consistency cleanup. 130 | - Added CmdletBinding and other PowerShell best practice changes. 131 | - Remove-VstsGitRepository Cmdlet: 132 | - Added cmdlet to delete repositories. 133 | - Unit tests completed. 134 | - Get-VstsBuildTag Cmdlet: 135 | - Added cmdlet to get build tags from a build or entire project. 136 | - Get-VstsBuildDefinition Cmdlet: 137 | - Added documentation. 138 | - Style consistency cleanup. 139 | - Added CmdletBinding and other PowerShell best practice changes. 140 | - Unit tests completed. 141 | - New-VstsBuildDefinition Cmdlet: 142 | - Added documentation. 143 | - Style consistency cleanup. 144 | - Added CmdletBinding and other PowerShell best practice changes. 145 | - Unit tests completed. 146 | - Added all cmdlets to manifest creation script. 147 | 148 | ## 1.0.0.0 149 | 150 | - Initial versions 151 | -------------------------------------------------------------------------------- /lib/Workitems.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Get work items from VSTS. 4 | 5 | .PARAMETER AccountName 6 | The name of the VSTS account to use. 7 | 8 | .PARAMETER User 9 | This user name to authenticate to VSTS. 10 | 11 | .PARAMETER Token 12 | This personal access token to use to authenticate to VSTS. 13 | 14 | .PARAMETER Session 15 | The session object created by New-VstsSession. 16 | 17 | .PARAMETER Id 18 | The Id of a single work item to lookup. 19 | 20 | .PARAMETER Ids 21 | The Ids to lookup for multiple work items. 22 | 23 | .PARAMETER AsOf 24 | Gets the work items as they existed at this time. 25 | 26 | The date format must be: 27 | 2014-12-29T20:49:22.103Z 28 | 29 | .PARAMETER Expand 30 | Gets work item relationships (work item links, hyperlinks, file attachments, etc.). 31 | #> 32 | function Get-VstsWorkItem 33 | { 34 | [CmdletBinding(DefaultParameterSetName = 'Account')] 35 | param 36 | ( 37 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 38 | [String] $AccountName, 39 | 40 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 41 | [String] $User, 42 | 43 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 44 | [String] $Token, 45 | 46 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 47 | $Session, 48 | 49 | [Parameter()] 50 | [String] $Id, 51 | 52 | [Parameter()] 53 | [String[]] $Ids, 54 | 55 | [Parameter()] 56 | [String] $AsOf, 57 | 58 | [Parameter()] 59 | [ValidateSet('All', 'Relations', 'None')] 60 | [String] $Expand 61 | ) 62 | 63 | if ($PSCmdlet.ParameterSetName -eq 'Account') 64 | { 65 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 66 | } 67 | 68 | $path = 'wit/workitems' 69 | $additionalInvokeParameters = @{} 70 | 71 | if ($PSBoundParameters.ContainsKey('Id')) 72 | { 73 | $path = ('{0}/{1}' -f $path, $Id) 74 | } 75 | else 76 | { 77 | # Convert the Ids into a comma delimited string 78 | $PSBoundParameters['Ids'] = ($PSBoundParameters['Ids'] -join ',') 79 | 80 | $additionalInvokeParameters = @{ 81 | QueryStringParameters = Get-VstsQueryStringParametersFromBound ` 82 | -BoundParameters $PSBoundParameters ` 83 | -ParameterList 'ids', 'asOf' 84 | QueryStringExtParameters = Get-VstsQueryStringParametersFromBound ` 85 | -BoundParameters $PSBoundParameters ` 86 | -ParameterList 'expand' 87 | } 88 | } 89 | 90 | $result = Invoke-VstsEndpoint ` 91 | -Session $Session ` 92 | -Project $Project ` 93 | -Path $path ` 94 | @additionalInvokeParameters 95 | 96 | return $result.Value 97 | } 98 | 99 | <# 100 | .SYNOPSIS 101 | Create new work items in VSTS 102 | 103 | .PARAMETER AccountName 104 | The name of the VSTS account to use. 105 | 106 | .PARAMETER User 107 | This user name to authenticate to VSTS. 108 | 109 | .PARAMETER Token 110 | This personal access token to use to authenticate to VSTS. 111 | 112 | .PARAMETER Session 113 | The session object created by New-VstsSession. 114 | 115 | .PARAMETER Project 116 | The name of the project to get the policy configuration from. 117 | 118 | .PARAMETER WorkItemType 119 | The work item type to create. 120 | 121 | .PARAMETER PropertyHashtable 122 | A hash table containing the properties to set for the new 123 | work item. 124 | 125 | .EXAMPLE 126 | > 127 | $vstsSession = New-VSTSSession ` 128 | -AccountName 'myvstsaccount' ` 129 | -User 'joe.bloggs@fabrikam.com' ` 130 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 131 | 132 | New-VstsWorkItem ` 133 | -Session $vstsSession ` 134 | -Project 'FabrikamFiber' ` 135 | -WorkItemType 'User Story' ` 136 | -PropertyHashtable @{ 'System.Title' = 'Add support for creating new work item' } 137 | 138 | Creates a new user story in FabrikamFiber project with the 139 | title 'Add support for creating new work item' 140 | #> 141 | function New-VstsWorkItem 142 | { 143 | [CmdletBinding(DefaultParameterSetName = 'Account')] 144 | param 145 | ( 146 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 147 | [String] $AccountName, 148 | 149 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 150 | [String] $User, 151 | 152 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 153 | [String] $Token, 154 | 155 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 156 | $Session, 157 | 158 | [Parameter(Mandatory = $True)] 159 | [String] $Project, 160 | 161 | [Parameter(Mandatory = $True)] 162 | [string] $WorkItemType, 163 | 164 | [Parameter(Mandatory = $True)] 165 | [Hashtable] $PropertyHashtable 166 | ) 167 | 168 | if ($PSCmdlet.ParameterSetName -eq 'Account') 169 | { 170 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 171 | } 172 | 173 | $path = ('wit/workitems/${0}' -f $WorkItemType) 174 | 175 | $fields = foreach ($kvp in $PropertyHashtable.GetEnumerator()) 176 | { 177 | [PSCustomObject] @{ 178 | op = 'add' 179 | path = ('/fields/{0}' -f $kvp.Key) 180 | value = $kvp.value 181 | } 182 | } 183 | 184 | $body = $fields | ConvertTo-Json 185 | 186 | if ($fields.Count -lt 2) 187 | { 188 | $body = ('[{0}]' -f $body) 189 | } 190 | 191 | $result = Invoke-VstsEndpoint ` 192 | -Session $Session ` 193 | -Project $Project ` 194 | -Path $path ` 195 | -Method 'PATCH' ` 196 | -Body $body 197 | 198 | return $result.Value 199 | } 200 | 201 | <# 202 | .SYNOPSIS 203 | Returns a list of work item queries from the specified folder. 204 | 205 | .PARAMETER AccountName 206 | The name of the VSTS account to use. 207 | 208 | .PARAMETER User 209 | This user name to authenticate to VSTS. 210 | 211 | .PARAMETER Token 212 | This personal access token to use to authenticate to VSTS. 213 | 214 | .PARAMETER Session 215 | The session object created by New-VstsSession. 216 | #> 217 | function Get-VstsWorkItemQuery 218 | { 219 | [CmdletBinding(DefaultParameterSetName = 'Account')] 220 | param 221 | ( 222 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 223 | [String] $AccountName, 224 | 225 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 226 | [String] $User, 227 | 228 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 229 | [String] $Token, 230 | 231 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 232 | $Session, 233 | 234 | [Parameter(Mandatory = $true)] 235 | [String] $Project 236 | ) 237 | 238 | if ($PSCmdlet.ParameterSetName -eq 'Account') 239 | { 240 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 241 | } 242 | 243 | $path = 'wit/queries' 244 | 245 | $result = Invoke-VstsEndpoint ` 246 | -Session $Session ` 247 | -Project $Project ` 248 | -Path $path ` 249 | -QueryStringParameters @{ depth = 1 } 250 | 251 | foreach ($value in $result.Value) 252 | { 253 | if ($Value.isFolder -and $Value.hasChildren) 254 | { 255 | Write-Verbose "$Value.Name" 256 | foreach ($child in $value.Children) 257 | { 258 | if (-not $child.isFolder) 259 | { 260 | $child 261 | } 262 | } 263 | } 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /Tests/Projects.tests.ps1: -------------------------------------------------------------------------------- 1 | $userName = $env:VSTSPoshUserName 2 | $token = $env:VSTSPoshToken 3 | $account = $env:VSTSPoshAccount 4 | 5 | function New-ProjectName 6 | { 7 | [Guid]::NewGuid().ToString().Replace('-', '').Substring(10) 8 | } 9 | 10 | $moduleRoot = Split-Path -Path $PSScriptRoot -Parent 11 | $modulePath = Join-Path -Path $moduleRoot -ChildPath 'VSTS.psm1' 12 | Import-Module -Name $modulePath -Force 13 | 14 | Describe 'Code' -Tags 'Unit' { 15 | InModuleScope -ModuleName VSTS { 16 | # All unit tests run in VSTS module scope 17 | 18 | } 19 | } 20 | 21 | Describe 'Projects' -Tags 'Integration' { 22 | $Script:Session = New-VSTSSession -AccountName $account -User $userName -Token $token 23 | 24 | Context "Project doesn't exist" { 25 | Context 'Using session object' { 26 | Context 'Using no parameters' { 27 | $projectName = New-ProjectName 28 | 29 | $parameterDetails = @{ 30 | Session = $Script:Session 31 | Name = $projectName 32 | } 33 | 34 | It "Should create a new project '$projectName'" { 35 | { New-VSTSProject @parameterDetails -Verbose } | Should Not Throw 36 | } 37 | 38 | It "Should wait for new project '$projectName' to be WellFormed" { 39 | { 40 | Wait-VSTSProject @parameterDetails ` 41 | -Exists ` 42 | -State 'WellFormed' ` 43 | -Attempts 50 ` 44 | -RetryIntervalSec 5 45 | } | Should Not Throw 46 | } 47 | 48 | It "Should return the new project '$projectName'" { 49 | { $script:Result = Get-VSTSProject @parameterDetails -Verbose } | Should Not Throw 50 | $script:Result.Name | Should BeExactly $projectName 51 | } 52 | 53 | It "Should delete the new project '$projectName'" { 54 | { Remove-VSTSProject @parameterDetails -Verbose } | Should Not Throw 55 | } 56 | } 57 | 58 | Context "Using template name 'Scrum'" { 59 | $projectName = New-ProjectName 60 | 61 | $parameterDetails = @{ 62 | Session = $Script:Session 63 | Name = $projectName 64 | } 65 | 66 | It "Should create a new project '$projectName'" { 67 | { New-VSTSProject @parameterDetails -TemplateTypeName 'Scrum' -Verbose } | Should Not Throw 68 | } 69 | 70 | It "Should wait for new project '$projectName' to be WellFormed" { 71 | { 72 | Wait-VSTSProject @parameterDetails ` 73 | -Exists ` 74 | -State 'WellFormed' ` 75 | -Attempts 50 ` 76 | -RetryIntervalSec 5 77 | } | Should Not Throw 78 | } 79 | 80 | It "Should return the new project '$projectName'" { 81 | { $script:Result = Get-VSTSProject @parameterDetails -Verbose } | Should Not Throw 82 | $script:Result.Name | Should BeExactly $projectName 83 | } 84 | 85 | It "Should delete the new project '$projectName'" { 86 | { Remove-VSTSProject @parameterDetails -Verbose } | Should Not Throw 87 | } 88 | } 89 | } 90 | 91 | Context 'Using account details' { 92 | Context 'Using no parameters' { 93 | $projectName = New-ProjectName 94 | 95 | $parameterDetails = @{ 96 | AccountName = $account 97 | User = $userName 98 | Token = $Token 99 | Name = $projectName 100 | } 101 | 102 | It "Should create a new project '$projectName'" { 103 | { New-VSTSProject @parameterDetails -Verbose } | Should Not Throw 104 | } 105 | 106 | It "Should wait for new project '$projectName' to be WellFormed" { 107 | { 108 | Wait-VSTSProject @parameterDetails ` 109 | -Exists ` 110 | -State 'WellFormed' ` 111 | -Attempts 50 ` 112 | -RetryIntervalSec 5 113 | } | Should Not Throw 114 | } 115 | 116 | It "Should return the new project '$projectName'" { 117 | { $script:Result = Get-VSTSProject @parameterDetails -Verbose } | Should Not Throw 118 | $script:Result.Name | Should BeExactly $projectName 119 | } 120 | 121 | It "Should delete the new project '$projectName'" { 122 | { Remove-VSTSProject @parameterDetails -Verbose } | Should Not Throw 123 | } 124 | } 125 | 126 | Context "Using template name 'Scrum'" { 127 | $projectName = New-ProjectName 128 | 129 | $parameterDetails = @{ 130 | AccountName = $account 131 | User = $userName 132 | Token = $Token 133 | Name = $projectName 134 | } 135 | 136 | It "Should create a new project '$projectName'" { 137 | { New-VSTSProject @parameterDetails -TemplateTypeName 'Scrum' -Verbose } | Should Not Throw 138 | } 139 | 140 | It "Should wait for new project '$projectName' to be WellFormed" { 141 | { 142 | Wait-VSTSProject @parameterDetails ` 143 | -Exists ` 144 | -State 'WellFormed' ` 145 | -Attempts 50 ` 146 | -RetryIntervalSec 5 147 | } | Should Not Throw 148 | } 149 | 150 | It "Should return the new project '$projectName'" { 151 | { $script:Result = Get-VSTSProject @parameterDetails -Verbose } | Should Not Throw 152 | $script:Result.Name | Should BeExactly $projectName 153 | } 154 | 155 | It "Should delete the new project '$projectName'" { 156 | { Remove-VSTSProject @parameterDetails -Verbose } | Should Not Throw 157 | } 158 | } 159 | 160 | } 161 | } 162 | 163 | Context 'Process' { 164 | Context 'Using session object' { 165 | $parameterDetails = @{ 166 | Session = $Script:Session 167 | Verbose = $True 168 | } 169 | 170 | It 'Should returns default process templates' { 171 | { $script:Result = Get-VstsProcess @parameterDetails } | Should Not Throw 172 | $script:Result | Where-Object -Property Name -EQ 'Agile' | Should Not BeNullOrEmpty 173 | $script:Result | Where-Object -Property Name -EQ 'CMMI' | Should Not BeNullOrEmpty 174 | $script:Result | Where-Object -Property Name -EQ 'Scrum' | Should Not BeNullOrEmpty 175 | } 176 | } 177 | 178 | Context 'Using account details' { 179 | $parameterDetails = @{ 180 | AccountName = $account 181 | User = $userName 182 | Token = $Token 183 | Verbose = $True 184 | } 185 | 186 | It 'Should returns default process templates' { 187 | { $script:Result = Get-VstsProcess @parameterDetails } | Should Not Throw 188 | $script:Result | Where-Object -Property Name -EQ 'Agile' | Should Not BeNullOrEmpty 189 | $script:Result | Where-Object -Property Name -EQ 'CMMI' | Should Not BeNullOrEmpty 190 | $script:Result | Where-Object -Property Name -EQ 'Scrum' | Should Not BeNullOrEmpty 191 | } 192 | } 193 | 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /ci/CodeCovIo.psm1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Updates a hash table with the Unique file lines 4 | Structure: 5 | RootTable.[FileKey].[SubTable].[Line] 6 | 7 | .PARAMETER FileLine 8 | The table to update 9 | 10 | .PARAMETER Command 11 | The list of Command from pester to update the table based on 12 | 13 | .PARAMETER RepoRoot 14 | The path to the root of the repo. This part of the path will not be included in the report. Needed to normalize all the reports. 15 | 16 | .PARAMETER TableName 17 | The path of the file to write the report to. 18 | #> 19 | function Add-UniqueFileLineToTable 20 | { 21 | [CmdletBinding()] 22 | param 23 | ( 24 | [Parameter(Mandatory = $true)] 25 | [HashTable] 26 | $FileLine, 27 | 28 | [Parameter(Mandatory = $true)] 29 | [Object] 30 | $Command, 31 | 32 | [Parameter(Mandatory = $true)] 33 | [String] 34 | $RepoRoot, 35 | 36 | [Parameter(Mandatory = $true)] 37 | [String] 38 | $TableName 39 | ) 40 | 41 | # file paths need to be relative to repo root when querying GIT 42 | Push-Location -LiteralPath $RepoRoot 43 | try { 44 | Write-Verbose -Message "running git ls-files" -Verbose 45 | 46 | # Get the list of files as Git sees them 47 | $fileKeys = & git.exe ls-files 48 | 49 | # Populate the sub-table 50 | foreach ($command in $Command) 51 | { 52 | #Find the file as Git sees it 53 | $file = $command.File 54 | $fileKey = $file.replace($RepoRoot,'').TrimStart('\').replace('\','/') 55 | $fileKey = $fileKeys.where{$_ -like $fileKey} 56 | 57 | if ($null -eq $fileKey) 58 | { 59 | Write-Warning -Message "Unexpected error filekey was null" 60 | continue 61 | } 62 | elseif ($fileKey.Count -ne 1) 63 | { 64 | Write-Warning -Message "Unexpected error, more than one git file matched file ($file): $($fileKey -join ', ')" 65 | continue 66 | } 67 | 68 | $fileKey = $fileKey | Select-Object -First 1 69 | 70 | if (!$FileLine.ContainsKey($fileKey)) 71 | { 72 | $FileLine.add($fileKey, @{ $TableName = @{}}) 73 | } 74 | 75 | if (!$FileLine.$fileKey.ContainsKey($TableName)) 76 | { 77 | $FileLine.$fileKey.Add($TableName,@{}) 78 | } 79 | 80 | $lines = $FileLine.($fileKey).$TableName 81 | $lineKey = $($command.line) 82 | if (!$lines.ContainsKey($lineKey)) 83 | { 84 | $lines.Add($lineKey,1) 85 | } 86 | else 87 | { 88 | $lines.$lineKey ++ 89 | } 90 | } 91 | } 92 | finally 93 | { 94 | Pop-Location 95 | } 96 | } 97 | 98 | <# 99 | .SYNOPSIS 100 | Tests if the specified property is a CodeCoverage object 101 | For use in a ValidateScript attribute 102 | 103 | .PARAMETER CodeCoverage 104 | The CodeCoverage property of the output of Invoke-Pester with the -PassThru and -CodeCoverage options 105 | 106 | #> 107 | function Test-CodeCoverage 108 | { 109 | [CmdletBinding()] 110 | param( 111 | [Parameter(Mandatory = $true)] 112 | [Object] 113 | $CodeCoverage 114 | ) 115 | 116 | if (!($CodeCoverage | Get-Member -Name MissedCommands)) 117 | { 118 | throw 'Must be a Pester CodeCoverage object' 119 | } 120 | 121 | return $true 122 | } 123 | 124 | <# 125 | .SYNOPSIS 126 | Exports a Pester CodeCoverage report as a CodeCov.io json report 127 | 128 | .PARAMETER CodeCoverage 129 | The CodeCoverage property of the output of Invoke-Pester with the -PassThru and -CodeCoverage options 130 | 131 | .PARAMETER RepoRoot 132 | The path to the root of the repo. This part of the path will not be included in the report. Needed to normalize all the reports. 133 | 134 | .PARAMETER Path 135 | The path of the file to write the report to. 136 | #> 137 | function Export-CodeCovIoJson 138 | { 139 | [CmdletBinding()] 140 | param( 141 | [Parameter(Mandatory = $true)] 142 | [ValidateScript({Test-CodeCoverage -CodeCoverage $_})] 143 | [Object] 144 | $CodeCoverage, 145 | 146 | [Parameter(Mandatory = $true)] 147 | [String] 148 | $RepoRoot, 149 | 150 | [Parameter()] 151 | [ValidateNotNullOrEmpty()] 152 | [String] 153 | $Path = (Join-Path -Path $env:TEMP -ChildPath 'codeCov.json') 154 | ) 155 | 156 | Write-Verbose -Message "RepoRoot: $RepoRoot" 157 | 158 | # Get a list of all unique files 159 | $files = @() 160 | foreach ($file in ($CodeCoverage.MissedCommands | Select-Object -ExpandProperty File -Unique)) 161 | { 162 | if ($files -notcontains $file) 163 | { 164 | $files += $file 165 | } 166 | } 167 | 168 | foreach ($file in ($CodeCoverage.HitCommands | Select-Object -ExpandProperty File -Unique)) 169 | { 170 | if ($files -notcontains $file) 171 | { 172 | $files += $file 173 | } 174 | } 175 | 176 | # A table of the file key then a sub-tables of `misses` and `hits` lines. 177 | $FileLine = @{} 178 | 179 | # define common parameters 180 | $addUniqueFileLineParams= @{ 181 | FileLine = $FileLine 182 | RepoRoo = $RepoRoot 183 | } 184 | 185 | <# 186 | Basically indexing all the hit and miss lines by file and line. 187 | Populate the misses sub-table 188 | #> 189 | Add-UniqueFileLineToTable -Command $CodeCoverage.MissedCommands -TableName 'misses' @addUniqueFileLineParams 190 | 191 | # Populate the hits sub-table 192 | Add-UniqueFileLineToTable -Command $CodeCoverage.HitCommands -TableName 'hits' @addUniqueFileLineParams 193 | 194 | # Create the results structure 195 | $resultLineData = @{} 196 | $resultMessages = @{} 197 | $result = @{ 198 | coverage = $resultLineData 199 | messages = $resultMessages 200 | } 201 | 202 | foreach ($file in $FileLine.Keys) 203 | { 204 | $hit = 0 205 | $partial = 0 206 | $missed = 0 207 | Write-Verbose -Message "summarizing for file: $file" 208 | 209 | # Get the hits, if they exist 210 | $hits = @{} 211 | if ($FileLine.$file.ContainsKey('hits')) 212 | { 213 | $hits = $FileLine.$file.hits 214 | } 215 | 216 | # Get the misses, if they exist 217 | $misses = @{} 218 | if ($FileLine.$file.ContainsKey('misses')) 219 | { 220 | $misses = $FileLine.$file.misses 221 | } 222 | 223 | Write-Verbose -Message "fileKeys: $($FileLine.$file.Keys)" 224 | $max = $hits.Keys | Sort-Object -Descending | Select-Object -First 1 225 | $maxMissLine = $misses.Keys | Sort-Object -Descending | Select-Object -First 1 226 | 227 | <# 228 | if max missed line is greater than maxed hit line 229 | used max missed line as the max line 230 | #> 231 | if ($maxMissLine -gt $max) 232 | { 233 | $max = $maxMissLine 234 | } 235 | 236 | $lineData = @() 237 | $messages = @{} 238 | 239 | <# 240 | produce the results 241 | start at line 0 per codecov doc 242 | #> 243 | for ($lineNumber = 0; $lineNumber -le $max; $lineNumber++) 244 | { 245 | $hitInfo = $null 246 | $missInfo = $null 247 | switch ($true) 248 | { 249 | # Hit 250 | ($hits.ContainsKey($lineNumber) -and ! $misses.ContainsKey($lineNumber)) 251 | { 252 | Write-Verbose -Message "Got code coverage hit at $lineNumber" 253 | $lineData += "$($hits.$lineNumber)" 254 | } 255 | 256 | # Miss 257 | ($misses.ContainsKey($lineNumber) -and ! $hits.ContainsKey($lineNumber)) 258 | { 259 | Write-Verbose -Message "Got code coverage miss at $lineNumber" 260 | $lineData += '0' 261 | } 262 | 263 | # Partial Hit 264 | ($misses.ContainsKey($lineNumber) -and $hits.ContainsKey($lineNumber)) 265 | { 266 | Write-Verbose -Message "Got code coverage partial at $lineNumber" 267 | 268 | $missInfo = $misses.$lineNumber 269 | $hitInfo = $hits.$lineNumber 270 | $lineData += "$hitInfo/$($hitInfo+$missInfo)" 271 | } 272 | 273 | # Non-Code Line 274 | (!$misses.ContainsKey($lineNumber) -and !$hits.ContainsKey($lineNumber)) 275 | { 276 | Write-Verbose -Message "Got non-code at $lineNumber" 277 | 278 | <# 279 | If I put an actual null in an array ConvertTo-Json just leaves it out 280 | I'll put this string in and clean it up later. 281 | #> 282 | $lineData += '!null!' 283 | } 284 | 285 | default 286 | { 287 | throw "Unexpected error occured generating codeCov.io report for $file at line $lineNumber with hits: $($hits.ContainsKey($lineNumber)) and misses: $($misses.ContainsKey($lineNumber))" 288 | } 289 | } 290 | } 291 | 292 | $resultLineData.Add($file,$lineData) 293 | $resultMessages.add($file,$messages) 294 | } 295 | 296 | $commitOutput = @(&git.exe log -1 --pretty=format:%H) 297 | $commit = $commitOutput[0] 298 | 299 | Write-Verbose -Message "Branch: $Branch" 300 | 301 | $json = $result | ConvertTo-Json 302 | $json = $json.Replace('"!null!"','null') 303 | 304 | $json | Out-File -Encoding ascii -LiteralPath $Path -Force 305 | return $Path 306 | } 307 | 308 | <# 309 | .SYNOPSIS 310 | Uploads a CodeCov.io code coverage report 311 | 312 | .PARAMETER Path 313 | The path to the code coverage report (gcov not supported) 314 | #> 315 | function Invoke-UploadCoveCoveIoReport 316 | { 317 | [CmdletBinding()] 318 | param 319 | ( 320 | [Parameter(Mandatory = $true)] 321 | [String] 322 | $Path 323 | ) 324 | 325 | $resolvedResultFile = (Resolve-Path -Path $Path).ProviderPath 326 | 327 | if ($env:APPVEYOR_REPO_BRANCH) 328 | { 329 | Push-AppVeyorArtifact $resolvedResultFile 330 | } 331 | 332 | # Set the location of Python, install the pip and get the CodeCov script, and upload the code coverage report to CodeCov 333 | $ENV:PATH = 'C:\\Python34;C:\\Python34\\Scripts;' + $ENV:PATH 334 | $null = python -m pip install --upgrade pip 335 | $null = pip install git+git://github.com/codecov/codecov-python.git 336 | $uploadResults = codecov -f $resolvedResultFile -X gcov 337 | 338 | if ($env:APPVEYOR_REPO_BRANCH) 339 | { 340 | $logPath = (Join-Path -Path $env:TEMP -ChildPath 'codeCovUpload.log') 341 | $uploadResults | Out-File -Encoding ascii -LiteralPath $logPath -Force 342 | $resolvedLogPath = (Resolve-Path -Path $logPath).ProviderPath 343 | Push-AppVeyorArtifact $resolvedLogPath 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /VSTS.psm1: -------------------------------------------------------------------------------- 1 | # System.Web is not always loaded by default, so ensure it is loaded. 2 | Add-Type -AssemblyName System.Web 3 | 4 | # Import all the lib files 5 | $moduleRoot = Split-Path ` 6 | -Path $MyInvocation.MyCommand.Path ` 7 | -Parent 8 | 9 | $libs = Get-ChildItem ` 10 | -Path (Join-Path -Path $moduleRoot -ChildPath 'lib') ` 11 | -Include '*.ps1' ` 12 | -Recurse 13 | $libs.Foreach( 14 | { 15 | Write-Verbose -Message ('Importing the lib file {0}' -f $_.Fullname) 16 | . $_.Fullname 17 | } 18 | ) 19 | 20 | <# 21 | .SYNOPSIS 22 | Create a new VSTS session object that needs to be passed 23 | to other VSTS module calls to provide connection 24 | information. It can be used to connect to VSTS or TFS 25 | APIs. 26 | 27 | .PARAMETER AccountName 28 | The name of the VSTS account to use. Not required for TFS 29 | sessions. 30 | 31 | .PARAMETER User 32 | This user name to authenticate to VSTS or TFS. 33 | 34 | .PARAMETER Token 35 | This personal access token to use to authenticate to VSTS 36 | or TFS. 37 | 38 | .PARAMETER Collection 39 | This collection to use. This defaults to 40 | 'DefaultCollection'. 41 | 42 | .PARAMETER Server 43 | The name of the VSTS or TFS Server to connect to. 44 | For VSTS this will be 'visualstudio.com', but for TFS 45 | this should be set to the TFS server. The default value 46 | if this is not specified is 'visualstudio.com'. 47 | 48 | .PARAMETER HTTPS 49 | Use HTTP or HTTPS to connect to the server. 50 | Defaults to HTTPS. 51 | 52 | .OUTPUTS 53 | VSTS Session Object. 54 | #> 55 | function New-VstsSession 56 | { 57 | [CmdletBinding(DefaultParameterSetName = 'VSTS')] 58 | [OutputType([PSCustomObject])] 59 | param 60 | ( 61 | [Parameter(Mandatory = $true, ParameterSetName = 'VSTS')] 62 | [ValidateNotNullOrEmpty()] 63 | [String] $AccountName, 64 | 65 | [Parameter(Mandatory = $true)] 66 | [ValidateNotNullOrEmpty()] 67 | [String] $User, 68 | 69 | [Parameter(Mandatory = $true)] 70 | [ValidateNotNullOrEmpty()] 71 | [String] $Token, 72 | 73 | [Parameter()] 74 | [ValidateNotNullOrEmpty()] 75 | [String] $Collection = 'DefaultCollection', 76 | 77 | [Parameter(Mandatory = $true, ParameterSetName = 'TFS')] 78 | [ValidateNotNullOrEmpty()] 79 | [String] $Server, 80 | 81 | [Parameter()] 82 | [ValidateSet('HTTP', 'HTTPS')] 83 | [String] $Scheme = 'HTTPS' 84 | ) 85 | 86 | if ($PSCmdlet.ParameterSetName -eq 'VSTS') 87 | { 88 | $Server = 'visualstudio.com' 89 | } 90 | 91 | [PSCustomObject] @{ 92 | AccountName = $AccountName 93 | User = $User 94 | Token = $Token 95 | Collection = $Collection 96 | Server = $Server 97 | Scheme = $Scheme 98 | } 99 | } 100 | 101 | <# 102 | .SYNOPSIS 103 | Helper function that takes an array of bound 104 | parameters passed to the calling function 105 | and an array of parameter names and creates a hash 106 | table containing each parameter that appears in 107 | the Bound Parameters and in the Parameters 108 | List. 109 | 110 | .PARAMETER BoundParameters 111 | This is the content of the PSBoundParameters from 112 | the calling function. 113 | 114 | .PARAMETER ParameterList 115 | This is the list of parameters to extract from the 116 | bound parameters list. 117 | 118 | .OUTPUTS 119 | Hashtable containing all parameters from 120 | BoundParameters that also appear in ParameterList. 121 | #> 122 | function Get-VstsQueryStringParametersFromBound 123 | { 124 | [CmdletBinding()] 125 | [OutputType([Hashtable])] 126 | param 127 | ( 128 | [Parameter(Mandatory = $true)] 129 | $BoundParameters, 130 | 131 | [Parameter(Mandatory = $true)] 132 | [Array] $ParameterList 133 | ) 134 | 135 | $result = @{} 136 | foreach ($parameter in $ParameterList) 137 | { 138 | if ($BoundParameters.ContainsKey($parameter)) 139 | { 140 | $result += @{ $parameter = $BoundParameters[$parameter] } 141 | } 142 | } 143 | return $result 144 | } 145 | 146 | <# 147 | .SYNOPSIS 148 | Assembles a VSTS or TFS endpoint URI object 149 | to be used to connect to a VSTS or TFS endpoint. 150 | 151 | .PARAMETER Session 152 | The session object created by New-VstsSession. 153 | 154 | .PARAMETER EndpointName 155 | Set an alternate VSTS endpoint to call. 156 | This is required by API calls for to preview APIs that are not 157 | yet available on the primary endpoint. 158 | #> 159 | function Get-VstsEndpointUri 160 | { 161 | [CmdletBinding()] 162 | [OutputType([System.UriBuilder])] 163 | param 164 | ( 165 | [Parameter(Mandatory = $true)] 166 | $Session, 167 | 168 | [Parameter()] 169 | [String] $EndpointName 170 | ) 171 | 172 | if ([String]::IsNullOrEmpty($Session.AccountName)) 173 | { 174 | $argumentList = ('{0}://{1}' -f $Session.Scheme, $Session.Server) 175 | } 176 | else 177 | { 178 | if ([String]::IsNullOrEmpty($EndpointName)) 179 | { 180 | $argumentList = ('{0}://{1}.visualstudio.com' -f $Session.Scheme, $Session.AccountName) 181 | } 182 | else 183 | { 184 | $argumentList = ('{0}://{1}.{2}.visualstudio.com' -f $Session.Scheme, $Session.AccountName, $EndpointName) 185 | } 186 | } 187 | 188 | $uriBuilder = New-Object ` 189 | -TypeName System.UriBuilder ` 190 | -ArgumentList $argumentList 191 | 192 | return $uriBuilder 193 | } 194 | 195 | <# 196 | .SYNOPSIS 197 | Invokes the VSTS REST API endpoint. 198 | 199 | .PARAMETER Session 200 | The session object created by New-VstsSession. 201 | 202 | .PARAMETER QueryStringParameters 203 | A hash table containing any additional query string 204 | parameters to add to the URI. 205 | 206 | .PARAMETER Project 207 | The name of the project to invoke the REST API for. 208 | 209 | .PARAMETER Path 210 | The path to add to the URI. 211 | 212 | .PARAMETER ApiVersion 213 | The version of the REST API to use. 214 | 215 | .PARAMETER Method 216 | The method to use for the REST API. Deraults to 'GET'. 217 | 218 | .PARAMETER Body 219 | The body to pass in the REST call. 220 | 221 | .PARAMETER EndpointName 222 | Set an alternate VSTS endpoint to call. 223 | This is required by API calls for to preview APIs that are not 224 | yet available on the primary endpoint. 225 | 226 | .PARAMETER QueryStringExtParameters 227 | A hash table containing any additional query string 228 | parameters to add to the URI. These will be added with a '$' 229 | pre-pended to the query string name. E.g. '&$Top=10'. 230 | #> 231 | function Invoke-VstsEndpoint 232 | { 233 | [CmdletBinding()] 234 | param 235 | ( 236 | [Parameter(Mandatory = $true)] 237 | $Session, 238 | 239 | [Parameter()] 240 | [Hashtable] $QueryStringParameters, 241 | 242 | [Parameter()] 243 | [ValidateNotNullOrEmpty()] 244 | [String] $Project, 245 | 246 | [Parameter()] 247 | [Uri] $Path, 248 | 249 | [Parameter()] 250 | [String] $ApiVersion = '1.0', 251 | 252 | [ValidateSet('GET', 'PUT', 'POST', 'DELETE', 'PATCH')] 253 | [String] $Method = 'GET', 254 | 255 | [Parameter()] 256 | [String] $Body, 257 | 258 | [Parameter()] 259 | [String] $EndpointName, 260 | 261 | [Parameter()] 262 | [Hashtable] $QueryStringExtParameters 263 | ) 264 | 265 | $queryString = [System.Web.HttpUtility]::ParseQueryString([string]::Empty) 266 | 267 | if ($QueryStringParameters -ne $null) 268 | { 269 | foreach ($parameter in $QueryStringParameters.GetEnumerator()) 270 | { 271 | $queryString[$parameter.Key] = $parameter.Value 272 | } 273 | } 274 | 275 | <# 276 | These are query parmaeters that will be added prepended with a $. 277 | They can't be passed in the QueryStringParameters. 278 | #> 279 | if ($QueryStringExtParameters -ne $null) 280 | { 281 | foreach ($parameter in $QueryStringExtParameters.GetEnumerator()) 282 | { 283 | $queryString['$' + $parameter.Key] = $parameter.Value 284 | } 285 | } 286 | 287 | $queryString["api-version"] = $ApiVersion 288 | $queryString = $queryString.ToString() 289 | 290 | $authorization = Get-VstsAuthorization -User $Session.User -Token $Session.Token 291 | 292 | $collection = $Session.Collection 293 | 294 | $uriBuilder = Get-VstsEndpointUri -Session $Session -EndpointName $EndpointName 295 | $uriBuilder.Query = $queryString 296 | 297 | if ([String]::IsNullOrEmpty($Project)) 298 | { 299 | $uriBuilder.Path = ('{0}/_apis/{1}' -f $collection, $Path) 300 | } 301 | else 302 | { 303 | $uriBuilder.Path = ('{0}/{1}/_apis/{2}' -f $collection, $Project, $Path) 304 | } 305 | 306 | $uri = $uriBuilder.Uri 307 | 308 | Write-Verbose -Message "Invoke URI [$uri]" 309 | 310 | $contentType = 'application/json' 311 | $invokeRestMethodParameters = @{ 312 | Uri = $Uri 313 | Method = $Method 314 | ContentType = $ContentType 315 | Headers = @{ Authorization = $authorization } 316 | } 317 | 318 | if ($Method -eq 'PUT' -or $Method -eq 'POST' -or $Method -eq 'PATCH') 319 | { 320 | if ($Method -eq 'PATCH') 321 | { 322 | $invokeRestMethodParameters['contentType'] = 'application/json-patch+json' 323 | } 324 | 325 | $invokeRestMethodParameters += @{ 326 | Body = $Body 327 | } 328 | } 329 | 330 | $restResult = Invoke-RestMethod @invokeRestMethodParameters 331 | 332 | if ($restResult.Value) 333 | { 334 | return $restResult 335 | } 336 | else 337 | { 338 | <# 339 | A Value property wasn't returned which usually occurs 340 | if a specific record is requested from the API. 341 | So create a new object with the value property set 342 | to the returned object. 343 | #> 344 | return [psobject] @{ 345 | Value = $restResult 346 | } 347 | } 348 | } 349 | 350 | <# 351 | .SYNOPSIS 352 | Generates a VSTS authorization header value from a username and Personal 353 | Access Token. 354 | 355 | .PARAMETER User 356 | The username of the account to generate the authentication header for. 357 | 358 | .PARAMETER Token 359 | The Personal Access Token to use in the authentication header. 360 | #> 361 | function Get-VstsAuthorization 362 | { 363 | [CmdletBinding()] 364 | [OutputType([String])] 365 | param 366 | ( 367 | [Parameter(Mandatory = $True)] 368 | [String] $User, 369 | 370 | [Parameter(Mandatory = $True)] 371 | [String] $Token 372 | ) 373 | 374 | $value = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User, $Token))) 375 | return ("Basic {0}" -f $value) 376 | } 377 | 378 | <# 379 | .SYNOPSIS 380 | Checks that a Guid is valid. 381 | 382 | .PARAMETER Guid 383 | The Guid to validate. 384 | 385 | .OUTPUTS 386 | Returns true if the Guid is valid. 387 | #> 388 | function Test-Guid 389 | { 390 | [CmdletBinding()] 391 | [OutputType([Boolean])] 392 | param 393 | ( 394 | [Parameter(Mandatory = $True)] 395 | [String] $Guid 396 | ) 397 | 398 | $newGuid = [Guid]::Empty 399 | [Guid]::TryParse($Guid, [ref]$newGuid) 400 | } 401 | -------------------------------------------------------------------------------- /lib/Releases.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Gets team project release definitions. 4 | 5 | .PARAMETER AccountName 6 | The name of the VSTS account to use. 7 | 8 | .PARAMETER User 9 | This user name to authenticate to VSTS. 10 | 11 | .PARAMETER Token 12 | This personal access token to use to authenticate to VSTS. 13 | 14 | .PARAMETER Session 15 | The session object created by New-VstsSession. 16 | 17 | .PARAMETER Project 18 | The name of the project to get the release from. 19 | 20 | .PARAMETER DefinitionId 21 | The DefinitionId of the release to return. 22 | #> 23 | function Get-VstsReleaseDefinition 24 | { 25 | [CmdletBinding(DefaultParameterSetName = 'Account')] 26 | param 27 | ( 28 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 29 | [String] $AccountName, 30 | 31 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 32 | [String] $User, 33 | 34 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 35 | [String] $Token, 36 | 37 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 38 | $Session, 39 | 40 | [Parameter(Mandatory = $True)] 41 | [String] $Project, 42 | 43 | [Parameter()] 44 | [Int32] $DefinitionId 45 | ) 46 | 47 | if ($PSCmdlet.ParameterSetName -eq 'Account') 48 | { 49 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 50 | } 51 | 52 | $path = 'release/definitions' 53 | 54 | $additionalInvokeParameters = @{ 55 | QueryStringParameters = (Get-VstsQueryStringParametersFromBound ` 56 | -BoundParameters $PSBoundParameters ` 57 | -ParameterList 'DefinitionId') 58 | } 59 | 60 | $result = Invoke-VstsEndpoint ` 61 | -Session $Session ` 62 | -Path $path ` 63 | -Project $Project ` 64 | -ApiVersion '3.0-preview.2' ` 65 | -EndpointName 'vsrm' ` 66 | @additionalInvokeParameters 67 | 68 | return $result.Value 69 | } 70 | 71 | <# 72 | .SYNOPSIS 73 | Gets team project release definitions. 74 | 75 | .PARAMETER AccountName 76 | The name of the VSTS account to use. 77 | 78 | .PARAMETER User 79 | This user name to authenticate to VSTS. 80 | 81 | .PARAMETER Token 82 | This personal access token to use to authenticate to VSTS. 83 | 84 | .PARAMETER Session 85 | The session object created by New-VstsSession. 86 | 87 | .PARAMETER Project 88 | The name of the project to get the release from. 89 | 90 | .PARAMETER Id 91 | The Id of the release to return. 92 | 93 | .PARAMETER Top 94 | The maximum number of releases to return. 95 | 96 | .PARAMETER CreatedBy 97 | The alias of the user that created the release. 98 | 99 | .PARAMETER StatusFilter 100 | The releases that have this status. 101 | 102 | .PARAMETER QueryOrder 103 | Gets the results in the defined order of created date 104 | for releases. 105 | #> 106 | function Get-VstsRelease 107 | { 108 | [CmdletBinding(DefaultParameterSetName = 'Account')] 109 | param 110 | ( 111 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 112 | [String] $AccountName, 113 | 114 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 115 | [String] $User, 116 | 117 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 118 | [String] $Token, 119 | 120 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 121 | $Session, 122 | 123 | [Parameter(Mandatory = $true)] 124 | [String] $Project, 125 | 126 | [Parameter()] 127 | [Int32] $Id, 128 | 129 | [Parameter()] 130 | [Int32] $DefinitionId, 131 | 132 | [Parameter()] 133 | [Int32] $Top, 134 | 135 | [Parameter()] 136 | [String] $CreatedBy, 137 | 138 | [Parameter()] 139 | [ValidateSet('Draft', 'Active', 'Abandoned')] 140 | [String] $StatusFilter, 141 | 142 | [Parameter()] 143 | [ValidateSet('ascending', 'descending')] 144 | [String] $QueryOrder 145 | ) 146 | 147 | if ($PSCmdlet.ParameterSetName -eq 'Account') 148 | { 149 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 150 | } 151 | 152 | $path = 'release/releases' 153 | $additionalInvokeParameters = @{} 154 | 155 | if ($PSBoundParameters.ContainsKey('Id')) 156 | { 157 | $path = ('{0}/{1}' -f $path, $Id) 158 | } 159 | else 160 | { 161 | $additionalInvokeParameters = @{ 162 | QueryStringParameters = (Get-VstsQueryStringParametersFromBound ` 163 | -BoundParameters $PSBoundParameters ` 164 | -ParameterList 'definitionId', 'createdBy', 'statusFilter', 'queryOrder') 165 | QueryStringExtParameters = Get-VstsQueryStringParametersFromBound ` 166 | -BoundParameters $PSBoundParameters ` 167 | -ParameterList 'top' 168 | } 169 | } 170 | 171 | $result = Invoke-VstsEndpoint ` 172 | -Session $Session ` 173 | -Path $path ` 174 | -Project $Project ` 175 | -ApiVersion '3.0-preview.2' ` 176 | -EndpointName 'vsrm' ` 177 | @additionalInvokeParameters 178 | 179 | return $Result.Value 180 | } 181 | 182 | <# 183 | .SYNOPSIS 184 | Creates a new release for a project. 185 | 186 | .PARAMETER AccountName 187 | The name of the VSTS account to use. 188 | 189 | .PARAMETER User 190 | This user name to authenticate to VSTS. 191 | 192 | .PARAMETER Token 193 | This personal access token to use to authenticate to VSTS. 194 | 195 | .PARAMETER Session 196 | The session object created by New-VstsSession. 197 | 198 | .PARAMETER Project 199 | The name of the project to create the new release in. 200 | 201 | .PARAMETER DefinitionId 202 | The release definition Id to create the new release for. 203 | 204 | .PARAMETER Description 205 | The description of the new release. 206 | 207 | .PARAMETER Artifacts 208 | The artifacts that will be provided into the release. 209 | 210 | These must be in the format: 211 | [ 212 | alias: {string}, 213 | instanceReference: { 214 | name: {string}, 215 | id: {string}, 216 | sourceBranch: {string} 217 | } 218 | ] 219 | 220 | .EXAMPLE 221 | > 222 | $vstsSession = New-VSTSSession ` 223 | -AccountName 'myvstsaccount' ` 224 | -User 'joe.bloggs@fabrikam.com' ` 225 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 226 | 227 | New-VstsRelease ` 228 | -Session $vstsSession ` 229 | -Project 'pipeline' ` 230 | -DefinitionId 2 ` 231 | -Description 'Test from API' ` 232 | -Artifacts @( @{ Alias = 'FabrikamCI'; instanceReference = @{ id = 2217 } } ) 233 | #> 234 | function New-VstsRelease 235 | { 236 | [CmdletBinding(DefaultParameterSetName = 'Account')] 237 | param 238 | ( 239 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 240 | [String] $AccountName, 241 | 242 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 243 | [String] $User, 244 | 245 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 246 | [String] $Token, 247 | 248 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 249 | $Session, 250 | 251 | [Parameter(Mandatory = $true)] 252 | [String] $Project, 253 | 254 | [Parameter(Mandatory = $true)] 255 | [Int32] $DefinitionId, 256 | 257 | [Parameter(Mandatory = $true)] 258 | [String] $Description, 259 | 260 | [Parameter(Mandatory = $true)] 261 | [HashTable[]] $Artifacts 262 | ) 263 | 264 | if ($PSCmdlet.ParameterSetName -eq 'Account') 265 | { 266 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 267 | } 268 | 269 | $Body = @{ 270 | definitionId = $DefinitionId 271 | description = $Description 272 | artifacts = $Artifacts 273 | } | ConvertTo-Json -Depth 20 274 | 275 | Invoke-VstsEndpoint ` 276 | -Session $Session ` 277 | -Project $Project ` 278 | -Path 'release/releases' ` 279 | -ApiVersion '3.0-preview.2' ` 280 | -EndpointName 'vsrm' ` 281 | -Method POST ` 282 | -Body $Body 283 | } 284 | 285 | 286 | <# 287 | .SYNOPSIS 288 | Creates a team project release definition. 289 | 290 | .PARAMETER AccountName 291 | The name of the VSTS account to use. 292 | 293 | .PARAMETER User 294 | This user name to authenticate to VSTS. 295 | 296 | .PARAMETER Token 297 | This personal access token to use to authenticate to VSTS. 298 | 299 | .PARAMETER Session 300 | The session object created by New-VstsSession. 301 | 302 | .PARAMETER Project 303 | The name of the project in which to create the release. 304 | 305 | .PARAMETER Name 306 | The name of release definition to create. 307 | 308 | .PARAMETER EnvironmentNames 309 | A list of Environments to create. Will be created with identical defaults. 310 | #> 311 | function New-VstsReleaseDefinition 312 | { 313 | [CmdletBinding(DefaultParameterSetName = 'Account')] 314 | param 315 | ( 316 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 317 | [String] $AccountName, 318 | 319 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 320 | [String] $User, 321 | 322 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 323 | [String] $Token, 324 | 325 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 326 | $Session, 327 | 328 | [Parameter(Mandatory = $True)] 329 | [String] $Project, 330 | 331 | [Parameter(Mandatory = $true)] 332 | [String] $Name, 333 | 334 | [Parameter(Mandatory = $false)] 335 | [string[]]$EnvironmentNames = @('Staging'), 336 | 337 | [Parameter(Mandatory = $false)] 338 | [string]$ReleaseNameFormat 339 | ) 340 | 341 | if ($PSCmdlet.ParameterSetName -eq 'Account') 342 | { 343 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 344 | } 345 | 346 | [psobject[]]$environments = for($i = 0; $i -lt $environmentNames.Count; $i++){ 347 | $environmentDefinition = @{ 348 | id = $i 349 | name = $EnvironmentNames[$i] 350 | variables = "" 351 | preDeployApprovals = @{ 352 | approvals = @( 353 | @{ 354 | rank = 1 355 | isAutomated = $true 356 | isNotificationOn = $false 357 | id = 0 358 | } 359 | ) 360 | } 361 | postDeployApprovals = @{ 362 | approvals = @( 363 | @{ 364 | rank = 1 365 | isAutomated = $true 366 | isNotificationOn = $false 367 | id = 0 368 | } 369 | ) 370 | } 371 | deployPhases = @( 372 | @{ 373 | deploymentInput = @{ 374 | parallelExecution = @{ 375 | parallelExecutionType = "none" 376 | } 377 | skipArtifactsDownload = $false 378 | timeoutInMinutes = 0 379 | queueId = 45 380 | demands = @() 381 | enableAccessToken = $false 382 | } 383 | rank = 1 384 | phaseType = "agentBasedDeployment" 385 | name = "Run on agent" 386 | workflowTasks = @() 387 | } 388 | ) 389 | environmentOptions = @{ 390 | emailNotificationType = "OnlyOnFailure" 391 | emailRecipients = "release.environment.owner;release.creator" 392 | skipArtifactsDownload = $false 393 | timeoutInMinutes = 0 394 | enableAccessToken = $false 395 | publishDeploymentStatus = $false 396 | } 397 | demands = @() 398 | conditions = @() 399 | executionPolicy = @{ 400 | concurrencyCount = 0 401 | queueDepthCount = 0 402 | } 403 | schedules = @() 404 | retentionPolicy = @{ 405 | daysToKeep = 30 406 | releasesToKeep = 3 407 | retainBuild = $true 408 | } 409 | } 410 | Write-Output $environmentDefinition 411 | } 412 | 413 | 414 | $body = @{ 415 | source = "undefined" 416 | id = 0 417 | revision = 1 418 | name = $name 419 | createdBy = $null 420 | createdOn = "0001-01-01T00:00:00" 421 | modifiedBy = $null 422 | modifiedOn = "0001-01-01T00:00:00" 423 | lastRelease = $null 424 | path = $null 425 | variables = "" 426 | variableGroups = @() 427 | environments = $environments 428 | artifacts = @() 429 | triggers = @() 430 | releaseNameFormat = $ReleaseNameFormat 431 | _links = "" 432 | tags = @() 433 | properties = "" 434 | } | ConvertTo-Json -Depth 20 -Verbose 435 | 436 | $result = Invoke-VstsEndpoint ` 437 | -Session $Session ` 438 | -Project $Project ` 439 | -Path 'Release/definitions' ` 440 | -ApiVersion '4.0-preview.3' ` 441 | -EndpointName 'vsrm' ` 442 | -Method POST ` 443 | -Body $Body 444 | 445 | 446 | Write-Output $result.Value 447 | } 448 | -------------------------------------------------------------------------------- /lib/Projects.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Get projects in a VSTS account. 4 | 5 | .PARAMETER AccountName 6 | The name of the VSTS account to use. 7 | 8 | .PARAMETER User 9 | This user name to authenticate to VSTS. 10 | 11 | .PARAMETER Token 12 | This personal access token to use to authenticate to VSTS. 13 | 14 | .PARAMETER Session 15 | The session object created by New-VstsSession. 16 | 17 | .PARAMETER Name 18 | The name of the project to return. 19 | 20 | .PARAMETER StateFilter 21 | If specified will return all projects matching this state. 22 | 23 | .PARAMETER Top 24 | Restrict the number of projects to be returned. 25 | 26 | .PARAMETER Skip 27 | Do not return the first 'skip' number of projects. 28 | #> 29 | function Get-VstsProject 30 | { 31 | [CmdletBinding(DefaultParameterSetName = 'Account')] 32 | param 33 | ( 34 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 35 | [String] $AccountName, 36 | 37 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 38 | [String] $User, 39 | 40 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 41 | [String] $Token, 42 | 43 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 44 | $Session, 45 | 46 | [Parameter()] 47 | [String] $Name, 48 | 49 | [Parameter()] 50 | [ValidateSet('WellFormed', 'CreatePending', 'Deleting', 'New', 'All')] 51 | [String] $StateFilter, 52 | 53 | [Parameter()] 54 | [Int32] $Top, 55 | 56 | [Parameter()] 57 | [Int32] $Skip 58 | ) 59 | 60 | if ($PSCmdlet.ParameterSetName -eq 'Account') 61 | { 62 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 63 | } 64 | 65 | $path = 'projects' 66 | $additionalInvokeParameters = @{} 67 | 68 | if ($PSBoundParameters.ContainsKey('Name')) 69 | { 70 | $path = ('{0}/{1}' -f $path, $Name) 71 | } 72 | else 73 | { 74 | $additionalInvokeParameters = @{ 75 | QueryStringParameters = (Get-VstsQueryStringParametersFromBound ` 76 | -BoundParameters $PSBoundParameters ` 77 | -ParameterList 'stateFilter') 78 | QueryStringExtParameters = Get-VstsQueryStringParametersFromBound ` 79 | -BoundParameters $PSBoundParameters ` 80 | -ParameterList 'Top', 'Skip' 81 | } 82 | } 83 | 84 | $result = Invoke-VstsEndpoint ` 85 | -Session $Session ` 86 | -Path $path ` 87 | @additionalInvokeParameters 88 | 89 | return $result.Value 90 | } 91 | 92 | <# 93 | .SYNOPSIS 94 | Wait for a project to be created or deleted. 95 | 96 | .PARAMETER AccountName 97 | The name of the VSTS account to use. 98 | 99 | .PARAMETER User 100 | This user name to authenticate to VSTS. 101 | 102 | .PARAMETER Token 103 | This personal access token to use to authenticate to VSTS. 104 | 105 | .PARAMETER Session 106 | The session object created by New-VstsSession. 107 | 108 | .PARAMETER Name 109 | The name of the project to wait for. 110 | 111 | .PARAMETER Attempts 112 | The number of attempts to make when waiting for the project. 113 | 114 | .PARAMETER Exists 115 | Specifies if the cmdlet will wait for the project to exist 116 | or be absent (e.g. if being deleted). 117 | 118 | .PARAMETER RetryIntervalSec 119 | The number of seconds to wait between each check for the 120 | project. 121 | 122 | .PARAMETER State 123 | Specifies if the cmdlet will wait for the project to enter 124 | a specific state. This only applies if the Exists switch is 125 | enabled. 126 | #> 127 | function Wait-VSTSProject 128 | { 129 | [CmdletBinding(DefaultParameterSetName = 'Account')] 130 | param 131 | ( 132 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 133 | [String] $AccountName, 134 | 135 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 136 | [String] $User, 137 | 138 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 139 | [String] $Token, 140 | 141 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 142 | $Session, 143 | 144 | [Parameter(Mandatory = $True)] 145 | [String] $Name, 146 | 147 | [Parameter()] 148 | [Int32] $Attempts = 30, 149 | 150 | [Parameter()] 151 | [Switch] $Exists, 152 | 153 | [Parameter()] 154 | [Int32] $RetryIntervalSec = 2, 155 | 156 | [Parameter()] 157 | [ValidateSet('WellFormed', 'CreatePending', 'Deleting', 'New', 'All')] 158 | [String] $State 159 | ) 160 | 161 | if ($PSCmdlet.ParameterSetName -eq 'Account') 162 | { 163 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 164 | } 165 | 166 | $isMatched = $false 167 | $retries = 0 168 | do 169 | { 170 | 171 | Write-Verbose -Message ('Querying project {0}' -f $Name) 172 | $project = Get-VSTSProject ` 173 | -Session $Session ` 174 | -Name $Name ` 175 | -ErrorAction SilentlyContinue 176 | 177 | if ($Exists) 178 | { 179 | # Waiting for project to exist 180 | if ($project) 181 | { 182 | # Project exists 183 | if ($PSBoundParameters.ContainsKey('State')) 184 | { 185 | # The correct state also needs to be determined 186 | if ($project.State -eq $State) 187 | { 188 | $resultMessage = ('Project {0} exists in required state {1}' -f $Name, $project.State) 189 | $isMatched = $true 190 | } 191 | else 192 | { 193 | $resultMessage = ('Project {0} exists in state {1}, but not in required state {2}' -f $Name, $project.State, $State) 194 | } 195 | } 196 | else 197 | { 198 | $resultMessage = ('Project {0} exists and should' -f $Name) 199 | $isMatched = $true 200 | } 201 | } 202 | else 203 | { 204 | $resultMessage = ('Project {0} does not exist but should' -f $Name) 205 | } 206 | } 207 | else 208 | { 209 | # Waiting for project to not exist 210 | if ($project) 211 | { 212 | $resultMessage = ('Project {0} exists but should not' -f $Name) 213 | } 214 | else 215 | { 216 | $resultMessage = ('Project {0} does not exist and should not' -f $Name) 217 | $isMatched = $true 218 | } 219 | } 220 | 221 | Write-Verbose -Message $resultMessage 222 | 223 | if ($isMatched) 224 | { 225 | break 226 | } 227 | 228 | $retries++ 229 | 230 | # Don't wait on the last retry 231 | if ($retries -lt $Attempts) 232 | { 233 | Start-Sleep -Seconds $RetryIntervalSec 234 | } 235 | } while ($retries -le $Attempts) 236 | 237 | if (-not $isMatched) 238 | { 239 | # If we never reached the correct state then throw exception 240 | throw ('{0} after {1} attempts' -f $resultMessage,$Attempts) 241 | } 242 | } 243 | 244 | <# 245 | .SYNOPSIS 246 | Creates a new project in a VSTS account. 247 | 248 | .PARAMETER AccountName 249 | The name of the VSTS account to use. 250 | 251 | .PARAMETER User 252 | This user name to authenticate to VSTS. 253 | 254 | .PARAMETER Token 255 | This personal access token to use to authenticate to VSTS. 256 | 257 | .PARAMETER Session 258 | The session object created by New-VstsSession. 259 | 260 | .PARAMETER Name 261 | The name of the project to create. 262 | 263 | .PARAMETER Description 264 | The description of the project to create. 265 | 266 | .PARAMETER SourceControlType 267 | The type of source control system to use. 268 | Defaults to 'Git'. 269 | 270 | .PARAMETER TemplateTypeId 271 | The template type Id for the type of work item management 272 | to use for the project. 273 | 274 | .PARAMETER TemplateTypeName 275 | The template type Name for the type of work item management 276 | to use for the project. 277 | 278 | .PARAMETER Wait 279 | Switch to cause the cmdlet to wait for the project to be 280 | created before returning. 281 | #> 282 | function New-VstsProject 283 | { 284 | [CmdletBinding(DefaultParameterSetName = 'Account')] 285 | param 286 | ( 287 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 288 | [String] $AccountName, 289 | 290 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 291 | [String] $User, 292 | 293 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 294 | [String] $Token, 295 | 296 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 297 | $Session, 298 | 299 | [Parameter(Mandatory = $True)] 300 | [String] $Name, 301 | 302 | [Parameter()] 303 | [String] $Description, 304 | 305 | [Parameter()] 306 | [ValidateSet('Git', 'Tfvc')] 307 | [String] $SourceControlType = 'Git', 308 | 309 | [Parameter()] 310 | [ValidateNotNullOrEmpty()] 311 | [String] $TemplateTypeId, 312 | 313 | [Parameter()] 314 | [ValidateNotNullOrEmpty()] 315 | [String] $TemplateTypeName = 'Agile', 316 | 317 | [Parameter()] 318 | [Switch] $Wait 319 | ) 320 | 321 | if ($PSCmdlet.ParameterSetName -eq 'Account') 322 | { 323 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 324 | } 325 | 326 | $path = 'projects' 327 | 328 | if ([String]::IsNullOrEmpty($TemplateTypeId)) 329 | { 330 | Write-Verbose -Message ('Getting template Id for process {0}' -f $templateTypeName) 331 | 332 | $templateTypeId = Get-VstsProcess -Session $Session | 333 | Where-Object -Property Name -EQ $TemplateTypeName | 334 | Select-Object -ExpandProperty Id 335 | 336 | if ($null -eq $templateTypeId) 337 | { 338 | throw "Template $TemplateTypeName not found." 339 | } 340 | 341 | Write-Verbose -Message ('Template Id {0} found for process {1}' -f $templateTypeId, $templateTypeName) 342 | } 343 | 344 | $body = @{ 345 | name = $Name 346 | description = $Description 347 | capabilities = @{ 348 | versioncontrol = @{ 349 | sourceControlType = $SourceControlType 350 | } 351 | processTemplate = @{ 352 | templateTypeId = $templateTypeId 353 | } 354 | } 355 | } | ConvertTo-Json 356 | 357 | $result = Invoke-VstsEndpoint ` 358 | -Session $Session ` 359 | -Path $path ` 360 | -Method 'POST' ` 361 | -Body $body ` 362 | -ErrorAction Stop 363 | 364 | if ($Wait) 365 | { 366 | Write-Verbose -Message ('Waiting for project {0} to be created' -f $Name) 367 | Wait-VSTSProject -Session $Session -Name $Name -Exists -State WellFormed 368 | } 369 | 370 | return $result.Value 371 | } 372 | 373 | <# 374 | .SYNOPSIS 375 | Deletes a project from the specified VSTS account. 376 | 377 | .PARAMETER AccountName 378 | The name of the VSTS account to use. 379 | 380 | .PARAMETER User 381 | This user name to authenticate to VSTS. 382 | 383 | .PARAMETER Token 384 | This personal access token to use to authenticate to VSTS. 385 | 386 | .PARAMETER Session 387 | The session object created by New-VstsSession. 388 | 389 | .PARAMETER Name 390 | The name of the project to delete. 391 | 392 | .PARAMETER Wait 393 | Switch to cause the cmdlet to wait for the project to be 394 | deleted before returning. 395 | #> 396 | function Remove-VSTSProject 397 | { 398 | [CmdletBinding(DefaultParameterSetName = 'Account')] 399 | param 400 | ( 401 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 402 | [String] $AccountName, 403 | 404 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 405 | [String] $User, 406 | 407 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 408 | [String] $Token, 409 | 410 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 411 | $Session, 412 | 413 | [Parameter(Mandatory = $True)] 414 | [String] $Name, 415 | 416 | [Parameter()] 417 | [Switch] $Wait 418 | ) 419 | 420 | if ($PSCmdlet.ParameterSetName -eq 'Account') 421 | { 422 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 423 | } 424 | 425 | $projectId = (Get-VstsProject -Session $Session -Name $Name).Id 426 | 427 | if ($null -eq $projectId) 428 | { 429 | throw "Project $Name not found." 430 | } 431 | 432 | $path = ('projects/{0}' -f $projectId) 433 | 434 | Write-Verbose -Message ('Removing project Id {0}' -f $projectId) 435 | $null = Invoke-VstsEndpoint ` 436 | -Session $Session ` 437 | -Path $path ` 438 | -Method 'DELETE' 439 | 440 | if ($Wait) 441 | { 442 | Write-Verbose -Message ('Waiting for project {0} to be deleted' -f $Name) 443 | Wait-VSTSProject -Session $Session -Name $Name 444 | } 445 | } 446 | 447 | <# 448 | .SYNOPSIS 449 | Gets available team processes. 450 | 451 | .PARAMETER AccountName 452 | The name of the VSTS account to use. 453 | 454 | .PARAMETER User 455 | This user name to authenticate to VSTS. 456 | 457 | .PARAMETER Token 458 | This personal access token to use to authenticate to VSTS. 459 | 460 | .PARAMETER Session 461 | The session object created by New-VstsSession. 462 | 463 | .PARAMETER Id 464 | The process Id of the process to return. This is a Guid. 465 | #> 466 | function Get-VstsProcess 467 | { 468 | [CmdletBinding(DefaultParameterSetName = 'Account')] 469 | param 470 | ( 471 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 472 | [String] $AccountName, 473 | 474 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 475 | [String] $User, 476 | 477 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 478 | [String] $Token, 479 | 480 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 481 | $Session, 482 | 483 | [Parameter()] 484 | [String] $Id 485 | ) 486 | 487 | if ($PSCmdlet.ParameterSetName -eq 'Account') 488 | { 489 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 490 | } 491 | 492 | $path = 'process/processes' 493 | 494 | if ($PSBoundParameters.ContainsKey('Id')) 495 | { 496 | $path = ('{0}/{1}' -f $path, $Id) 497 | } 498 | 499 | $result = Invoke-VstsEndpoint ` 500 | -Session $Session ` 501 | -Path $path 502 | 503 | return $result.Value 504 | } 505 | -------------------------------------------------------------------------------- /lib/Code.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Gets Git repositories in the specified team project. 4 | 5 | .PARAMETER AccountName 6 | The name of the VSTS account to use. 7 | 8 | .PARAMETER User 9 | This user name to authenticate to VSTS. 10 | 11 | .PARAMETER Token 12 | This personal access token to use to authenticate to VSTS. 13 | 14 | .PARAMETER Session 15 | The session object created by New-VstsSession. 16 | 17 | .PARAMETER Project 18 | The name of the project to get the repositories from. 19 | 20 | .PARAMETER Repository 21 | The id or name of the repository. If this is a repository 22 | id then the Project is optional. 23 | 24 | .EXAMPLE 25 | > 26 | $vstsSession = New-VSTSSession ` 27 | -AccountName 'myvstsaccount' ` 28 | -User 'joe.bloggs@fabrikam.com' ` 29 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 30 | 31 | Get-VstsGitRepository ` 32 | -Session $session ` 33 | -Project 'FabrikamFiber' 34 | 35 | Get a list of Git repositories in the FabrikamFiber project. 36 | 37 | .EXAMPLE 38 | > 39 | $vstsSession = New-VSTSSession ` 40 | -AccountName 'myvstsaccount' ` 41 | -User 'joe.bloggs@fabrikam.com' ` 42 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 43 | 44 | Get-VstsGitRepository ` 45 | -Session $session ` 46 | -Project 'FabrikamFiber' ` 47 | -Repository 'PortalApp' 48 | 49 | Get a the PortalApp repository in the FabrikamFiber project. 50 | #> 51 | function Get-VstsGitRepository 52 | { 53 | [CmdletBinding(DefaultParameterSetName = 'Account')] 54 | param 55 | ( 56 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 57 | [String] $AccountName, 58 | 59 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 60 | [String] $User, 61 | 62 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 63 | [String] $Token, 64 | 65 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 66 | $Session, 67 | 68 | [Parameter()] 69 | [ValidateNotNullOrEmpty()] 70 | [String] $Project, 71 | 72 | [Parameter()] 73 | [ValidateNotNullOrEmpty()] 74 | [String] $Repository 75 | ) 76 | 77 | if ($PSCmdlet.ParameterSetName -eq 'Account') 78 | { 79 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 80 | } 81 | 82 | $path = 'git/repositories' 83 | 84 | if ($PSBoundParameters.ContainsKey('Repository')) 85 | { 86 | $path = ('{0}/{1}' -f $path, $Repository) 87 | } 88 | 89 | $invokeParameters = @{ 90 | Session = $Session 91 | Path = $Path 92 | } 93 | 94 | if ($PSBoundParameters.ContainsKey('Project')) 95 | { 96 | $invokeParameters += @{ Project = $Project } 97 | } 98 | 99 | $result = Invoke-VstsEndpoint @invokeParameters 100 | 101 | return $result.Value 102 | } 103 | 104 | <# 105 | .SYNOPSIS 106 | Creates a new Git repository in the specified team project. 107 | 108 | .PARAMETER AccountName 109 | The name of the VSTS account to use. 110 | 111 | .PARAMETER User 112 | This user name to authenticate to VSTS. 113 | 114 | .PARAMETER Token 115 | This personal access token to use to authenticate to VSTS. 116 | 117 | .PARAMETER Session 118 | The session object created by New-VstsSession. 119 | 120 | .PARAMETER Project 121 | The name of the project to create the repositories in. 122 | 123 | .PARAMETER RepositoryName 124 | The name of the repository to create. 125 | 126 | .EXAMPLE 127 | > 128 | $vstsSession = New-VSTSSession ` 129 | -AccountName 'myvstsaccount' ` 130 | -User 'joe.bloggs@fabrikam.com' ` 131 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 132 | 133 | New-VstsGitRepository ` 134 | -Session $session ` 135 | -Project 'FabrikamFiber' ` 136 | -RepositoryName 'PortalApp' 137 | 138 | Create a repository in the FabrikamFiber project called PortalApp. 139 | #> 140 | function New-VstsGitRepository 141 | { 142 | [CmdletBinding(DefaultParameterSetName = 'Account')] 143 | param 144 | ( 145 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 146 | [String] $AccountName, 147 | 148 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 149 | [String] $User, 150 | 151 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 152 | [String] $Token, 153 | 154 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 155 | $Session, 156 | 157 | [Parameter(Mandatory = $True)] 158 | [String] $Project, 159 | 160 | [Parameter(Mandatory = $True)] 161 | [String] $RepositoryName 162 | ) 163 | 164 | if ($PSCmdlet.ParameterSetName -eq 'Account') 165 | { 166 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 167 | } 168 | 169 | $path = 'git/repositories' 170 | 171 | # Ensure we have what looks like a Project Id Guid. 172 | if (Test-Guid -Guid $Project) 173 | { 174 | $projectId = $Project 175 | } 176 | else 177 | { 178 | $projectId = (Get-VstsProject -Session $Session -Name $Project).Id 179 | } 180 | 181 | $body = @{ 182 | Name = $RepositoryName 183 | Project = @{ 184 | Id = $projectId 185 | } 186 | } | ConvertTo-Json 187 | 188 | $result = Invoke-VstsEndpoint ` 189 | -Session $Session ` 190 | -Path $path ` 191 | -Method 'POST' ` 192 | -Body $body ` 193 | -ErrorAction Stop 194 | 195 | return $result.Value 196 | } 197 | 198 | <# 199 | .SYNOPSIS 200 | Deletes a Git repository from the specified team project. 201 | 202 | .PARAMETER AccountName 203 | The name of the VSTS account to use. 204 | 205 | .PARAMETER User 206 | This user name to authenticate to VSTS. 207 | 208 | .PARAMETER Token 209 | This personal access token to use to authenticate to VSTS. 210 | 211 | .PARAMETER Session 212 | The session object created by New-VstsSession. 213 | 214 | .PARAMETER Project 215 | The name of the project to delete the repository from. 216 | 217 | .PARAMETER RepositoryName 218 | The name of the repository to delete. 219 | 220 | .EXAMPLE 221 | > 222 | $vstsSession = New-VSTSSession ` 223 | -AccountName 'myvstsaccount' ` 224 | -User 'joe.bloggs@fabrikam.com' ` 225 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 226 | 227 | Remove-VstsGitRepository ` 228 | -Session $session ` 229 | -Project 'FabrikamFiber' ` 230 | -RepositoryName 'PortalApp' 231 | 232 | Delete the PortalAll repository from the FabrikamFiber project. 233 | #> 234 | function Remove-VstsGitRepository 235 | { 236 | [CmdletBinding(DefaultParameterSetName = 'Account')] 237 | param 238 | ( 239 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 240 | [String] $AccountName, 241 | 242 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 243 | [String] $User, 244 | 245 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 246 | [String] $Token, 247 | 248 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 249 | $Session, 250 | 251 | [Parameter()] 252 | [ValidateNotNullOrEmpty()] 253 | [String] $Project, 254 | 255 | [Parameter(Mandatory = $True)] 256 | [ValidateNotNullOrEmpty()] 257 | [String] $Repository 258 | ) 259 | 260 | if ($PSCmdlet.ParameterSetName -eq 'Account') 261 | { 262 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 263 | } 264 | 265 | # Make sure the Repository Id Guid is available 266 | if (Test-Guid -Guid $Repository) 267 | { 268 | if ($PSBoundParameters.ContainsKey('Project')) 269 | { 270 | Throw 'If repository Id is passed then Project should not be passed.' 271 | } 272 | 273 | $repositoryId = $Repository 274 | } 275 | else 276 | { 277 | if (-not $PSBoundParameters.ContainsKey('Project')) 278 | { 279 | Throw 'If repository Name is passed then Project must be passed.' 280 | } 281 | 282 | $repositoryId = (Get-VstsGitRepository -Session $Session -Project $Project -Repository $Repository).Id 283 | Write-Verbose -Message ('Repository Id {0} retrieved for repository {1}' -f $repositoryId, $Repository) 284 | } 285 | 286 | $path = ('git/repositories/{0}' -f $repositoryId) 287 | 288 | $invokeParameters = @{ 289 | Session = $Session 290 | Path = $Path 291 | Method = 'DELETE' 292 | ErrorAction = 'Stop' 293 | } 294 | 295 | if ($PSBoundParameters.ContainsKey('Project')) 296 | { 297 | $invokeParameters += @{ Project = $Project } 298 | } 299 | 300 | $null = Invoke-VstsEndpoint @invokeParameters 301 | } 302 | 303 | <# 304 | .SYNOPSIS 305 | Get code policy configurations for the specified project. 306 | 307 | .PARAMETER AccountName 308 | The name of the VSTS account to use. 309 | 310 | .PARAMETER User 311 | This user name to authenticate to VSTS. 312 | 313 | .PARAMETER Token 314 | This personal access token to use to authenticate to VSTS. 315 | 316 | .PARAMETER Session 317 | The session object created by New-VstsSession. 318 | 319 | .PARAMETER Project 320 | The name of the project to get the policy configuration from. 321 | 322 | .PARAMETER Id 323 | The Id of the policy configuration to return. 324 | 325 | .PARAMETER Top 326 | Restrict the number of policy configurations to be returned. 327 | 328 | .PARAMETER Skip 329 | Do not return the first 'skip' number of policy configurations. 330 | #> 331 | function Get-VstsCodePolicyConfiguration 332 | { 333 | [CmdletBinding(DefaultParameterSetName = 'Account')] 334 | param 335 | ( 336 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 337 | [String] $AccountName, 338 | 339 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 340 | [String] $User, 341 | 342 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 343 | [String] $Token, 344 | 345 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 346 | $Session, 347 | 348 | [Parameter(Mandatory = $true)] 349 | [String] $Project, 350 | 351 | [Parameter()] 352 | [String] $Id, 353 | 354 | [Parameter()] 355 | [Int32] $Top, 356 | 357 | [Parameter()] 358 | [Int32] $Skip 359 | 360 | ) 361 | 362 | if ($PSCmdlet.ParameterSetName -eq 'Account') 363 | { 364 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 365 | } 366 | 367 | $path = 'policy/configurations' 368 | $additionalInvokeParameters = @{} 369 | 370 | if ($PSCmdlet.ParameterSetName -eq 'Query') 371 | { 372 | $additionalInvokeParameters = @{ 373 | QueryStringExtParameters = Get-VstsQueryStringParametersFromBound ` 374 | -BoundParameters $PSBoundParameters ` 375 | -ParameterList 'Top', 'Skip' 376 | } 377 | } 378 | else 379 | { 380 | if ($PSBoundParameters.ContainsKey('Id')) 381 | { 382 | $path = ('{0}/{1}' -f $path, $Id) 383 | } 384 | } 385 | 386 | $result = Invoke-VstsEndpoint ` 387 | -Session $Session ` 388 | -Project $Project ` 389 | -Path $path ` 390 | -ApiVersion '2.0-preview.1' ` 391 | @additionalInvokeParameters 392 | 393 | return $result.Value 394 | } 395 | 396 | <# 397 | .SYNOPSIS 398 | Creates a new Code Policy Configuration for the specified project. 399 | 400 | .PARAMETER AccountName 401 | The name of the VSTS account to use. 402 | 403 | .PARAMETER User 404 | This user name to authenticate to VSTS. 405 | 406 | .PARAMETER Token 407 | This personal access token to use to authenticate to VSTS. 408 | 409 | .PARAMETER Session 410 | The session object created by New-VstsSession. 411 | 412 | .PARAMETER Project 413 | The name of the project to create the Code Policy Configuration in. 414 | 415 | .PARAMETER RepositoryId 416 | The repository Id to create the new Code Policy Configuration on. 417 | 418 | .PARAMETER MinimumReviewers 419 | The minimum number of reviewers. 420 | 421 | .PARAMETER Branches 422 | The branches to apply the Code Policy Configuration to. 423 | #> 424 | function New-VstsCodePolicyConfiguration 425 | { 426 | [CmdletBinding(DefaultParameterSetName = 'Account')] 427 | param 428 | ( 429 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 430 | [String] $AccountName, 431 | 432 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 433 | [String] $User, 434 | 435 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 436 | [String] $Token, 437 | 438 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 439 | $Session, 440 | 441 | [Parameter(Mandatory = $True)] 442 | [String] $Project, 443 | 444 | [Parameter()] 445 | [Guid] $RepositoryId = [Guid]::Empty, 446 | 447 | [Parameter()] 448 | [Int] $MinimumReviewers = 1, 449 | 450 | [Parameter(Mandatory = $True)] 451 | [String[]] $Branches 452 | ) 453 | 454 | if ($PSCmdlet.ParameterSetName -eq 'Account') 455 | { 456 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 457 | } 458 | 459 | $path = 'policy/configurations' 460 | 461 | $repoId = $null 462 | if ($RepositoryId -ne [Guid]::Empty) 463 | { 464 | $repoId = $RepositoryId.ToString() 465 | } 466 | 467 | $scopes = foreach ($branch in $Branches) 468 | { 469 | @{ 470 | repositoryId = $RepoId 471 | refName = "refs/heads/$branch" 472 | matchKind = "exact" 473 | } 474 | } 475 | 476 | $policy = @{ 477 | isEnabled = $true 478 | isBlocking = $false 479 | type = @{ 480 | id = 'fa4e907d-c16b-4a4c-9dfa-4906e5d171dd' 481 | } 482 | settings = @{ 483 | minimumApproverCount = $MinimumReviewers 484 | creatorVoteCounts = $false 485 | scope = @($scopes) 486 | } 487 | } | ConvertTo-Json -Depth 10 488 | 489 | $result = Invoke-VstsEndpoint ` 490 | -Session $Session ` 491 | -Project $Project ` 492 | -Path $path ` 493 | -ApiVersion '2.0-preview.1' ` 494 | -Body $policy ` 495 | -Method 'POST' ` 496 | -ErrorAction Stop 497 | 498 | return $result.Value 499 | } 500 | 501 | <# 502 | .SYNOPSIS 503 | Converts a TFVC repository to a VSTS Git repository. 504 | 505 | .PARAMETER AccountName 506 | The name of the VSTS account to use. 507 | 508 | .PARAMETER User 509 | This user name to authenticate to VSTS. 510 | 511 | .PARAMETER Token 512 | This personal access token to use to authenticate to VSTS. 513 | 514 | .PARAMETER Session 515 | The session object created by New-VstsSession. 516 | 517 | .PARAMETER Project 518 | The session object created by New-VstsSession. 519 | 520 | .PARAMETER TargetName 521 | The name of the VSTS Re 522 | 523 | .PARAMETER SourceFolder 524 | The session object created by New-VstsSession. 525 | #> 526 | function ConvertTo-VstsGitRepository 527 | { 528 | [CmdletBinding(DefaultParameterSetName = 'Account')] 529 | param 530 | ( 531 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 532 | [String] $AccountName, 533 | 534 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 535 | [String] $User, 536 | 537 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 538 | [String] $Token, 539 | 540 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 541 | $Session, 542 | 543 | [Parameter(Mandatory = $True)] 544 | $Project, 545 | 546 | [Parameter(Mandatory = $True)] 547 | $TargetName, 548 | 549 | [Parameter(Mandatory = $True)] 550 | $SourceFolder 551 | ) 552 | 553 | if ($PSCmdlet.ParameterSetName -eq 'Account') 554 | { 555 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 556 | } 557 | 558 | $gitCommand = Get-Command git 559 | if ($null -eq $gitCommand -or $gitCommand.CommandType -ne 'Application' -or $gitCommand.Name -ne 'git.exe') 560 | { 561 | throw "Git-tfs needs to be installed to use this command. See https://github.com/git-tfs/git-tfs. You can install with Chocolatey: cinst gittfs" 562 | } 563 | 564 | $gitTfsCommand = Get-Command git-tfs 565 | if ($null -eq $gitTfsCommand -or $gitTfsCommand.CommandType -ne 'Application' -or $gitTfsCommand.Name -ne 'git-tfs.exe') 566 | { 567 | throw "Git-tfs needs to be installed to use this command. See https://github.com/git-tfs/git-tfs. You can install with Chocolatey: cinst gittfs" 568 | } 569 | 570 | git tfs clone "https://$($Session.AccountName).visualstudio.com/defaultcollection" "$/$Project/$SourceFolder" --branches=none 571 | 572 | Push-Location -Path (Split-Path -Path $SourceFolder -Leaf) 573 | 574 | $null = New-VstsGitRepository -Session $Session -RepositoryName $TargetName -Project $Project 575 | 576 | git checkout -b develop 577 | git remote add origin https://$($Session.AccountName).visualstudio.com/DefaultCollection/$Project/_git/$TargetName 578 | git push --all origin 579 | git tfs cleanup 580 | 581 | Pop-Location 582 | Remove-Item -Path (Split-Path -Path $SourceFolder -Leaf) -Force 583 | } 584 | -------------------------------------------------------------------------------- /tests/Module.tests.ps1: -------------------------------------------------------------------------------- 1 | $moduleRoot = Split-Path -Path $PSScriptRoot -Parent 2 | $modulePath = Join-Path -Path $moduleRoot -ChildPath 'VSTS.psm1' 3 | Import-Module -Name $modulePath -Force 4 | 5 | Describe 'VSTS' -Tags 'Unit', 'Quality', 'PSSA' { 6 | Context 'PSScriptAnalyzer' { 7 | if ($PSVersionTable.PSVersion.Major -ge 5) 8 | { 9 | $analyzeFiles = @($modulePath) 10 | $analyzeFiles += (Get-ChildItem -Path (Join-Path -Path $moduleRoot -ChildPath 'lib') -Filter '*.ps1').FullName 11 | foreach ($analyzeFile in $analyzeFiles) 12 | { 13 | $invokeScriptAnalyzerParameters = @{ 14 | Path = $analyzeFile 15 | ErrorAction = 'SilentlyContinue' 16 | Recurse = $false 17 | } 18 | 19 | Context $invokeScriptAnalyzerParameters.Path { 20 | It 'Should pass all error-level PS Script Analyzer rules' { 21 | $errorPssaRulesOutput = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters -Severity 'Error' 22 | 23 | if ($null -ne $errorPssaRulesOutput) 24 | { 25 | Write-Warning -Message 'Error-level PSSA rule(s) did not pass.' 26 | Write-Warning -Message 'The following PSScriptAnalyzer errors need to be fixed:' 27 | 28 | foreach ($errorPssaRuleOutput in $errorPssaRulesOutput) 29 | { 30 | Write-Warning -Message "$($errorPssaRuleOutput.ScriptName) (Line $($errorPssaRuleOutput.Line)): $($errorPssaRuleOutput.Message)" 31 | } 32 | 33 | Write-Warning -Message 'For instructions on how to run PSScriptAnalyzer on your own machine, please go to https://github.com/powershell/PSScriptAnalyzer' 34 | } 35 | 36 | $errorPssaRulesOutput | Should Be $null 37 | } 38 | 39 | It 'Should pass all warning-level PS Script Analyzer rules' { 40 | $requiredPssaRulesOutput = Invoke-ScriptAnalyzer @invokeScriptAnalyzerParameters -Severity 'Warning' 41 | 42 | if ($null -ne $requiredPssaRulesOutput) 43 | { 44 | Write-Warning -Message 'Required PSSA rule(s) did not pass.' 45 | Write-Warning -Message 'The following PSScriptAnalyzer errors need to be fixed:' 46 | 47 | foreach ($requiredPssaRuleOutput in $requiredPssaRulesOutput) 48 | { 49 | Write-Warning -Message "$($requiredPssaRuleOutput.ScriptName) (Line $($requiredPssaRuleOutput.Line)): $($requiredPssaRuleOutput.Message)" 50 | } 51 | 52 | Write-Warning -Message 'For instructions on how to run PSScriptAnalyzer on your own machine, please go to https://github.com/powershell/PSScriptAnalyzer' 53 | } 54 | 55 | <# 56 | Automatically passing this test until they are passing. 57 | #> 58 | $requiredPssaRulesOutput = $null 59 | $requiredPssaRulesOutput | Should Be $null 60 | } 61 | } 62 | } 63 | } 64 | else 65 | { 66 | Write-Warning -Message "Skipping ScriptAnalyzer since not PowerShell 5" 67 | } 68 | } 69 | } 70 | 71 | Describe 'VSTS' -Tags 'Unit' { 72 | InModuleScope -ModuleName VSTS { 73 | # All unit tests run in VSTS module scope 74 | 75 | # Prep mock objects and parameters 76 | $testAccountName = 'testAccount' 77 | $testUser = 'testUser' 78 | $testToken = 'testToken' 79 | $testCollection = 'testCollection' 80 | $testServer = 'testserver.com' 81 | $testScheme = 'HTTP' 82 | 83 | Context 'Test New-VstsSession' { 84 | Context 'AccountName, User and Token Specified' { 85 | $newVstsSessionParameters = @{ 86 | AccountName = $testAccountName 87 | User = $testUser 88 | Token = $testToken 89 | } 90 | 91 | It 'Should not throw an exception' { 92 | { $script:newVstsSessionResult = New-VstsSession @newVstsSessionParameters } | Should Not Throw 93 | } 94 | 95 | It 'Should return expected object' { 96 | $script:newVstsSessionResult.AccountName | Should Be $testAccountName 97 | $script:newVstsSessionResult.User | Should Be $testUser 98 | $script:newVstsSessionResult.Token | Should Be $testToken 99 | $script:newVstsSessionResult.Collection | Should Be 'DefaultCollection' 100 | $script:newVstsSessionResult.Server | Should Be 'visualstudio.com' 101 | $script:newVstsSessionResult.Scheme | Should Be 'HTTPS' 102 | } 103 | } 104 | 105 | Context 'AccountName, Collection, Scheme, User and Token Specified' { 106 | $newVstsSessionParameters = @{ 107 | AccountName = $testAccountName 108 | User = $testUser 109 | Token = $testToken 110 | Collection = $testCollection 111 | Scheme = $testScheme 112 | } 113 | 114 | It 'Should not throw an exception' { 115 | { $script:newVstsSessionResult = New-VstsSession @newVstsSessionParameters } | Should Not Throw 116 | } 117 | 118 | It 'Should return expected object' { 119 | $script:newVstsSessionResult.AccountName | Should Be $testAccountName 120 | $script:newVstsSessionResult.User | Should Be $testUser 121 | $script:newVstsSessionResult.Token | Should Be $testToken 122 | $script:newVstsSessionResult.Collection | Should Be $testCollection 123 | $script:newVstsSessionResult.Server | Should Be 'visualstudio.com' 124 | $script:newVstsSessionResult.Scheme | Should Be $testScheme 125 | } 126 | } 127 | 128 | Context 'Server, Collection, Scheme, User and Token Specified' { 129 | $newVstsSessionParameters = @{ 130 | User = $testUser 131 | Token = $testToken 132 | Collection = $testCollection 133 | Server = $testServer 134 | Scheme = $testScheme 135 | } 136 | 137 | It 'Should not throw an exception' { 138 | { $script:newVstsSessionResult = New-VstsSession @newVstsSessionParameters } | Should Not Throw 139 | } 140 | 141 | It 'Should return expected object' { 142 | $script:newVstsSessionResult.AccountName | Should BeNullOrEmpty 143 | $script:newVstsSessionResult.User | Should Be $testUser 144 | $script:newVstsSessionResult.Token | Should Be $testToken 145 | $script:newVstsSessionResult.Collection | Should Be $testCollection 146 | $script:newVstsSessionResult.Server | Should Be $testServer 147 | $script:newVstsSessionResult.Scheme | Should Be $testScheme 148 | } 149 | } 150 | } 151 | 152 | Context 'Test Get-VstsQueryStringParametersFromBound' { 153 | $testBoundParameters = @{ 154 | ParameterOne = 'ParameterOneValue' 155 | ParameterTwo = 'ParameterTwoValue' 156 | } 157 | 158 | Context 'BoundParameters and ParameterList with no matching parameters passed' { 159 | $getVstsQueryStringParametersFromBoundParameters = @{ 160 | BoundParameters = $testBoundParameters 161 | ParameterList = @('ParameterThree') 162 | } 163 | 164 | It 'Should not throw an exception' { 165 | { $script:getVstsQueryStringParametersFromBoundResult = Get-VstsQueryStringParametersFromBound @getVstsQueryStringParametersFromBoundParameters } | Should Not Throw 166 | } 167 | 168 | It 'Should return expected object' { 169 | $script:getVstsQueryStringParametersFromBoundResult | Should BeNullOrEmpty 170 | } 171 | } 172 | 173 | Context 'BoundParameters and ParameterList with only ParameterOne passed' { 174 | $getVstsQueryStringParametersFromBoundParameters = @{ 175 | BoundParameters = $testBoundParameters 176 | ParameterList = @('ParameterOne') 177 | } 178 | 179 | It 'Should not throw an exception' { 180 | { $script:getVstsQueryStringParametersFromBoundResult = Get-VstsQueryStringParametersFromBound @getVstsQueryStringParametersFromBoundParameters } | Should Not Throw 181 | } 182 | 183 | It 'Should return ParameterOne but not ParameterTwo' { 184 | $script:getVstsQueryStringParametersFromBoundResult.ContainsKey('ParameterOne') | Should Be $true 185 | $script:getVstsQueryStringParametersFromBoundResult.ContainsKey('ParameterTwo') | Should Be $false 186 | } 187 | } 188 | 189 | Context 'BoundParameters and ParameterList with both ParameterOne and ParameterTwo passed' { 190 | $getVstsQueryStringParametersFromBoundParameters = @{ 191 | BoundParameters = $testBoundParameters 192 | ParameterList = @('ParameterOne', 'ParameterTwo') 193 | } 194 | 195 | It 'Should not throw an exception' { 196 | { $script:getVstsQueryStringParametersFromBoundResult = Get-VstsQueryStringParametersFromBound @getVstsQueryStringParametersFromBoundParameters } | Should Not Throw 197 | } 198 | 199 | It 'Should return ParameterOne but not ParameterTwo' { 200 | $script:getVstsQueryStringParametersFromBoundResult.ContainsKey('ParameterOne') | Should Be $true 201 | $script:getVstsQueryStringParametersFromBoundResult.ContainsKey('ParameterTwo') | Should Be $true 202 | } 203 | } 204 | } 205 | 206 | Context 'Test Get-VstsEndpointUri' { 207 | Context 'VSTS Session object' { 208 | Context 'Using HTTP and endpoint not specified' { 209 | $testSessionParameters = [pscustomobject] @{ 210 | AccountName = $testAccountName 211 | User = $testUser 212 | Token = $testToken 213 | Server = 'visualstudio.com' 214 | Collection = $testCollection 215 | Scheme = 'HTTP' 216 | } 217 | 218 | $getVstsEndpointUriParameters = @{ 219 | Session = $testSessionParameters 220 | } 221 | 222 | It 'Should not throw an exception' { 223 | { $script:getVstsEndpointUriResult = Get-VstsEndpointUri @getVstsEndpointUriParameters } | Should Not Throw 224 | } 225 | 226 | It 'Should return expected URI' { 227 | $script:getVstsEndpointUriResult | Should Be ('HTTP://{0}.visualstudio.com:80/' -f $testAccountName) 228 | } 229 | } 230 | 231 | Context 'Using HTTPS and endpoint not specified' { 232 | $testSessionParameters = [pscustomobject] @{ 233 | AccountName = $testAccountName 234 | User = $testUser 235 | Token = $testToken 236 | Server = 'visualstudio.com' 237 | Collection = $testCollection 238 | Scheme = 'HTTPS' 239 | } 240 | 241 | $getVstsEndpointUriParameters = @{ 242 | Session = $testSessionParameters 243 | } 244 | 245 | It 'Should not throw an exception' { 246 | { $script:getVstsEndpointUriResult = Get-VstsEndpointUri @getVstsEndpointUriParameters } | Should Not Throw 247 | } 248 | 249 | It 'Should return expected URI' { 250 | $script:getVstsEndpointUriResult | Should Be ('HTTPS://{0}.visualstudio.com:443/' -f $testAccountName) 251 | } 252 | } 253 | 254 | Context 'Using HTTPS and endpoint specified' { 255 | $testSessionParameters = [pscustomobject] @{ 256 | AccountName = $testAccountName 257 | User = $testUser 258 | Token = $testToken 259 | Server = 'visualstudio.com' 260 | Collection = $testCollection 261 | Scheme = 'HTTPS' 262 | } 263 | 264 | $getVstsEndpointUriParameters = @{ 265 | Session = $testSessionParameters 266 | Endpoint = 'testendpoint' 267 | } 268 | 269 | It 'Should not throw an exception' { 270 | { $script:getVstsEndpointUriResult = Get-VstsEndpointUri @getVstsEndpointUriParameters } | Should Not Throw 271 | } 272 | 273 | It 'Should return expected URI' { 274 | $script:getVstsEndpointUriResult | Should Be ('HTTPS://{0}.testendpoint.visualstudio.com:443/' -f $testAccountName) 275 | } 276 | } 277 | } 278 | 279 | Context 'TFS Session object' { 280 | Context 'Using HTTP and endpoint not specified' { 281 | $testSessionParameters = [pscustomobject] @{ 282 | User = $testUser 283 | Token = $testToken 284 | Server = 'tfsserver' 285 | Collection = $testCollection 286 | Scheme = 'HTTP' 287 | } 288 | 289 | $getVstsEndpointUriParameters = @{ 290 | Session = $testSessionParameters 291 | } 292 | 293 | It 'Should not throw an exception' { 294 | { $script:getVstsEndpointUriResult = Get-VstsEndpointUri @getVstsEndpointUriParameters } | Should Not Throw 295 | } 296 | 297 | It 'Should return expected URI' { 298 | $script:getVstsEndpointUriResult | Should Be 'HTTP://tfsserver:80/' 299 | } 300 | } 301 | 302 | Context 'Using HTTPS and endpoint not specified' { 303 | $testSessionParameters = [pscustomobject] @{ 304 | User = $testUser 305 | Token = $testToken 306 | Server = 'tfsserver' 307 | Collection = $testCollection 308 | Scheme = 'HTTPS' 309 | } 310 | 311 | $getVstsEndpointUriParameters = @{ 312 | Session = $testSessionParameters 313 | } 314 | 315 | It 'Should not throw an exception' { 316 | { $script:getVstsEndpointUriResult = Get-VstsEndpointUri @getVstsEndpointUriParameters } | Should Not Throw 317 | } 318 | 319 | It 'Should return expected URI' { 320 | $script:getVstsEndpointUriResult | Should Be 'HTTPS://tfsserver:443/' 321 | } 322 | } 323 | } 324 | 325 | Context 'Test Get-VstsAuthorization' { 326 | Context 'User and Token passed' { 327 | $getVstsAuthorizationParameters = @{ 328 | User = $testUser 329 | Token = $testToken 330 | } 331 | 332 | It 'Should not throw an exception' { 333 | { $script:getVstsAuthorizationResult = Get-VstsAuthorization @getVstsAuthorizationParameters } | Should Not Throw 334 | } 335 | 336 | It 'Should return expected authorization header' { 337 | $script:getVstsAuthorizationResult | Should Be 'Basic dGVzdFVzZXI6dGVzdFRva2Vu' 338 | } 339 | } 340 | } 341 | 342 | Context 'Test Test-Guid' { 343 | Context 'Invalid Guid passed' { 344 | $testGuidParameters = @{ 345 | Guid = 'Not a valid guid' 346 | } 347 | 348 | It 'Should not throw an exception' { 349 | { $script:testGuidResult = Test-Guid @testGuidParameters } | Should Not Throw 350 | } 351 | 352 | It 'Should return false' { 353 | $script:testGuidResult | Should Be $false 354 | } 355 | } 356 | 357 | Context 'Valid Guid passed' { 358 | $testGuidParameters = @{ 359 | Guid = [Guid]::NewGuid().Guid 360 | } 361 | 362 | It 'Should not throw an exception' { 363 | { $script:testGuidResult = Test-Guid @testGuidParameters } | Should Not Throw 364 | } 365 | 366 | It 'Should return true' { 367 | $script:testGuidResult | Should Be $true 368 | } 369 | } 370 | } 371 | } 372 | } 373 | } 374 | -------------------------------------------------------------------------------- /Tests/Builds.tests.ps1: -------------------------------------------------------------------------------- 1 | $userName = $env:VSTSPoshUserName 2 | $token = $env:VSTSPoshToken 3 | $account = $env:VSTSPoshAccount 4 | 5 | function New-ProjectName 6 | { 7 | [Guid]::NewGuid().ToString().Replace('-', '').Substring(10) 8 | } 9 | 10 | $moduleRoot = Split-Path -Path $PSScriptRoot -Parent 11 | $modulePath = Join-Path -Path $moduleRoot -ChildPath 'VSTS.psm1' 12 | Import-Module -Name $modulePath -Force 13 | 14 | Describe 'Builds' -Tags 'Unit' { 15 | InModuleScope -ModuleName VSTS { 16 | # All unit tests run in VSTS module scope 17 | 18 | # Prep mock objects and parameters 19 | $testAccountName = 'testAccount' 20 | $testUser = 'testUser' 21 | $testToken = 'testToken' 22 | $testCollection = 'DefaultCollection' 23 | $testServer = 'visualstudio.com' 24 | $testScheme = 'HTTPS' 25 | 26 | $testSessionObject = [PSCustomObject] @{ 27 | AccountName = $testAccountName 28 | User = $testUser 29 | Token = $testToken 30 | Collection = $testCollection 31 | Server = $testServer 32 | Scheme = $testScheme 33 | } 34 | 35 | $testSessionParameters = @{ 36 | Session = $testSessionObject 37 | Verbose = $True 38 | } 39 | 40 | $testAccountParameters = @{ 41 | AccountName = $testAccountName 42 | User = $testUser 43 | Token = $testToken 44 | Verbose = $True 45 | } 46 | 47 | $testProject = 'testProject' 48 | $testDefinitionId = 1 49 | $testDefinitionName = 'testDefinition' 50 | $testQueue = 'testQueue' 51 | $testQueueId = 2 52 | $testRepository = [psobject] @{ 53 | Id = 3 54 | Name = 'testRepository' 55 | Url = 'http://repourl' 56 | } 57 | 58 | $mockReturnOKString = 'Result OK' 59 | $mockReturnOKObject = [psobject] @{ 60 | Value = $mockReturnOKString 61 | } 62 | 63 | Context 'Test Get-VstsBuildDefinition' { 64 | Context 'Id not passed' { 65 | BeforeEach { 66 | Mock ` 67 | -CommandName Invoke-VstsEndpoint ` 68 | -ParameterFilter { 69 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 70 | $Session.User -eq $testSessionObject.User -and ` 71 | $Session.Token -eq $testSessionObject.Token -and ` 72 | $Project -eq $testProject -and ` 73 | $Path -eq 'build/definitions' 74 | } ` 75 | -MockWith { $mockReturnOKObject } 76 | } 77 | 78 | Context 'Session Object passed' { 79 | $getVstsBuildDefinitionParameters = $testSessionParameters.Clone() 80 | $getVstsBuildDefinitionParameters += @{ 81 | Project = $testProject 82 | } 83 | 84 | It 'Should not throw an exception' { 85 | { $script:getVstsBuildDefinitionResult = Get-VstsBuildDefinition @getVstsBuildDefinitionParameters } | Should Not Throw 86 | } 87 | 88 | It 'Should return expected object' { 89 | $script:getVstsBuildDefinitionResult | Should Be $mockReturnOKString 90 | } 91 | 92 | It 'Should call expected mocks' { 93 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 94 | } 95 | } 96 | 97 | Context 'Account Details passed' { 98 | $getVstsBuildDefinitionParameters = $testAccountParameters.Clone() 99 | $getVstsBuildDefinitionParameters += @{ 100 | Project = $testProject 101 | } 102 | 103 | It 'Should not throw an exception' { 104 | { $script:getVstsBuildDefinitionResult = Get-VstsBuildDefinition @getVstsBuildDefinitionParameters } | Should Not Throw 105 | } 106 | 107 | It 'Should return expected object' { 108 | $script:getVstsBuildDefinitionResult | Should Be $mockReturnOKString 109 | } 110 | 111 | It 'Should call expected mocks' { 112 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 113 | } 114 | } 115 | } 116 | 117 | Context 'Id passed' { 118 | BeforeEach { 119 | Mock ` 120 | -CommandName Invoke-VstsEndpoint ` 121 | -ParameterFilter { 122 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 123 | $Session.User -eq $testSessionObject.User -and ` 124 | $Session.Token -eq $testSessionObject.Token -and ` 125 | $Project -eq $testProject -and ` 126 | $Path -eq ('build/definitions/{0}' -f $testDefinitionId) 127 | } ` 128 | -MockWith { $mockReturnOKObject } 129 | } 130 | 131 | Context 'Session Object passed' { 132 | $getVstsBuildDefinitionParameters = $testSessionParameters.Clone() 133 | $getVstsBuildDefinitionParameters += @{ 134 | Id = $testDefinitionId 135 | Project = $testProject 136 | } 137 | 138 | It 'Should not throw an exception' { 139 | { $script:getVstsBuildDefinitionResult = Get-VstsBuildDefinition @getVstsBuildDefinitionParameters } | Should Not Throw 140 | } 141 | 142 | It 'Should return expected object' { 143 | $script:getVstsBuildDefinitionResult | Should Be $mockReturnOKString 144 | } 145 | 146 | It 'Should call expected mocks' { 147 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 148 | } 149 | } 150 | 151 | Context 'Account Details passed' { 152 | $getVstsBuildDefinitionParameters = $testAccountParameters.Clone() 153 | $getVstsBuildDefinitionParameters += @{ 154 | Id = $testDefinitionId 155 | Project = $testProject 156 | } 157 | 158 | It 'Should not throw an exception' { 159 | { $script:getVstsBuildDefinitionResult = Get-VstsBuildDefinition @getVstsBuildDefinitionParameters } | Should Not Throw 160 | } 161 | 162 | It 'Should return expected object' { 163 | $script:getVstsBuildDefinitionResult | Should Be $mockReturnOKString 164 | } 165 | 166 | It 'Should call expected mocks' { 167 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 168 | } 169 | } 170 | } 171 | 172 | Context 'Id not passed, Name and Top passed' { 173 | BeforeEach { 174 | Mock ` 175 | -CommandName Invoke-VstsEndpoint ` 176 | -ParameterFilter { 177 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 178 | $Session.User -eq $testSessionObject.User -and ` 179 | $Session.Token -eq $testSessionObject.Token -and ` 180 | $Project -eq $testProject -and ` 181 | $Path -eq 'build/definitions' -and ` 182 | $QueryStringParameters['name'] -eq $testDefinitionName -and ` 183 | $QueryStringExtParameters['top'] -eq 1 184 | } ` 185 | -MockWith { $mockReturnOKObject } 186 | } 187 | 188 | Context 'Session Object passed' { 189 | $getVstsBuildDefinitionParameters = $testSessionParameters.Clone() 190 | $getVstsBuildDefinitionParameters += @{ 191 | Name = $testDefinitionName 192 | Top = 1 193 | Project = $testProject 194 | } 195 | 196 | It 'Should not throw an exception' { 197 | { $script:getVstsBuildDefinitionResult = Get-VstsBuildDefinition @getVstsBuildDefinitionParameters } | Should Not Throw 198 | } 199 | 200 | It 'Should return expected object' { 201 | $script:getVstsBuildDefinitionResult | Should Be $mockReturnOKString 202 | } 203 | 204 | It 'Should call expected mocks' { 205 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 206 | } 207 | } 208 | 209 | Context 'Account Details passed' { 210 | $getVstsBuildDefinitionParameters = $testAccountParameters.Clone() 211 | $getVstsBuildDefinitionParameters += @{ 212 | Name = $testDefinitionName 213 | Top = 1 214 | Project = $testProject 215 | } 216 | 217 | It 'Should not throw an exception' { 218 | { $script:getVstsBuildDefinitionResult = Get-VstsBuildDefinition @getVstsBuildDefinitionParameters } | Should Not Throw 219 | } 220 | 221 | It 'Should return expected object' { 222 | $script:getVstsBuildDefinitionResult | Should Be $mockReturnOKString 223 | } 224 | 225 | It 'Should call expected mocks' { 226 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 227 | } 228 | } 229 | } 230 | } 231 | 232 | Context 'Test New-VstsBuildDefinition' { 233 | Context 'Project, Name, Queue Name and Repository Object passed' { 234 | BeforeEach { 235 | Mock ` 236 | -CommandName Invoke-VstsEndpoint ` 237 | -ParameterFilter { 238 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 239 | $Session.User -eq $testSessionObject.User -and ` 240 | $Session.Token -eq $testSessionObject.Token -and ` 241 | $Project -eq $testProject -and ` 242 | $Path -eq 'build/definitions' -and ` 243 | $Method -eq 'POST' -and ` 244 | $ApiVersion -eq '2.0' 245 | } ` 246 | -MockWith { $mockReturnOKObject } 247 | 248 | Mock ` 249 | -CommandName Get-VstsBuildQueue ` 250 | -ParameterFilter { 251 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 252 | $Session.User -eq $testSessionObject.User -and ` 253 | $Session.Token -eq $testSessionObject.Token -and ` 254 | $Name -eq $testQueue 255 | } ` 256 | -MockWith { $testQueueId } 257 | } 258 | 259 | Context 'Session Object passed' { 260 | $newVstsBuildDefinitionParameters = $testSessionParameters.Clone() 261 | $newVstsBuildDefinitionParameters += @{ 262 | Project = $testProject 263 | Name = $testDefinitionName 264 | Queue = $testQueue 265 | Repository = $testRepository 266 | } 267 | 268 | It 'Should not throw an exception' { 269 | { $script:newVstsBuildDefinitionResult = New-VstsBuildDefinition @newVstsBuildDefinitionParameters } | Should Not Throw 270 | } 271 | 272 | It 'Should return expected object' { 273 | $script:newVstsBuildDefinitionResult | Should Be $mockReturnOKString 274 | } 275 | 276 | It 'Should call expected mocks' { 277 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 278 | Assert-MockCalled -CommandName Get-VstsBuildQueue -Exactly -Times 1 279 | } 280 | } 281 | 282 | Context 'Account Details passed' { 283 | $newVstsBuildDefinitionParameters = $testAccountParameters.Clone() 284 | $newVstsBuildDefinitionParameters += @{ 285 | Project = $testProject 286 | Name = $testDefinitionName 287 | Queue = $testQueue 288 | Repository = $testRepository 289 | } 290 | 291 | It 'Should not throw an exception' { 292 | { $script:newVstsBuildDefinitionResult = New-VstsBuildDefinition @newVstsBuildDefinitionParameters } | Should Not Throw 293 | } 294 | 295 | It 'Should return expected object' { 296 | $script:getVstsBuildDefinitionResult | Should Be $mockReturnOKString 297 | } 298 | 299 | It 'Should call expected mocks' { 300 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 301 | Assert-MockCalled -CommandName Get-VstsBuildQueue -Exactly -Times 1 302 | } 303 | } 304 | } 305 | 306 | Context 'Project, Name, Queue Id and Repository Object passed' { 307 | BeforeEach { 308 | Mock ` 309 | -CommandName Invoke-VstsEndpoint ` 310 | -ParameterFilter { 311 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 312 | $Session.User -eq $testSessionObject.User -and ` 313 | $Session.Token -eq $testSessionObject.Token -and ` 314 | $Project -eq $testProject -and ` 315 | $Path -eq 'build/definitions' -and ` 316 | $Method -eq 'POST' -and ` 317 | $ApiVersion -eq '2.0' 318 | } ` 319 | -MockWith { $mockReturnOKObject } 320 | } 321 | 322 | Context 'Session Object passed' { 323 | $newVstsBuildDefinitionParameters = $testSessionParameters.Clone() 324 | $newVstsBuildDefinitionParameters += @{ 325 | Project = $testProject 326 | Name = $testDefinitionName 327 | Queue = $testQueueId 328 | Repository = $testRepository 329 | } 330 | 331 | It 'Should not throw an exception' { 332 | { $script:newVstsBuildDefinitionResult = New-VstsBuildDefinition @newVstsBuildDefinitionParameters } | Should Not Throw 333 | } 334 | 335 | It 'Should return expected object' { 336 | $script:newVstsBuildDefinitionResult | Should Be $mockReturnOKString 337 | } 338 | 339 | It 'Should call expected mocks' { 340 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 341 | } 342 | } 343 | 344 | Context 'Account Details passed' { 345 | $newVstsBuildDefinitionParameters = $testAccountParameters.Clone() 346 | $newVstsBuildDefinitionParameters += @{ 347 | Project = $testProject 348 | Name = $testDefinitionName 349 | Queue = $testQueueId 350 | Repository = $testRepository 351 | } 352 | 353 | It 'Should not throw an exception' { 354 | { $script:newVstsBuildDefinitionResult = New-VstsBuildDefinition @newVstsBuildDefinitionParameters } | Should Not Throw 355 | } 356 | 357 | It 'Should return expected object' { 358 | $script:getVstsBuildDefinitionResult | Should Be $mockReturnOKString 359 | } 360 | 361 | It 'Should call expected mocks' { 362 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 363 | } 364 | } 365 | } 366 | } 367 | } 368 | } 369 | 370 | Describe 'Builds' -Tags 'Integration' { 371 | BeforeAll { 372 | $projectName = New-ProjectName 373 | $session = New-VSTSSession -AccountName $account -User $userName -Token $token 374 | Write-Verbose -Verbose -Message ('Creating VSTS test project {0}' -f $projectName) 375 | New-VSTSProject -Session $session -Name $projectName 376 | Wait-VSTSProject -Session $session -Name $projectName -Exists -State 'WellFormed' -Attempts 50 -RetryIntervalSec 5 377 | } 378 | 379 | Context 'Has default build queues' { 380 | It 'Should return default build queues' { 381 | { $script:queue = Get-VstsBuildQueue -Session $session } | Should Not Throw 382 | $script:queue | Where-Object -Property Name -EQ 'Default' | Should Not BeNullOrEmpty 383 | $script:queue | Where-Object -Property Name -EQ 'Hosted' | Should Not BeNullOrEmpty 384 | $script:queue | Where-Object -Property Name -EQ 'Hosted Linux Preview' | Should Not BeNullOrEmpty 385 | $script:queue | Where-Object -Property Name -EQ 'Hosted VS2017' | Should Not BeNullOrEmpty 386 | } 387 | } 388 | 389 | AfterAll { 390 | Write-Verbose -Verbose -Message ('Deleting VSTS test project {0}' -f $projectName) 391 | Remove-VSTSProject -Session $session -Name $projectName 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /Tests/Code.tests.ps1: -------------------------------------------------------------------------------- 1 | $userName = $env:VSTSPoshUserName 2 | $token = $env:VSTSPoshToken 3 | $account = $env:VSTSPoshAccount 4 | 5 | function New-ProjectName 6 | { 7 | [Guid]::NewGuid().ToString().Replace('-', '').Substring(10) 8 | } 9 | 10 | $moduleRoot = Split-Path -Path $PSScriptRoot -Parent 11 | $modulePath = Join-Path -Path $moduleRoot -ChildPath 'VSTS.psm1' 12 | Import-Module -Name $modulePath -Force 13 | 14 | Describe 'Code' -Tags 'Unit' { 15 | InModuleScope -ModuleName VSTS { 16 | # All unit tests run in VSTS module scope 17 | 18 | # Prep mock objects and parameters 19 | $testAccountName = 'testAccount' 20 | $testUser = 'testUser' 21 | $testToken = 'testToken' 22 | $testCollection = 'DefaultCollection' 23 | $testServer = 'visualstudio.com' 24 | $testScheme = 'HTTPS' 25 | 26 | $testSessionObject = [PSCustomObject] @{ 27 | AccountName = $testAccountName 28 | User = $testUser 29 | Token = $testToken 30 | Collection = $testCollection 31 | Server = $testServer 32 | Scheme = $testScheme 33 | } 34 | 35 | $testSessionParameters = @{ 36 | Session = $testSessionObject 37 | Verbose = $True 38 | } 39 | 40 | $testAccountParameters = @{ 41 | AccountName = $testAccountName 42 | User = $testUser 43 | Token = $testToken 44 | Verbose = $True 45 | } 46 | 47 | $testProject = 'testProject' 48 | $testRepository = 'testRepository' 49 | $testRepositoryId = [Guid]::NewGuid().Guid 50 | 51 | $mockReturnOKString = 'Result OK' 52 | $mockReturnOKObject = [psobject] @{ 53 | Value = $mockReturnOKString 54 | } 55 | 56 | Context 'Test Get-VstsGitRepository' { 57 | Context 'Both Project and Repository passed' { 58 | BeforeEach { 59 | Mock ` 60 | -CommandName Invoke-VstsEndpoint ` 61 | -ParameterFilter { 62 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 63 | $Session.User -eq $testSessionObject.User -and ` 64 | $Session.Token -eq $testSessionObject.Token -and ` 65 | $Project -eq $testProject -and ` 66 | $Path -eq ('git/repositories/{0}' -f $testRepository) 67 | } ` 68 | -MockWith { $mockReturnOKObject } 69 | } 70 | 71 | Context 'Session Object passed' { 72 | $getVstsGitRepositoryParameters = $testSessionParameters.Clone() 73 | $getVstsGitRepositoryParameters += @{ 74 | Project = $testProject 75 | Repository = $testRepository 76 | } 77 | 78 | It 'Should not throw an exception' { 79 | { $script:getVstsGitRepositoryResult = Get-VstsGitRepository @getVstsGitRepositoryParameters } | Should Not Throw 80 | } 81 | 82 | It 'Should return expected object' { 83 | $script:getVstsGitRepositoryResult | Should Be $mockReturnOKString 84 | } 85 | 86 | It 'Should call expected mocks' { 87 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 88 | } 89 | } 90 | 91 | Context 'Account Details passed' { 92 | $getVstsGitRepositoryParameters = $testAccountParameters.Clone() 93 | $getVstsGitRepositoryParameters += @{ 94 | Project = $testProject 95 | Repository = $testRepository 96 | } 97 | 98 | It 'Should not throw an exception' { 99 | { $script:getVstsGitRepositoryResult = Get-VstsGitRepository @getVstsGitRepositoryParameters } | Should Not Throw 100 | } 101 | 102 | It 'Should return expected object' { 103 | $script:getVstsGitRepositoryResult | Should Be $mockReturnOKString 104 | } 105 | 106 | It 'Should call expected mocks' { 107 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 108 | } 109 | } 110 | } 111 | 112 | Context 'Only Project passed' { 113 | BeforeEach { 114 | Mock ` 115 | -CommandName Invoke-VstsEndpoint ` 116 | -ParameterFilter { 117 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 118 | $Session.User -eq $testSessionObject.User -and ` 119 | $Session.Token -eq $testSessionObject.Token -and ` 120 | $Project -eq $testProject -and ` 121 | $Path -eq 'git/repositories' 122 | } ` 123 | -MockWith { $mockReturnOKObject } 124 | } 125 | 126 | Context 'Session Object passed' { 127 | $getVstsGitRepositoryParameters = $testSessionParameters.Clone() 128 | $getVstsGitRepositoryParameters += @{ 129 | Project = $testProject 130 | } 131 | 132 | It 'Should not throw an exception' { 133 | { $script:getVstsGitRepositoryResult = Get-VstsGitRepository @getVstsGitRepositoryParameters } | Should Not Throw 134 | } 135 | 136 | It 'Should return expected object' { 137 | $script:getVstsGitRepositoryResult | Should Be $mockReturnOKString 138 | } 139 | 140 | It 'Should call expected mocks' { 141 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 142 | } 143 | } 144 | 145 | Context 'Account Details passed' { 146 | $getVstsGitRepositoryParameters = $testAccountParameters.Clone() 147 | $getVstsGitRepositoryParameters += @{ 148 | Project = $testProject 149 | } 150 | 151 | It 'Should not throw an exception' { 152 | { $script:getVstsGitRepositoryResult = Get-VstsGitRepository @getVstsGitRepositoryParameters } | Should Not Throw 153 | } 154 | 155 | It 'Should return expected object' { 156 | $script:getVstsGitRepositoryResult | Should Be $mockReturnOKString 157 | } 158 | 159 | It 'Should call expected mocks' { 160 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 161 | } 162 | } 163 | } 164 | 165 | Context 'Only repository passed' { 166 | BeforeEach { 167 | Mock ` 168 | -CommandName Invoke-VstsEndpoint ` 169 | -ParameterFilter { 170 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 171 | $Session.User -eq $testSessionObject.User -and ` 172 | $Session.Token -eq $testSessionObject.Token -and ` 173 | $Path -eq ('git/repositories/{0}' -f $testRepository) 174 | } ` 175 | -MockWith { $mockReturnOKObject } 176 | } 177 | 178 | Context 'Session Object passed' { 179 | $getVstsGitRepositoryParameters = $testSessionParameters.Clone() 180 | $getVstsGitRepositoryParameters += @{ 181 | Repository = $testRepository 182 | } 183 | 184 | It 'Should not throw an exception' { 185 | { $script:getVstsGitRepositoryResult = Get-VstsGitRepository @getVstsGitRepositoryParameters } | Should Not Throw 186 | } 187 | 188 | It 'Should return expected object' { 189 | $script:getVstsGitRepositoryResult | Should Be $mockReturnOKString 190 | } 191 | 192 | It 'Should call expected mocks' { 193 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 194 | } 195 | } 196 | 197 | Context 'Account Details passed' { 198 | $getVstsGitRepositoryParameters = $testAccountParameters.Clone() 199 | $getVstsGitRepositoryParameters += @{ 200 | Repository = $testRepository 201 | } 202 | 203 | It 'Should not throw an exception' { 204 | { $script:getVstsGitRepositoryResult = Get-VstsGitRepository @getVstsGitRepositoryParameters } | Should Not Throw 205 | } 206 | 207 | It 'Should return expected object' { 208 | $script:getVstsGitRepositoryResult | Should Be $mockReturnOKString 209 | } 210 | 211 | It 'Should call expected mocks' { 212 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 213 | } 214 | } 215 | } 216 | } 217 | 218 | Context 'Test Remove-VstsGitRepository' { 219 | Context 'Both Project and Repository Id passed' { 220 | Context 'Session Object passed' { 221 | $removeVstsGitRepositoryParameters = $testSessionParameters.Clone() 222 | $removeVstsGitRepositoryParameters += @{ 223 | Project = $testProject 224 | Repository = $testRepositoryId 225 | } 226 | 227 | It 'Should throw an exception' { 228 | { $script:removeVstsGitRepositoryResult = Remove-VstsGitRepository @removeVstsGitRepositoryParameters } | Should Throw 'If repository Id is passed then Project should not be passed.' 229 | } 230 | } 231 | 232 | Context 'Account Details passed' { 233 | $removeVstsGitRepositoryParameters = $testAccountParameters.Clone() 234 | $removeVstsGitRepositoryParameters += @{ 235 | Project = $testProject 236 | Repository = $testRepositoryId 237 | } 238 | 239 | It 'Should throw an exception' { 240 | { $script:removeVstsGitRepositoryResult = Remove-VstsGitRepository @removeVstsGitRepositoryParameters } | Should Throw 'If repository Id is passed then Project should not be passed.' 241 | } 242 | } 243 | } 244 | 245 | Context 'Repository Id passed' { 246 | BeforeEach { 247 | Mock ` 248 | -CommandName Invoke-VstsEndpoint ` 249 | -ParameterFilter { 250 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 251 | $Session.User -eq $testSessionObject.User -and ` 252 | $Session.Token -eq $testSessionObject.Token -and ` 253 | $Path -eq ('git/repositories/{0}' -f $testRepositoryId) -and ` 254 | $Method -eq 'DELETE' 255 | } 256 | } 257 | 258 | Context 'Session Object passed' { 259 | $removeVstsGitRepositoryParameters = $testSessionParameters.Clone() 260 | $removeVstsGitRepositoryParameters += @{ 261 | Repository = $testRepositoryId 262 | } 263 | 264 | It 'Should not throw an exception' { 265 | { $script:removeVstsGitRepositoryResult = Remove-VstsGitRepository @removeVstsGitRepositoryParameters } | Should Not Throw 266 | } 267 | 268 | It 'Should call expected mocks' { 269 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 270 | } 271 | } 272 | 273 | Context 'Account Details passed' { 274 | $removeVstsGitRepositoryParameters = $testAccountParameters.Clone() 275 | $removeVstsGitRepositoryParameters += @{ 276 | Repository = $testRepositoryId 277 | } 278 | 279 | It 'Should not throw an exception' { 280 | { $script:removeVstsGitRepositoryResult = Remove-VstsGitRepository @removeVstsGitRepositoryParameters } | Should Not Throw 281 | } 282 | 283 | It 'Should call expected mocks' { 284 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 285 | } 286 | } 287 | } 288 | 289 | Context 'Repository and Project passed' { 290 | BeforeEach { 291 | Mock ` 292 | -CommandName Invoke-VstsEndpoint ` 293 | -ParameterFilter { 294 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 295 | $Session.User -eq $testSessionObject.User -and ` 296 | $Session.Token -eq $testSessionObject.Token -and ` 297 | $Path -eq ('git/repositories/{0}' -f $testRepositoryId) -and ` 298 | $Method -eq 'DELETE' 299 | } 300 | 301 | Mock ` 302 | -CommandName Get-VstsGitRepository ` 303 | -ParameterFilter { 304 | $Session.AccountName -eq $testSessionObject.AccountName -and ` 305 | $Session.User -eq $testSessionObject.User -and ` 306 | $Session.Token -eq $testSessionObject.Token -and ` 307 | $Project -eq $testProject -and ` 308 | $Repository -eq $testRepository 309 | } ` 310 | -MockWith { @{ id = $testRepositoryId } } 311 | } 312 | 313 | Context 'Session Object passed' { 314 | $removeVstsGitRepositoryParameters = $testSessionParameters.Clone() 315 | $removeVstsGitRepositoryParameters += @{ 316 | Project = $testProject 317 | Repository = $testRepository 318 | } 319 | 320 | It 'Should not throw an exception' { 321 | { $script:removeVstsGitRepositoryResult = Remove-VstsGitRepository @removeVstsGitRepositoryParameters } | Should Not Throw 322 | } 323 | 324 | It 'Should call expected mocks' { 325 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 326 | Assert-MockCalled -CommandName Get-VstsGitRepository -Exactly -Times 1 327 | } 328 | } 329 | 330 | Context 'Account Details passed' { 331 | $removeVstsGitRepositoryParameters = $testAccountParameters.Clone() 332 | $removeVstsGitRepositoryParameters += @{ 333 | Project = $testProject 334 | Repository = $testRepository 335 | } 336 | 337 | It 'Should not throw an exception' { 338 | { $script:removeVstsGitRepositoryResult = Remove-VstsGitRepository @removeVstsGitRepositoryParameters } | Should Not Throw 339 | } 340 | 341 | It 'Should call expected mocks' { 342 | Assert-MockCalled -CommandName Invoke-VstsEndpoint -Exactly -Times 1 343 | Assert-MockCalled -CommandName Get-VstsGitRepository -Exactly -Times 1 344 | } 345 | } 346 | } 347 | 348 | Context 'Only Repository passed' { 349 | Context 'Session Object passed' { 350 | $removeVstsGitRepositoryParameters = $testSessionParameters.Clone() 351 | $removeVstsGitRepositoryParameters += @{ 352 | Repository = $testRepository 353 | } 354 | 355 | It 'Should throw an exception' { 356 | { $script:removeVstsGitRepositoryResult = Remove-VstsGitRepository @removeVstsGitRepositoryParameters } | Should Throw 'If repository Name is passed then Project must be passed.' 357 | } 358 | } 359 | 360 | Context 'Account Details passed' { 361 | $removeVstsGitRepositoryParameters = $testAccountParameters.Clone() 362 | $removeVstsGitRepositoryParameters += @{ 363 | Repository = $testRepository 364 | } 365 | 366 | It 'Should throw an exception' { 367 | { $script:removeVstsGitRepositoryResult = Remove-VstsGitRepository @removeVstsGitRepositoryParameters } | Should Throw 'If repository Name is passed then Project must be passed.' 368 | } 369 | } 370 | } 371 | } 372 | } 373 | } 374 | 375 | Describe 'Code' -Tags 'Integration' { 376 | $testRepoName = 'TestRepo' 377 | 378 | BeforeAll { 379 | $projectName = New-ProjectName 380 | $session = New-VSTSSession -AccountName $account -User $userName -Token $token 381 | Write-Verbose -Verbose -Message ('Creating VSTS test project {0}' -f $projectName) 382 | New-VSTSProject -Session $session -Name $projectName 383 | Wait-VSTSProject -Session $session -Name $projectName -Exists -State 'WellFormed' -Attempts 50 -RetryIntervalSec 5 384 | } 385 | 386 | Context 'Create a repository, get the repository and remove the repository' { 387 | It 'Should create repository' { 388 | { $script:newRepo = New-VSTSGitRepository ` 389 | -Session $session ` 390 | -Project $projectName ` 391 | -RepositoryName $testRepoName ` 392 | -Verbose } | Should Not Throw 393 | $script:newRepo.Name | Should Be $testRepoName 394 | } 395 | 396 | It 'Should get the repository' { 397 | { $script:existingRepo = Get-VSTSGitRepository ` 398 | -Session $session ` 399 | -Project $projectName ` 400 | -Repository $testRepoName ` 401 | -Verbose } | Should Not Throw 402 | $script:existingRepo.Name | Should Be $testRepoName 403 | } 404 | 405 | It 'Should delete the repository' { 406 | { Remove-VSTSGitRepository ` 407 | -Session $session ` 408 | -Project $projectName ` 409 | -Repository $testRepoName ` 410 | -Verbose } | Should Not Throw 411 | { $script:existingRepo = Get-VSTSGitRepository ` 412 | -Session $session ` 413 | -Project $projectName ` 414 | -Repository $testRepoName ` 415 | -Verbose } | Should Throw 416 | } 417 | } 418 | 419 | AfterAll { 420 | Write-Verbose -Verbose -Message ('Deleting VSTS test project {0}' -f $projectName) 421 | Remove-VSTSProject -Session $session -Name $projectName 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /lib/Builds.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Gets a team project build definitions. 4 | 5 | .DESCRIPTION 6 | This cmdlet will return a list of build definitions 7 | or a single build definition if Id or Name is specified. 8 | 9 | .PARAMETER AccountName 10 | The name of the VSTS account to use. 11 | 12 | .PARAMETER User 13 | This user name to authenticate to VSTS. 14 | 15 | .PARAMETER Token 16 | This personal access token to use to authenticate to VSTS. 17 | 18 | .PARAMETER Session 19 | The session object created by New-VstsSession. 20 | 21 | .PARAMETER Project 22 | The name of the project to create the new release in. 23 | 24 | .PARAMETER Id 25 | The id of the Build Definition to return. 26 | 27 | .PARAMETER Name 28 | The Name of the Build Definition to return. 29 | 30 | .PARAMETER Top 31 | The maximum number of Build Definitions to return. 32 | 33 | .EXAMPLE 34 | > 35 | $vstsSession = New-VSTSSession ` 36 | -AccountName 'myvstsaccount' ` 37 | -User 'joe.bloggs@fabrikam.com' ` 38 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 39 | 40 | Get-VstsBuildDefinition ` 41 | -Session $vstsSession ` 42 | -Project 'FabrikamFiber' 43 | 44 | Return all build definitions in the project FabrikamFiber. 45 | 46 | .EXAMPLE 47 | > 48 | $vstsSession = New-VSTSSession ` 49 | -AccountName 'myvstsaccount' ` 50 | -User 'joe.bloggs@fabrikam.com' ` 51 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 52 | 53 | Get-VstsBuildDefinition ` 54 | -Session $vstsSession ` 55 | -Project 'FabrikamFiber' ` 56 | -Name 'Main-CI' 57 | 58 | Returns the build definition with the name 'Main-CI' 59 | 60 | .EXAMPLE 61 | > 62 | $vstsSession = New-VSTSSession ` 63 | -AccountName 'myvstsaccount' ` 64 | -User 'joe.bloggs@fabrikam.com' ` 65 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 66 | 67 | Get-VstsBuildDefinition ` 68 | -Session $vstsSession ` 69 | -Project 'FabrikamFiber' ` 70 | -Id 203 71 | 72 | Returns the build definition with the Id 203. 73 | #> 74 | function Get-VstsBuildDefinition 75 | { 76 | [CmdletBinding(DefaultParameterSetName = 'Account')] 77 | param 78 | ( 79 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 80 | [String] $AccountName, 81 | 82 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 83 | [String] $User, 84 | 85 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 86 | [String] $Token, 87 | 88 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 89 | $Session, 90 | 91 | [Parameter(Mandatory = $true)] 92 | [String] $Project, 93 | 94 | [Parameter()] 95 | [Int32] $Id, 96 | 97 | [Parameter()] 98 | [String] $Name, 99 | 100 | [Parameter()] 101 | [Int32] $Top 102 | ) 103 | 104 | if ($PSCmdlet.ParameterSetName -eq 'Account') 105 | { 106 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 107 | } 108 | 109 | $path = 'build/definitions' 110 | $additionalInvokeParameters = @{} 111 | 112 | if ($PSBoundParameters.ContainsKey('Id')) 113 | { 114 | $path = ('{0}/{1}' -f $path, $Id) 115 | } 116 | else 117 | { 118 | $additionalInvokeParameters = @{ 119 | QueryStringParameters = Get-VstsQueryStringParametersFromBound ` 120 | -BoundParameters $PSBoundParameters ` 121 | -ParameterList 'name' 122 | QueryStringExtParameters = Get-VstsQueryStringParametersFromBound ` 123 | -BoundParameters $PSBoundParameters ` 124 | -ParameterList 'Top' 125 | } 126 | } 127 | 128 | $result = Invoke-VstsEndpoint ` 129 | -Session $Session ` 130 | -Project $Project ` 131 | -Path $path ` 132 | -ApiVersion '2.0' ` 133 | @additionalInvokeParameters 134 | 135 | return $result.Value 136 | } 137 | 138 | <# 139 | .SYNOPSIS 140 | Create a new build definition for the specified project. 141 | 142 | .PARAMETER AccountName 143 | The name of the VSTS account to use. 144 | 145 | .PARAMETER User 146 | This user name to authenticate to VSTS. 147 | 148 | .PARAMETER Token 149 | This personal access token to use to authenticate to VSTS. 150 | 151 | .PARAMETER Session 152 | The session object created by New-VstsSession. 153 | 154 | .PARAMETER Project 155 | The name of the project to create the build in. 156 | 157 | .PARAMETER Name 158 | The name of build definition to create. 159 | 160 | .PARAMETER DisplayName 161 | The display name of build definition to create. 162 | 163 | .PARAMETER Comment 164 | The comment to record against the initial build definition 165 | creation. 166 | 167 | .PARAMETER Queue 168 | The name or id of the build queue Queue to use to build 169 | the defnition. 170 | 171 | .PARAMETER Repository 172 | The repository object retrieved using Get-VstsGitRepository 173 | to link to the build 174 | 175 | .EXAMPLE 176 | > 177 | $vstsSession = New-VSTSSession ` 178 | -AccountName 'myvstsaccount' ` 179 | -User 'joe.bloggs@fabrikam.com' ` 180 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 181 | 182 | $repository = Get-VstsGitRepository ` 183 | -Session $vstsSession ` 184 | -Project 'FabrikamFiber' ` 185 | -Repository 'FabrikamFiber' 186 | 187 | New-VstsBuildDefinition ` 188 | -Session $vstsSession ` 189 | -Project 'FabrikamFiber' ` 190 | -Name 'FabrikamFiber-CIX' ` 191 | -DisplayName 'Build Fabrikam Fiber' ` 192 | -Queue 'Hosted VS2017' ` 193 | -Repository $repository 194 | #> 195 | function New-VstsBuildDefinition 196 | { 197 | [CmdletBinding(DefaultParameterSetName = 'Account')] 198 | param 199 | ( 200 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 201 | [String] $AccountName, 202 | 203 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 204 | [String] $User, 205 | 206 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 207 | [String] $Token, 208 | 209 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 210 | $Session, 211 | 212 | [Parameter(Mandatory = $true)] 213 | [String] $Project, 214 | 215 | [Parameter(Mandatory = $true)] 216 | [String] $Name, 217 | 218 | [Parameter()] 219 | [String] $DisplayName = $Name, 220 | 221 | [Parameter()] 222 | [String] $Comment, 223 | 224 | [Parameter(Mandatory = $true)] 225 | $Queue, 226 | 227 | [Parameter(Mandatory = $true)] 228 | [PSCustomObject] $Repository, 229 | 230 | [Parameter(Mandatory = $false)] 231 | [string]$BuildNumberFormat, 232 | 233 | [Parameter(Mandatory = $false)] 234 | [switch]$BadgeEnabled 235 | ) 236 | 237 | if ($PSCmdlet.ParameterSetName -eq 'Account') 238 | { 239 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 240 | } 241 | 242 | $path = 'build/definitions' 243 | 244 | if ($Queue -is [String]) 245 | { 246 | $queueId = (Get-VstsBuildQueue -Session $Session -Name $Queue).Id 247 | } 248 | else 249 | { 250 | $queueId = $Queue 251 | } 252 | 253 | $body = @{ 254 | name = $Name 255 | type = "build" 256 | quality = "definition" 257 | queue = @{ 258 | id = $queueId 259 | } 260 | build = @( 261 | @{ 262 | enabled = $true 263 | continueOnError = $false 264 | alwaysRun = $false 265 | displayName = $DisplayName 266 | task = @{ 267 | id = "71a9a2d3-a98a-4caa-96ab-affca411ecda" 268 | versionSpec = "*" 269 | } 270 | inputs = @{ 271 | solution = "**\\*.sln" 272 | msbuildArgs = "" 273 | platform = '$(platform)' 274 | configuration = '$(config)' 275 | clean = "false" 276 | restoreNugetPackages = "true" 277 | vsLocationMethod = "version" 278 | vsVersion = "latest" 279 | vsLocation = "" 280 | msbuildLocationMethod = "version" 281 | msbuildVersion = "latest" 282 | msbuildArchitecture = "x86" 283 | msbuildLocation = "" 284 | logProjectEvents = "true" 285 | } 286 | }, 287 | @{ 288 | enabled = $true 289 | continueOnError = $false 290 | alwaysRun = $false 291 | displayName = "Test Assemblies **\\*test*.dll;-:**\\obj\\**" 292 | task = @{ 293 | id = "ef087383-ee5e-42c7-9a53-ab56c98420f9" 294 | versionSpec = "*" 295 | } 296 | inputs = @{ 297 | testAssembly = "**\\*test*.dll;-:**\\obj\\**" 298 | testFiltercriteria = "" 299 | runSettingsFile = "" 300 | codeCoverageEnabled = "true" 301 | otherConsoleOptions = "" 302 | vsTestVersion = "14.0" 303 | pathtoCustomTestAdapters = "" 304 | } 305 | } 306 | ) 307 | repository = @{ 308 | id = $Repository.Id 309 | type = "tfsgit" 310 | name = $Repository.Name 311 | localPath = "`$(sys.sourceFolder)/$($Repository.Name)" 312 | defaultBranch = "refs/heads/master" 313 | url = $Repository.Url 314 | clean = "false" 315 | } 316 | options = @( 317 | @{ 318 | enabled = $true 319 | definition = @{ 320 | id = "7c555368-ca64-4199-add6-9ebaf0b0137d" 321 | } 322 | inputs = @{ 323 | parallel = "false" 324 | multipliers = '["config", "platform"]' 325 | } 326 | } 327 | ) 328 | variables = @{ 329 | forceClean = @{ 330 | value = "false" 331 | allowOverride = $true 332 | } 333 | config = @{ 334 | value = "debug, release" 335 | allowOverride = $true 336 | } 337 | platform = @{ 338 | value = "any cpu" 339 | allowOverride = $true 340 | } 341 | } 342 | badgeEnabled = [bool]$BadgeEnabled 343 | buildNumberFormat = $BuildNumberFormat 344 | triggers = @() 345 | comment = $Comment 346 | } | ConvertTo-Json -Depth 20 347 | 348 | $result = Invoke-VstsEndpoint ` 349 | -Session $Session ` 350 | -Project $Project ` 351 | -Path $path ` 352 | -ApiVersion '2.0' ` 353 | -Method 'POST' ` 354 | -Body $body 355 | 356 | return $result.Value 357 | } 358 | 359 | <# 360 | .SYNOPSIS 361 | Gets team project builds. 362 | 363 | .DESCRIPTION 364 | This cmdlet will return a list of builds 365 | or a single build if Id is specified. 366 | 367 | It can also be provided with additional query parmeters 368 | to allow additional filters to be applied. 369 | 370 | .PARAMETER AccountName 371 | The name of the VSTS account to use. 372 | 373 | .PARAMETER User 374 | This user name to authenticate to VSTS. 375 | 376 | .PARAMETER Token 377 | This personal access token to use to authenticate to VSTS. 378 | 379 | .PARAMETER Session 380 | The session object created by New-VstsSession. 381 | 382 | .PARAMETER Project 383 | The name of the project to get the builds from. 384 | 385 | .PARAMETER Id 386 | The Id of the build to retrieve. 387 | 388 | .PARAMETER Definitions 389 | Get builds matching any of these definitions. 390 | 391 | .PARAMETER Queues 392 | Get builds in any of these queues. 393 | 394 | .PARAMETER RequestedFor 395 | Get build requested by this user. 396 | 397 | .PARAMETER ReasonFilter 398 | Gets builds that were created for this reason. 399 | 400 | .PARAMETER ResultFilter 401 | Gets builds that have this result. 402 | 403 | .PARAMETER StatusFilter 404 | Gets builds that were match this status. 405 | 406 | .PARAMETER Top 407 | The maximum number of builds to return. 408 | #> 409 | function Get-VstsBuild 410 | { 411 | [CmdletBinding(DefaultParameterSetName = 'Account')] 412 | param 413 | ( 414 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 415 | [String] $AccountName, 416 | 417 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 418 | [String] $User, 419 | 420 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 421 | [String] $Token, 422 | 423 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 424 | $Session, 425 | 426 | [Parameter(Mandatory = $True)] 427 | [String] $Project, 428 | 429 | [Parameter()] 430 | [Int32] $Id, 431 | 432 | [Parameter()] 433 | [Int32[]] $Definitions, 434 | 435 | [Parameter()] 436 | [Int32[]] $Queues, 437 | 438 | [Parameter()] 439 | [String] $RequestedFor, 440 | 441 | [Parameter()] 442 | [ValidateSet('Manual', 'IndividualCI', 'BatchedCI', 'Schedule', 'UserCreated', 'ValidateShelveset', 'CheckInShelveset', 'Triggered', 'All')] 443 | [String] $ReasonFilter, 444 | 445 | [Parameter()] 446 | [ValidateSet('Succeeded', 'PartiallySucceeded', 'Failed', 'Canceled')] 447 | [String] $ResultFilter, 448 | 449 | [Parameter()] 450 | [ValidateSet('InProgress', 'Completed', 'Cancelling', 'Postponed', 'NotStarted', 'All')] 451 | [String] $StatusFilter, 452 | 453 | [Parameter()] 454 | [Int32] $Top 455 | ) 456 | 457 | if ($PSCmdlet.ParameterSetName -eq 'Account') 458 | { 459 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 460 | } 461 | 462 | $path = 'build/builds' 463 | $additionalInvokeParameters = @{} 464 | 465 | if ($PSBoundParameters.ContainsKey('Id')) 466 | { 467 | $path = ('{0}/{1}' -f $path, $Id) 468 | } 469 | else 470 | { 471 | $PSBoundParameters['Definitions'] = ($PSBoundParameters['Definitions'] -join ',') 472 | $PSBoundParameters['Queues'] = ($PSBoundParameters['Queues'] -join ',') 473 | 474 | $additionalInvokeParameters = @{ 475 | QueryStringParameters = Get-VstsQueryStringParametersFromBound ` 476 | -BoundParameters $PSBoundParameters ` 477 | -ParameterList 'definitions', 'queues', 'requestedFor', 'reasonFilter', 'resultFilter', 'statusFilter' 478 | QueryStringExtParameters = Get-VstsQueryStringParametersFromBound ` 479 | -BoundParameters $PSBoundParameters ` 480 | -ParameterList 'top' 481 | } 482 | } 483 | 484 | $Result = Invoke-VstsEndpoint ` 485 | -Session $Session ` 486 | -Project $Project ` 487 | -Path $path ` 488 | -ApiVersion '2.0' ` 489 | @additionalInvokeParameters 490 | 491 | return $Result.Value 492 | } 493 | 494 | <# 495 | .SYNOPSIS 496 | Gets team project build artifacts. 497 | 498 | .PARAMETER AccountName 499 | The name of the VSTS account to use. 500 | 501 | .PARAMETER User 502 | This user name to authenticate to VSTS. 503 | 504 | .PARAMETER Token 505 | This personal access token to use to authenticate to VSTS. 506 | 507 | .PARAMETER Session 508 | The session object created by New-VstsSession. 509 | 510 | .PARAMETER Project 511 | The name of the project to get the build artifacts from. 512 | 513 | .PARAMETER BuildId 514 | The BuildId of the artifacts to return. 515 | 516 | .EXAMPLE 517 | > 518 | $vstsSession = New-VSTSSession ` 519 | -AccountName 'myvstsaccount' ` 520 | -User 'joe.bloggs@fabrikam.com' ` 521 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 522 | 523 | $build = Get-VstsBuild ` 524 | -Session $Session ` 525 | -Project 'FabrikamFiber' ` 526 | -Top 1 527 | 528 | Get-VstsBuildArtifact ` 529 | -Session $Session ` 530 | -Project 'FabrikamFiber' ` 531 | -BuildId ($build.Id) 532 | 533 | Get all the build artifacts from the latest build in project 534 | FabrikamFiber. 535 | #> 536 | function Get-VstsBuildArtifact 537 | { 538 | [CmdletBinding(DefaultParameterSetName = 'Account')] 539 | param 540 | ( 541 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 542 | [String] $AccountName, 543 | 544 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 545 | [String] $User, 546 | 547 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 548 | [String] $Token, 549 | 550 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 551 | $Session, 552 | 553 | [Parameter(Mandatory = $true)] 554 | [String] $Project, 555 | 556 | [Parameter(Mandatory = $true)] 557 | [Int32] $BuildId 558 | ) 559 | 560 | if ($PSCmdlet.ParameterSetName -eq 'Account') 561 | { 562 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 563 | } 564 | 565 | $path = ('build/builds/{0}/artifacts' -f $BuildId) 566 | 567 | $result = Invoke-VstsEndpoint ` 568 | -Session $Session ` 569 | -Project $Project ` 570 | -Path $path ` 571 | -ApiVersion '2.0' 572 | 573 | return $result.Value 574 | } 575 | 576 | <# 577 | .SYNOPSIS 578 | Gets build queues for the collection. 579 | 580 | .PARAMETER AccountName 581 | The name of the VSTS account to use. 582 | 583 | .PARAMETER User 584 | This user name to authenticate to VSTS. 585 | 586 | .PARAMETER Token 587 | This personal access token to use to authenticate to VSTS. 588 | 589 | .PARAMETER Session 590 | The session object created by New-VstsSession. 591 | 592 | .PARAMETER Id 593 | The Id of the Build Queue to retrieve. 594 | 595 | .PARAMETER Name 596 | The Name of the Build Queue to retrieve. 597 | #> 598 | function Get-VstsBuildQueue 599 | { 600 | [CmdletBinding(DefaultParameterSetName = 'Account')] 601 | param 602 | ( 603 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 604 | [String] $AccountName, 605 | 606 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 607 | [String] $User, 608 | 609 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 610 | [String] $Token, 611 | 612 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 613 | $Session, 614 | 615 | [Parameter()] 616 | [Int32] $Id, 617 | 618 | [Parameter()] 619 | [String] $Name 620 | ) 621 | 622 | if ($PSCmdlet.ParameterSetName -eq 'Account') 623 | { 624 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 625 | } 626 | 627 | $Path = 'build/queues' 628 | $additionalInvokeParameters = @{} 629 | 630 | if ($PSBoundParameters.ContainsKey('Id')) 631 | { 632 | $Path = ('{0}/{1}' -f $Path, $Id) 633 | } 634 | else 635 | { 636 | $additionalInvokeParameters = @{ 637 | QueryStringParameters = Get-VstsQueryStringParametersFromBound ` 638 | -BoundParameters $PSBoundParameters ` 639 | -ParameterList 'name' 640 | } 641 | } 642 | 643 | $Result = Invoke-VstsEndpoint ` 644 | -Session $Session ` 645 | -Path $Path ` 646 | -ApiVersion '2.0' ` 647 | @additionalInvokeParameters 648 | 649 | return $Result.Value 650 | } 651 | 652 | <# 653 | .SYNOPSIS 654 | Get a list of all tags across all builds or gets 655 | a list of tags for a specific build. 656 | 657 | .DESCRIPTION 658 | This cmdlet will return a list of tags used across 659 | all builds or will return a list of tags used in 660 | a specific build if the BuildId is passed. 661 | 662 | .PARAMETER AccountName 663 | The name of the VSTS account to use. 664 | 665 | .PARAMETER User 666 | This user name to authenticate to VSTS. 667 | 668 | .PARAMETER Token 669 | This personal access token to use to authenticate to VSTS. 670 | 671 | .PARAMETER Session 672 | The session object created by New-VstsSession. 673 | 674 | .PARAMETER Project 675 | The name of the project to create the new release in. 676 | 677 | .PARAMETER BuildId 678 | The id of the Build to return tags for. 679 | 680 | .EXAMPLE 681 | > 682 | $vstsSession = New-VSTSSession ` 683 | -AccountName 'myvstsaccount' ` 684 | -User 'joe.bloggs@fabrikam.com' ` 685 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 686 | 687 | Get-VstsBuildTag ` 688 | -Session $vstsSession ` 689 | -Project 'FabrikamFiber' 690 | 691 | Return all build tags in the project FabrikamFiber. 692 | 693 | .EXAMPLE 694 | > 695 | $vstsSession = New-VSTSSession ` 696 | -AccountName 'myvstsaccount' ` 697 | -User 'joe.bloggs@fabrikam.com' ` 698 | -Token 'hi3pxk5usaag6jslczs5bqmlkngvhr3czqyh65jdvlvtt3qkh4ya' 699 | 700 | Get-VstsBuildTag ` 701 | -Session $vstsSession ` 702 | -Project 'FabrikamFiber' ` 703 | -BuildId 103 704 | 705 | Return all build tags for the build 103 in project FabrikamFiber. 706 | #> 707 | function Get-VstsBuildTag 708 | { 709 | [CmdletBinding(DefaultParameterSetName = 'Account')] 710 | param 711 | ( 712 | [Parameter(Mandatory = $True, ParameterSetName = 'Account')] 713 | [String] $AccountName, 714 | 715 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 716 | [String] $User, 717 | 718 | [Parameter(Mandatory = $true, ParameterSetName = 'Account')] 719 | [String] $Token, 720 | 721 | [Parameter(Mandatory = $True, ParameterSetName = 'Session')] 722 | $Session, 723 | 724 | [Parameter(Mandatory = $True)] 725 | [String] $Project, 726 | 727 | [Parameter()] 728 | [Int32] $BuildId 729 | ) 730 | 731 | if ($PSCmdlet.ParameterSetName -eq 'Account') 732 | { 733 | $Session = New-VstsSession -AccountName $AccountName -User $User -Token $Token 734 | } 735 | 736 | if ($PSBoundParameters.ContainsKey('BuildId')) 737 | { 738 | $path = 'build/builds/{0}/tags' -f $BuildId 739 | $additionalInvokeParameters = @{} 740 | } 741 | else 742 | { 743 | $path = 'build/tags' 744 | } 745 | 746 | $result = Invoke-VstsEndpoint ` 747 | -Session $Session ` 748 | -Path $path ` 749 | -Project $Project ` 750 | -ApiVersion '2.0' ` 751 | @additionalInvokeParameters 752 | 753 | return $result.Value 754 | } 755 | --------------------------------------------------------------------------------