Skip to content

Instantly share code, notes, and snippets.

@Badgerati
Created June 16, 2016 20:25
Show Gist options
  • Save Badgerati/5236a27756e06ef4abde049a8ce26ef5 to your computer and use it in GitHub Desktop.
Save Badgerati/5236a27756e06ef4abde049a8ce26ef5 to your computer and use it in GitHub Desktop.
Automated Jira Release Notes using PowerShell
###############################################################################
# Script to generate Jira Release Notes.
#
# Release notes can be generated in either HTML, MD or just plain text. You can
# specify either the fixVersion, project tag/name or status(es) in any combination.
#
# Example:
# .\jira-release-notes.ps1 -jiraUrl 'http://jira.some.com' -project 'Potatoes'
# .\jira-release-notes.ps1 -jiraUrl 'http://jira.some.com' -fixVersion '1.2.0'
# .\jira-release-notes.ps1 -jiraUrl 'http://jira.some.com' -statuses @('Done')
#
# Author: Matthew Kelly
# Date: 16/06/2016
###############################################################################
param (
[Parameter(Mandatory=$true)]
[string] $jiraUrl,
[string] $base64AuthToken,
[string[]] $statuses,
[string] $project,
[string] $fixVersion,
[switch] $asHtml,
[switch] $asMarkDown
)
# Ensure we have at least one of status/project or fixVersion
if ([string]::IsNullOrWhiteSpace($project) -and [string]::IsNullOrWhiteSpace($fixVersion) -and ($statuses -eq $null -or $statuses.Length -eq 0))
{
Write-Error 'Need to at least specify one of either a fixVersion, project or statuses.'
return
}
# Trim the Jira URL for trailing slashes
if ($jiraUrl.EndsWith('/'))
{
$jiraUrl = $jiraUrl.Trim('/')
}
# Set the main Rest API and Jira endpoints
$jiraRestApi = "$jiraUrl/rest/api/latest/search"
$jiraBrowse = "$jiraUrl/browse"
# Construct the JQL
$jql = [string]::Empty
if (![string]::IsNullOrWhiteSpace($project))
{
$jql += "Project='$project' AND "
}
if (![string]::IsNullOrWhiteSpace($fixVersion))
{
$jql += "fixVersion='$fixVersion' AND "
}
if ($statuses -ne $null -and $statuses.Length -gt 0)
{
$jql += ("Status IN ('{0}')" -f ($statuses -join "','"))
}
if ($jql.EndsWith('AND '))
{
$jql = $jql.Trim('AND ')
}
$jql = $jql.Trim() -replace ' ', '%20'
# Invoke the Rest API for the constructed JQL
$jiraSearchUri = ("{0}?jql=$jql&startAt=0&maxResult=1000" -f $jiraRestApi)
if ([string]::IsNullOrWhiteSpace($base64AuthToken))
{
$result = Invoke-RestMethod -Method Get -Uri $jiraSearchUri -ContentType 'application/json'
}
else
{
$result = Invoke-RestMethod -Method Get -Uri $jiraSearchUri -Headers @{ Authorization = "Basic $base64AuthToken" } -ContentType 'application/json'
}
if (!$?)
{
Write-Error 'The call to the Jira REST API was not successful.'
return
}
# Gather up all of the issues
$issues = $result.issues
$issueMap = @{}
foreach ($issue in $issues)
{
$code = $issue.key
$type = $issue.fields.issueType.name
$summary = $issue.fields.summary
if (!$issueMap.Contains($type))
{
$issueMap.Add($type, @{})
}
$issueMap[$type].Add($code, $summary)
}
# Generate the output
$output = [string]::Empty
if ($asHtml)
{
foreach ($type in $issueMap.keys)
{
$output += "<h2>$type</h2>"
$output += "<ul>"
foreach ($issue in $issueMap[$type].keys)
{
$summary = $issueMap[$type][$issue]
$output += "<li>[<a href='$jiraBrowse/$issue'>$issue</a>]: $summary</li>"
}
$output += "</ul><br />"
}
}
elseif ($asMarkDown)
{
foreach ($type in $issueMap.keys)
{
$output += "## $type`n"
foreach ($issue in $issueMap[$type].keys)
{
$summary = $issueMap[$type][$issue]
$output += "* [[$issue]]($jiraBrowse/$issue): $summary`n"
}
$output += "`n"
}
}
else
{
foreach ($type in $issueMap.keys)
{
$output += "$type`n"
foreach ($issue in $issueMap[$type].keys)
{
$summary = $issueMap[$type][$issue]
$output += "* [$issue]: $summary`n"
}
$output += "`n"
}
}
return $output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment