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

Create Epic work item type as Service or product #6782

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 101 additions & 19 deletions eng/common/scripts/Helpers/DevOps-WorkItem-Helpers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ function BuildHashKey()
}

$parentWorkItems = @{}
function FindParentWorkItem($serviceName, $packageDisplayName, $outputCommand = $false)
function FindParentWorkItem($serviceName, $packageDisplayName, $outputCommand = $false, $ignoreReleasePlannerTests = $true)
{
$key = BuildHashKey $serviceName $packageDisplayName
if ($key -and $parentWorkItems.ContainsKey($key)) {
Expand All @@ -154,10 +154,12 @@ function FindParentWorkItem($serviceName, $packageDisplayName, $outputCommand =
else {
$serviceCondition = "[ServiceName] <> ''"
}

if($ignoreReleasePlannerTests){
$serviceCondition += " AND [Tags] NOT CONTAINS 'Release Planner App Test'"
}
$query = "SELECT [ID], [ServiceName], [PackageDisplayName], [Parent] FROM WorkItems WHERE [Work Item Type] = 'Epic' AND ${serviceCondition}"

$fields = @("System.Id", "Custom.ServiceName", "Custom.PackageDisplayName", "System.Parent")
$fields = @("System.Id", "Custom.ServiceName", "Custom.PackageDisplayName", "System.Parent", "System.Tags")

$workItems = Invoke-Query $fields $query $outputCommand

Expand All @@ -180,13 +182,63 @@ function FindParentWorkItem($serviceName, $packageDisplayName, $outputCommand =
return $null
}

$releasePlanWorkItems = @{}
function FindReleasePlanWorkItem($serviceName, $packageDisplayName, $outputCommand = $false, $ignoreReleasePlannerTests = $true)
{
$key = BuildHashKey $serviceName $packageDisplayName
if ($key -and $releasePlanWorkItems.ContainsKey($key)) {
return $releasePlanWorkItems[$key]
}

if ($serviceName) {
$condition = "[ServiceName] = '${serviceName}'"
if ($packageDisplayName) {
$condition += " AND [PackageDisplayName] = '${packageDisplayName}'"
}
else {
$condition += " AND [PackageDisplayName] = ''"
}
}
else {
$condition = "[ServiceName] <> ''"
}
$condition += " AND [System.State] <> 'Finished'"
if($ignoreReleasePlannerTests){
$condition += " AND [Tags] NOT CONTAINS 'Release Planner App Test'"
}

$query = "SELECT [ID], [ServiceName], [PackageDisplayName], [Parent] FROM WorkItems WHERE [Work Item Type] = 'Release Plan' AND ${condition}"

$fields = @("System.Id", "Custom.ServiceName", "Custom.PackageDisplayName", "System.Parent", "System.Tags")

$workItems = Invoke-Query $fields $query $outputCommand

foreach ($wi in $workItems)
{
$localKey = BuildHashKey $wi.fields["Custom.ServiceName"] $wi.fields["Custom.PackageDisplayName"]
if (!$localKey) { continue }
if ($releasePlanWorkItems.ContainsKey($localKey) -and $releasePlanWorkItems[$localKey].id -ne $wi.id) {
Write-Warning "Already found parent [$($releasePlanWorkItems[$localKey].id)] with key [$localKey], using that one instead of [$($wi.id)]."
}
else {
Write-Verbose "[$($wi.id)]$localKey - Cached"
$releasePlanWorkItems[$localKey] = $wi
}
}

if ($key -and $releasePlanWorkItems.ContainsKey($key)) {
return $releasePlanWorkItems[$key]
}
return $null
}

$packageWorkItems = @{}
$packageWorkItemWithoutKeyFields = @{}

function FindLatestPackageWorkItem($lang, $packageName, $outputCommand = $true)
function FindLatestPackageWorkItem($lang, $packageName, $outputCommand = $true, $ignoreReleasePlannerTests = $true)
{
# Cache all the versions of this package and language work items
$null = FindPackageWorkItem $lang $packageName -includeClosed $true -outputCommand $outputCommand
$null = FindPackageWorkItem $lang $packageName -includeClosed $true -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests

$latestWI = $null
foreach ($wi in $packageWorkItems.Values)
Expand All @@ -206,7 +258,7 @@ function FindLatestPackageWorkItem($lang, $packageName, $outputCommand = $true)
return $latestWI
}

function FindPackageWorkItem($lang, $packageName, $version, $outputCommand = $true, $includeClosed = $false)
function FindPackageWorkItem($lang, $packageName, $version, $outputCommand = $true, $includeClosed = $false, $ignoreReleasePlannerTests = $true)
{
$key = BuildHashKeyNoNull $lang $packageName $version
if ($key -and $packageWorkItems.ContainsKey($key)) {
Expand All @@ -218,6 +270,7 @@ function FindPackageWorkItem($lang, $packageName, $version, $outputCommand = $tr
$fields += "System.State"
$fields += "System.AssignedTo"
$fields += "System.Parent"
$fields += "System.Tags"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are we getting from the Tags? Is that only to filter out the tests? If so we might want to consider other potential ways to filter these out, like perhaps having some way to close them all so they don't show up in the queries.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to avoid showing up work items created from release planner app in dev and PPE.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are tags the best way of doing this? These will also start to show up in other query or dashboards that folks might be using directly in DevOps. Can we instead have something that goes in and closes all the dev and PPE created items?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can mark them as closed by automation pipeline. I will discuss with @maririos and come up with a plan. In the meanwhile, I think we should include current changes so work items created by prepare release script won't attach package WI to incorrect service and product.

$fields += "Custom.Language"
$fields += "Custom.Package"
$fields += "Custom.PackageDisplayName"
Expand Down Expand Up @@ -251,7 +304,9 @@ function FindPackageWorkItem($lang, $packageName, $version, $outputCommand = $tr
if ($version) {
$query += " AND [PackageVersionMajorMinor] = '${version}'"
}

if($ignoreReleasePlannerTests){
$query += " AND [Tags] NOT CONTAINS 'Release Planner App Test'"
}
$workItems = Invoke-Query $fields $query $outputCommand

foreach ($wi in $workItems)
Expand All @@ -277,13 +332,13 @@ function FindPackageWorkItem($lang, $packageName, $version, $outputCommand = $tr
return $null
}

function InitializeWorkItemCache($outputCommand = $true, $includeClosed = $false)
function InitializeWorkItemCache($outputCommand = $true, $includeClosed = $false, $ignoreReleasePlannerTests = $true)
{
# Pass null to cache all service parents
$null = FindParentWorkItem -serviceName $null -packageDisplayName $null -outputCommand $outputCommand
$null = FindParentWorkItem -serviceName $null -packageDisplayName $null -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests

# Pass null to cache all the package items
$null = FindPackageWorkItem -lang $null -packageName $null -version $null -outputCommand $outputCommand -includeClosed $includeClosed
$null = FindPackageWorkItem -lang $null -packageName $null -version $null -outputCommand $outputCommand -includeClosed $includeClosed -ignoreReleasePlannerTests $ignoreReleasePlannerTests
}

function GetCachedPackageWorkItems()
Expand Down Expand Up @@ -490,30 +545,55 @@ function CreateOrUpdatePackageWorkItem($lang, $pkg, $verMajorMinor, $existingIte
}
}

$newparentItem = FindOrCreatePackageGroupParent $serviceName $pkgDisplayName -outputCommand $false
$newparentItem = FindOrCreateReleasePlanParent $serviceName $pkgDisplayName -outputCommand $false
UpdateWorkItemParent $existingItem $newParentItem -outputCommand $outputCommand
return $existingItem
}

$parentItem = FindOrCreatePackageGroupParent $serviceName $pkgDisplayName -outputCommand $false
$parentItem = FindOrCreateReleasePlanParent $serviceName $pkgDisplayName -outputCommand $false
$workItem = CreateWorkItem $title "Package" "Release" "Release" $fields $assignedTo $parentItem.id -outputCommand $outputCommand
Write-Host "[$($workItem.id)]$lang - $pkgName($verMajorMinor) - Created"
return $workItem
}

function FindOrCreatePackageGroupParent($serviceName, $packageDisplayName, $outputCommand = $true)
function FindOrCreateReleasePlanParent($serviceName, $packageDisplayName, $outputCommand = $true, $ignoreReleasePlannerTests = $true)
{
$existingItem = FindReleasePlanWorkItem $serviceName $packageDisplayName -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests
if ($existingItem) {
Write-Host "Found existing release plan work item [$($existingItem.id)]"
$newparentItem = FindOrCreatePackageGroupParent $serviceName $packageDisplayName -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests
UpdateWorkItemParent $existingItem $newParentItem
return $existingItem
}

$fields = @()
$fields += "`"PackageDisplayName=${packageDisplayName}`""
$fields += "`"ServiceName=${serviceName}`""
$productParentItem = FindOrCreatePackageGroupParent $serviceName $packageDisplayName -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests
$title = "Release Plan - $($packageDisplayName)"
$workItem = CreateWorkItem $title "Release Plan" "Release" "Release" $fields $null $productParentItem.id

$localKey = BuildHashKey $serviceName $packageDisplayName
Write-Host "[$($workItem.id)]$localKey - Created release plan work item"
$releasePlanWorkItems[$localKey] = $workItem
return $workItem
}

function FindOrCreatePackageGroupParent($serviceName, $packageDisplayName, $outputCommand = $true, $ignoreReleasePlannerTests = $true)
{
$existingItem = FindParentWorkItem $serviceName $packageDisplayName -outputCommand $outputCommand
$existingItem = FindParentWorkItem $serviceName $packageDisplayName -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests
if ($existingItem) {
$newparentItem = FindOrCreateServiceParent $serviceName -outputCommand $outputCommand
Write-Host "Found existing product work item [$($existingItem.id)]"
$newparentItem = FindOrCreateServiceParent $serviceName -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests
UpdateWorkItemParent $existingItem $newParentItem
return $existingItem
}

$fields = @()
$fields += "`"PackageDisplayName=${packageDisplayName}`""
$fields += "`"ServiceName=${serviceName}`""
$serviceParentItem = FindOrCreateServiceParent $serviceName -outputCommand $outputCommand
$fields += "`"Custom.EpicType=Product`""
$serviceParentItem = FindOrCreateServiceParent $serviceName -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests
$workItem = CreateWorkItem $packageDisplayName "Epic" "Release" "Release" $fields $null $serviceParentItem.id

$localKey = BuildHashKey $serviceName $packageDisplayName
Expand All @@ -522,21 +602,23 @@ function FindOrCreatePackageGroupParent($serviceName, $packageDisplayName, $outp
return $workItem
}

function FindOrCreateServiceParent($serviceName, $outputCommand = $true)
function FindOrCreateServiceParent($serviceName, $outputCommand = $true, $ignoreReleasePlannerTests = $true)
{
$serviceParent = FindParentWorkItem $serviceName -outputCommand $outputCommand
$serviceParent = FindParentWorkItem $serviceName -packageDisplayName $null -outputCommand $outputCommand -ignoreReleasePlannerTests $ignoreReleasePlannerTests
if ($serviceParent) {
Write-Host "Found existing service work item [$($serviceParent.id)]"
return $serviceParent
}

$fields = @()
$fields += "`"PackageDisplayName=`""
$fields += "`"ServiceName=${serviceName}`""
$fields += "`"Custom.EpicType=Service`""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to care about Sub-Service type or Component type?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We create another Epic Item as child of Service Epic for the product. I am assuming that's what used currently for subservice name as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are managing subservice as another EPIC. Same as previously done before

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is fine if it is another Epic but does this automation need to handle those as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prepare release scrip is already handling it by creating a child under Service WI and then creating individual language package items under this subservice/product WI.

$parentId = $null
$workItem = CreateWorkItem $serviceName "Epic" "Release" "Release" $fields $null $parentId -outputCommand $outputCommand

$localKey = BuildHashKey $serviceName
Write-Host "[$($workItem.id)]$localKey - Created"
Write-Host "[$($workItem.id)]$localKey - Created service work item"
$parentWorkItems[$localKey] = $workItem
return $workItem
}
Expand Down