Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Enhance Get-VSTeamProcess #300 #322

Closed
wants to merge 10 commits into from
29 changes: 22 additions & 7 deletions .docs/Get-VSTeamProcess.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@

## DESCRIPTION

The list of Process Templates returned can be controlled by using the top and skip parameters.

You can also get a single Process Template by name or id.
The list of Process Templates can be filtered by name (which may include Wildcard). You can also get a single Process Template by id

You must call Set-VSTeamAccount before calling this function.

Expand All @@ -29,18 +27,32 @@ This will return all the Process Templates
### -------------------------- EXAMPLE 2 --------------------------

```PowerShell
PS C:\> Get-VSTeamProcess -top 5 | Format-Wide
PS C:\> Get-VSTeamProcess | Format-Wide
jhoneill marked this conversation as resolved.
Show resolved Hide resolved
```

This will return the top five Process Templates only showing their name
This will return the Process Templates only showing their name


### -------------------------- EXAMPLE 3 --------------------------

```PowerShell
PS C:\> Get-VSTeamProcess *scrum*
```

This will return an process templates with names containing scrum,
in other words, the default "Scrum" template and custom ones with
names like "Custom Scrum", "Scrum for Contoso" will all be returned.


## PARAMETERS

<!-- #include "./params/ProcessName.md" -->

### -Top

Specifies the maximum number to return.
Specifies the maximum number to return.
jhoneill marked this conversation as resolved.
Show resolved Hide resolved
If -Skip is specified and -Top is omitted the next 100 will be returned.
If neither Skip nor -Top is specified, all process templates will be returned.

```yaml
Type: Int32
Expand All @@ -50,7 +62,10 @@ Default value: 100

### -Skip

Defines the number of Process Templates to skip. The default value is 0
Defines the number of Process Templates to skip.
jhoneill marked this conversation as resolved.
Show resolved Hide resolved
If -Top is specified and -Skip is omitted none will be skipped.
If neither Skip nor -Top is specified, all process templates will be returned.


```yaml
Type: Int32
Expand Down
10 changes: 9 additions & 1 deletion Build-Module.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ param(

# outputs the code coverage
[Parameter(ParameterSetName = "UnitTest")]
[switch]$codeCoverage
[switch]$codeCoverage,

[switch]$WithPublicClasses
)

. ./Merge-File.ps1
Expand Down Expand Up @@ -83,6 +85,12 @@ if ($buildHelp.IsPresent) {
Write-Output 'Publishing about help files'
Copy-Item -Path ./Source/en-US -Destination "$output/" -Recurse -Force
Copy-Item -Path ./Source/VSTeam.psm1 -Destination "$output/VSTeam.psm1" -Force
if ($WithPublicClasses) {
jhoneill marked this conversation as resolved.
Show resolved Hide resolved
Write-Output "Merging classes.ps1 into VSTeam.ps1"
Get-Content -Path "$output/VSTeam.psm1" | Out-File -Append -FilePath "$output/vsteam.classes.ps1" -Encoding ascii
Copy-Item -Path "$output/vsteam.classes.ps1" -Destination "$output/VSTeam.psm1"
"#empty" | Out-File -Force -FilePath "$output/vsteam.classes.ps1" -Encoding ascii
}

Write-Output 'Updating Functions To Export'
$newValue = ((Get-ChildItem -Path "./Source/Public" -Filter '*.ps1').BaseName |
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

Source/Classes/ProcessTemplateCompleter.ps1 |
Source/Classes/ProcessValidateAttribute.ps1 |
Source/Classes/ProjectCompleter.ps1 |
Source/Classes/ProjectValidateAttribute.ps1 | Changed in previous PR and files need to stay in sync / are a depedency for this

Source/Classes/VSTeamProcessCache.ps1
Source/Public/Get-VSTeamProcess.ps1 | Update to get process from different URL branch (WORK/PROCESS)
| this version is more allows add, modify and is the path to changing work item types.
| However it ignores the top and skip options.
| Now update the cache automatically; support wildcards, paramater aliases, specify output type.
.docs/Get-VSTeamProcess.md | Update to documentation
Source/Classes/VSTeamProcess.ps1 | Modify class to be more pipeline friendly and to work with slightly different fields from the different URL path.
Source/formats/Team.Process.TableView.ps1xml | Updated to isDisabled and isDefault
Source/formats/Team.Process.ListView.ps1xml | Updated to isDisabled and isDefault

unit/test/Get-VSTeamProcess.Tests.ps1 | Updated for new behavior. (Don't validate name to allow wildcard use, top and skip ignored. )
unit/test/Add-VSTeamProject.Tests.ps1 | Fix for side effects of changes above
unit/test/ProcessValidateAttribute.Tests.ps1 | Fix for side effects of changes above

## 6.5.1

Merged [Pull Request](https://github.com/DarqueWarrior/vsteam/pull/317) from [Brittan DeYoung](https://github.com/brittandeyoung) which included the following:
Expand Down
17 changes: 7 additions & 10 deletions Source/Classes/ProcessTemplateCompleter.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ using namespace System.Collections
using namespace System.Collections.Generic
using namespace System.Management.Automation

# This class defines an attribute that allows the user the tab complete
# process templates for function parameters.
# This class defines an attribute that allows the user the tab complete process templates
# for function parameters.
class ProcessTemplateCompleter : IArgumentCompleter {
[IEnumerable[CompletionResult]] CompleteArgument(
[string] $CommandName,
Expand All @@ -14,17 +14,14 @@ class ProcessTemplateCompleter : IArgumentCompleter {

$results = [List[CompletionResult]]::new()

if (_hasProcessTemplateCacheExpired) {
[VSTeamProcessCache]::processes = _getProcesses
[VSTeamProcessCache]::timestamp = (Get-Date).Minute
}

foreach ($p in [VSTeamProcessCache]::processes) {
if ($p -like "*$WordToComplete*") {
foreach ($p in [VSTeamProcessCache]::GetCurrent()) {
if ($p -like "*$WordToComplete*" -and $p -notmatch '\W') {
$results.Add([CompletionResult]::new($p))
}
elseif ($p -like "*$WordToComplete*") {
$results.Add([CompletionResult]::new("'$($p.replace("'","''"))'", $p, 0, $p))
}
}

return $results
}
}
13 changes: 6 additions & 7 deletions Source/Classes/ProcessValidateAttribute.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ class ProcessValidateAttribute : ValidateArgumentsAttribute {
[void] Validate(
[object] $arguments,
[EngineIntrinsics] $EngineIntrinsics) {

if (_hasProcessTemplateCacheExpired) {
[VSTeamProcessCache]::processes = _getProcesses
[VSTeamProcessCache]::timestamp = (Get-Date).Minute
}

if (($null -ne [VSTeamProcessCache]::processes) -and (-not ($arguments -in [VSTeamProcessCache]::processes))) {
#Do not fail on null or empty, leave that to other validation conditions
if ([string]::IsNullOrEmpty($arguments)) {return}
#tests count HTTP calls and expect 1 from reading the cache, but for a call on each read, so only read once! #
$CachedProcesses = [VSTeamProcessCache]::GetCurrent()
if (($null -ne $CachedProcesses) -and ($arguments -notin $CachedProcesses) ) {
throw [ValidationMetadataException]::new(
"'$arguments' is not a valid process. Valid processes are: '" +
([VSTeamProcessCache]::processes -join "', '") + "'")
($CachedProcesses -join "', '") + "'")
}
}
}
15 changes: 7 additions & 8 deletions Source/Classes/ProjectCompleter.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using namespace System.Collections
using namespace System.Collections.Generic
using namespace System.Management.Automation

# This class defines an attribute that allows the user the tab complete project names
# for function parameters.
class ProjectCompleter : IArgumentCompleter {
[IEnumerable[CompletionResult]] CompleteArgument(
[string] $CommandName,
Expand All @@ -12,15 +13,13 @@ class ProjectCompleter : IArgumentCompleter {

$results = [List[CompletionResult]]::new()

if (_hasProjectCacheExpired) {
[VSTeamProjectCache]::projects = _getProjects
[VSTeamProjectCache]::timestamp = (Get-Date).Minute
}

foreach ($p in [VSTeamProjectCache]::projects) {
if ($p -like "*$WordToComplete*") {
foreach ($p in [VSTeamProjectCache]::GetCurrent()) {
if ($p -like "*$WordToComplete*" -and $p -notmatch "\W") {
$results.Add([CompletionResult]::new($p))
}
elseif ($p -like "*$WordToComplete*"){
$results.Add([CompletionResult]::new("'$($p.replace("'","''"))'", $p, 0, $p))
}
}

return $results
Expand Down
10 changes: 4 additions & 6 deletions Source/Classes/ProjectValidateAttribute.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ class ProjectValidateAttribute : ValidateArgumentsAttribute {
[void] Validate(
[object] $arguments,
[EngineIntrinsics] $EngineIntrinsics) {

if (_hasProjectCacheExpired) {
[VSTeamProjectCache]::projects = _getProjects
[VSTeamProjectCache]::timestamp = (Get-Date).Minute
}

if (($null -ne [VSTeamProjectCache]::projects) -and (-not ($arguments -in [VSTeamProjectCache]::projects))) {
#Do not fail on null or empty, leave that to other validation conditions
if ([string]::IsNullOrEmpty($arguments)) {return}

if (($null -ne [VSTeamProjectCache]::GetCurrent()) -and (-not ($arguments -in [VSTeamProjectCache]::projects))) {
throw [ValidationMetadataException]::new(
"'$arguments' is not a valid project. Valid projects are: '" +
([VSTeamProjectCache]::projects -join "', '") + "'")
Expand Down
44 changes: 33 additions & 11 deletions Source/Classes/VSTeamProcess.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,46 @@ class VSTeamProcess {
[string]$URL = $null
[string]$Description = $null
[string]$Name = $null
[string]$ReferenceName = $null
[bool]$IsEnabled = $true
[bool]$IsDefault = $false
[string]$Type = $null

[string]$ProcessTemplate = $null
[string]$ParentProcessTypeId = $null
VSTeamProcess (
[object]$obj
) {
$this.ID = $obj.id
$this.URL = $obj.url
$this.IsDefault = $obj.isDefault
$this.Name = $obj.name
$this.Type = $obj.type

$this.AddTypeName('Team.Process')
$this.Name = $obj.name
$this.ProcessTemplate = $obj.name
#Allow for processes from .../process/processes with ID property, or ...work/processes with TypeID
if ($obj.PSObject.Properties['typeId']) {
$this.ID = $obj.typeId
$this.URL = (_getInstance) + "/_apis/work/processes/" + $obj.typeId
jhoneill marked this conversation as resolved.
Show resolved Hide resolved
}
elseIf ($obj.PSObject.Properties['Id']) {
$this.ID = $obj.Id
$this.URL = (_getInstance) + "/_apis/work/processes/" + $obj.ID
}
if ($obj.PSObject.Properties['isEnabled']) {
$this.IsEnabled = $obj.isEnabled
}
if ($obj.PSObject.Properties['isDefault']) {
$this.IsDefault = $obj.isDefault
}
if ($obj.PSObject.Properties['referenceName']) {
$this.ReferenceName = $obj.referenceName
}
if ($obj.PSObject.Properties['customizationType']) {
$this.Type = $obj.customizationType
}
# The description is not always returned so protect yourself.
if ($obj.PSObject.Properties.Match('description').count -gt 0) {
$this.Description = $obj.description
if ($obj.PSObject.Properties['description']) {
$this.Description = $obj.description
}
if ($obj.PSObject.Properties['parentProcessTypeId']) {
$this.ParentProcessTypeId = $obj.parentProcessTypeId
}

$this.AddTypeName('Team.Process')
}

[void] hidden AddTypeName(
Expand Down
24 changes: 24 additions & 0 deletions Source/Classes/VSTeamProcessCache.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,28 @@
class VSTeamProcessCache {
static [int] $timestamp = -1
static [object] $processes = $null
static [hashtable] $urls = @{}
static [Void] Update () {
#Allow unit tests to mock returning the project list and testing freshness
$list = _getProcesses
if ($list) {
foreach ($process in $list) {
[VSTeamProcessCache]::urls[$process.name] = (_getInstance) + "/_apis/work/processes/" + $process.Id
}
[VSTeamProcessCache]::processes = $List.name | Sort-Object
}
else {
[VSTeamProcessCache]::processes = $null
}
[VSTeamProcessCache]::timestamp = (Get-Date).Minute
# "save current minute" refreshes on average after 30secs but not after exact hours timeOfDayTotalMinutes might be a better base
}
static [object] GetCurrent () {
if (_hasProcessTemplateCacheExpired) { [VSTeamProcessCache]::Update() }
return ([VSTeamProcessCache]::processes)
}
static [object] GetURl ([string]$ProcessName) {
if (_hasProcessTemplateCacheExpired) { [VSTeamProcessCache]::Update() }
return ([VSTeamProcessCache]::urls[$ProcessName])
}
}
13 changes: 13 additions & 0 deletions Source/Classes/VSTeamProjectCache.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,17 @@
class VSTeamProjectCache {
static [int] $timestamp = -1
static [object] $projects = $null
static [Void] Update () {
#Allow unit tests to mock returning the project list and testing freshness
[VSTeamProjectCache]::projects = _getProjects
[VSTeamProjectCache]::timestamp = (Get-Date).Minute
# "save current minute" refreshes on average after 30secs but not after exact hours timeOfDayTotalMinutes might be a better base
}
static [void] Invalidate () {
[VSTeamProjectCache]::timestamp = -1
}
static [object] GetCurrent () {
if (_hasProjectCacheExpired) { [VSTeamProjectCache]::Update() }
return ([VSTeamProjectCache]::projects)
}
}
Loading