Consolidate Release Notes

Octopus.Script exported 2023-03-09 by FinnianDempsey belongs to ‘Octopus’ category.

Consolidates all Release Notes between the last successful release in the current Environment and this one by merging or concatenating them.

Parameters

When steps based on the template are included in a project’s deployment process, the parameters below can be set.

Api Key

Consolidate_ApiKey =

The API Key to use for authentication

Remove Duplicates

Consolidate_Dedupe = True

Whether to remove duplicate lines when constructing release notes

Remove Blank Lines

Consolidate_RemoveWhitespace = True

Whether to remove blank lines when constructing release notes

Concatenation Order

Consolidate_Order = Newest

The order in which to append release notes

Script body

Steps based on this template will execute the following PowerShell script.

$baseUri = $OctopusParameters['#{if Octopus.Web.ServerUri}Octopus.Web.ServerUri#{else}Octopus.Web.BaseUrl#{/if}']
$reqheaders = @{"X-Octopus-ApiKey" = $Consolidate_ApiKey }
$putReqHeaders = @{"X-HTTP-Method-Override" = "PUT"; "X-Octopus-ApiKey" = $Consolidate_ApiKey }

$remWhiteSpace = [bool]::Parse($Consolidate_RemoveWhitespace)
$deDupe = [bool]::Parse($Consolidate_Dedupe)
$reverse = ($Consolidate_Order -eq "Oldest")

# Get details we'll need
$projectId = $OctopusParameters['Octopus.Project.Id']
$thisReleaseNumber = $OctopusParameters['Octopus.Release.Number']
$lastSuccessfulReleaseId = $OctopusParameters['Octopus.Release.CurrentForEnvironment.Id']
$lastSuccessfulReleaseNumber = $OctopusParameters['Octopus.Release.CurrentForEnvironment.Number']

function Test-SpacesApi {
	Write-Verbose "Checking API compatibility";
	$rootDocument = Invoke-WebRequest "$baseUri/api" -Headers $reqHeaders -UseBasicParsing | ConvertFrom-Json;
    if($rootDocument.Links -ne $null -and $rootDocument.Links.Spaces -ne $null) {
    	Write-Verbose "Spaces API found"
    	return $true;
    }
    Write-Verbose "Pre-spaces API found"
    return $false;
}

if(Test-SpacesApi) {
	$spaceId = $OctopusParameters['Octopus.Space.Id'];
    if([string]::IsNullOrWhiteSpace($spaceId)) {
        throw "This step needs to be run in a context that provides a value for the 'Octopus.Space.Id' system variable. In this case, we received a blank value, which isn't expected - please reach out to our support team at https://help.octopus.com if you encounter this error.";
    }
	$baseApiUrl = "/api/$spaceId" ;
} else {
	$baseApiUrl = "/api" ;
}

# Get all previous releases to this environment
$releaseUri = "$baseUri$baseApiUrl/projects/$projectId/releases"
try {
    $allReleases = Invoke-WebRequest $releaseUri -Headers $reqheaders -UseBasicParsing | ConvertFrom-Json
} catch {
    if ($_.Exception.Response.StatusCode.Value__ -ne 404) {
        $result = $_.Exception.Response.GetResponseStream()
        $reader = New-Object System.Io.StreamReader($result);
        $responseBody = $reader.ReadToEnd();
        throw "Error occurred: $responseBody"
    }
}

# Find and aggregate release notes
$aggregateNotes = @()

Write-Host "Finding all release notes between the last successful release: $lastSuccessfulReleaseNumber and this release: $thisReleaseNumber"
foreach ($rel in $allReleases.Items) {
    if ($rel.Id -ne $lastSuccessfulReleaseId) {
        Write-Host "Found release notes for $($rel.Version)"
        $theseNotes = @()
        #split into lines
        $lines = $rel.ReleaseNotes -split "`n"
        foreach ($line in $lines) {
            if (-not $remWhitespace -or -not [string]::IsNullOrWhiteSpace($line)) {
                if (-not $deDupe -or -not $aggregateNotes.Contains($line)) {
                    $theseNotes = $theseNotes + $line
                }
            }
        }
        if ($reverse) {
            $aggregateNotes = $theseNotes + $aggregateNotes
        } else {
            $aggregateNotes = $aggregateNotes + $theseNotes
        }
    } else {
        break
    }
}
$aggregateNotesText = $aggregateNotes -join "`n`n"

# Get the current release
$releaseUri = "$baseUri$baseApiUrl/projects/$projectId/releases/$thisReleaseNumber"
try {
    $currentRelease = Invoke-WebRequest $releaseUri -Headers $reqheaders -UseBasicParsing | ConvertFrom-Json
} catch {
    if ($_.Exception.Response.StatusCode.Value__ -ne 404) {
        $result = $_.Exception.Response.GetResponseStream()
        $reader = New-Object System.Io.StreamReader($result);
        $responseBody = $reader.ReadToEnd();
        throw "Error occurred: $responseBody"
    }
}

# Update the release notes for the current release
$currentRelease.ReleaseNotes = $aggregateNotesText
Write-Host "Updating release notes for $thisReleaseNumber`:`n`n"
Write-Host $aggregateNotesText
try {
    $releaseUri = "$baseUri$baseApiUrl/releases/$($currentRelease.Id)"
    $currentReleaseBody = $currentRelease | ConvertTo-Json -Depth 10
    $result = Invoke-WebRequest $releaseUri -Method Post -Headers $putReqHeaders -Body $currentReleaseBody -UseBasicParsing | ConvertFrom-Json
} catch {
    $result = $_.Exception.Response.GetResponseStream()
    $reader = New-Object System.Io.StreamReader($result);
    $responseBody = $reader.ReadToEnd();
    Write-Host $responseBody
    throw "Error occurred: $responseBody"
}

Provided under the Apache License version 2.0.

Report an issue

To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.

{
  "Id": "fa570d27-1405-4030-87b2-c0abf12bb833",
  "Name": "Consolidate Release Notes",
  "Description": "Consolidates all Release Notes between the last successful release in the current Environment and this one by merging or concatenating them.",
  "Version": 13,
  "ExportedAt": "2023-03-09T13:12:44.043Z",
  "ActionType": "Octopus.Script",
  "Author": "FinnianDempsey",
  "Parameters": [
    {
      "Id": "fa5cfdb4-b006-4f92-90ee-affc1791fc79",
      "Name": "Consolidate_ApiKey",
      "Type": "String",
      "Label": "Api Key",
      "HelpText": "The API Key to use for authentication",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      },
      "Links": {}
    },
    {
      "Id": "2fe221e5-1f47-4cf9-bde7-ed3b77028bf4",
      "Name": "Consolidate_Dedupe",
      "Type": "String",
      "Label": "Remove Duplicates",
      "HelpText": "Whether to remove **duplicate** lines when constructing release notes",
      "DefaultValue": "True",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox",
        "Octopus.SelectOptions": "Yes|Yes\nNo|No"
      },
      "Links": {}
    },
    {
      "Id": "301aa2a8-f06b-4904-9636-99189074f224",
      "Name": "Consolidate_RemoveWhitespace",
      "Type": "String",
      "Label": "Remove Blank Lines",
      "HelpText": "Whether to remove **blank** lines when constructing release notes",
      "DefaultValue": "True",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox",
        "Octopus.SelectOptions": "Yes|Yes\nNo|No"
      },
      "Links": {}
    },
    {
      "Id": "517d4aac-e6ae-451c-b18f-be31c6c153b8",
      "Name": "Consolidate_Order",
      "Type": "String",
      "Label": "Concatenation Order",
      "HelpText": "The order in which to append release notes",
      "DefaultValue": "Newest",
      "DisplaySettings": {
        "Octopus.ControlType": "Select",
        "Octopus.SelectOptions": "Newest|Newest to Oldest\nOldest|Oldest to Newest"
      },
      "Links": {}
    }
  ],
  "Properties": {
    "Octopus.Action.Script.Syntax": "PowerShell",
    "Octopus.Action.Script.ScriptSource": "Inline",
    "Octopus.Action.RunOnServer": "true",
    "Octopus.Action.Script.ScriptBody": "$baseUri = $OctopusParameters['#{if Octopus.Web.ServerUri}Octopus.Web.ServerUri#{else}Octopus.Web.BaseUrl#{/if}']\n$reqheaders = @{\"X-Octopus-ApiKey\" = $Consolidate_ApiKey }\n$putReqHeaders = @{\"X-HTTP-Method-Override\" = \"PUT\"; \"X-Octopus-ApiKey\" = $Consolidate_ApiKey }\n\n$remWhiteSpace = [bool]::Parse($Consolidate_RemoveWhitespace)\n$deDupe = [bool]::Parse($Consolidate_Dedupe)\n$reverse = ($Consolidate_Order -eq \"Oldest\")\n\n# Get details we'll need\n$projectId = $OctopusParameters['Octopus.Project.Id']\n$thisReleaseNumber = $OctopusParameters['Octopus.Release.Number']\n$lastSuccessfulReleaseId = $OctopusParameters['Octopus.Release.CurrentForEnvironment.Id']\n$lastSuccessfulReleaseNumber = $OctopusParameters['Octopus.Release.CurrentForEnvironment.Number']\n\nfunction Test-SpacesApi {\n\tWrite-Verbose \"Checking API compatibility\";\n\t$rootDocument = Invoke-WebRequest \"$baseUri/api\" -Headers $reqHeaders -UseBasicParsing | ConvertFrom-Json;\n    if($rootDocument.Links -ne $null -and $rootDocument.Links.Spaces -ne $null) {\n    \tWrite-Verbose \"Spaces API found\"\n    \treturn $true;\n    }\n    Write-Verbose \"Pre-spaces API found\"\n    return $false;\n}\n\nif(Test-SpacesApi) {\n\t$spaceId = $OctopusParameters['Octopus.Space.Id'];\n    if([string]::IsNullOrWhiteSpace($spaceId)) {\n        throw \"This step needs to be run in a context that provides a value for the 'Octopus.Space.Id' system variable. In this case, we received a blank value, which isn't expected - please reach out to our support team at https://help.octopus.com if you encounter this error.\";\n    }\n\t$baseApiUrl = \"/api/$spaceId\" ;\n} else {\n\t$baseApiUrl = \"/api\" ;\n}\n\n# Get all previous releases to this environment\n$releaseUri = \"$baseUri$baseApiUrl/projects/$projectId/releases\"\ntry {\n    $allReleases = Invoke-WebRequest $releaseUri -Headers $reqheaders -UseBasicParsing | ConvertFrom-Json\n} catch {\n    if ($_.Exception.Response.StatusCode.Value__ -ne 404) {\n        $result = $_.Exception.Response.GetResponseStream()\n        $reader = New-Object System.Io.StreamReader($result);\n        $responseBody = $reader.ReadToEnd();\n        throw \"Error occurred: $responseBody\"\n    }\n}\n\n# Find and aggregate release notes\n$aggregateNotes = @()\n\nWrite-Host \"Finding all release notes between the last successful release: $lastSuccessfulReleaseNumber and this release: $thisReleaseNumber\"\nforeach ($rel in $allReleases.Items) {\n    if ($rel.Id -ne $lastSuccessfulReleaseId) {\n        Write-Host \"Found release notes for $($rel.Version)\"\n        $theseNotes = @()\n        #split into lines\n        $lines = $rel.ReleaseNotes -split \"`n\"\n        foreach ($line in $lines) {\n            if (-not $remWhitespace -or -not [string]::IsNullOrWhiteSpace($line)) {\n                if (-not $deDupe -or -not $aggregateNotes.Contains($line)) {\n                    $theseNotes = $theseNotes + $line\n                }\n            }\n        }\n        if ($reverse) {\n            $aggregateNotes = $theseNotes + $aggregateNotes\n        } else {\n            $aggregateNotes = $aggregateNotes + $theseNotes\n        }\n    } else {\n        break\n    }\n}\n$aggregateNotesText = $aggregateNotes -join \"`n`n\"\n\n# Get the current release\n$releaseUri = \"$baseUri$baseApiUrl/projects/$projectId/releases/$thisReleaseNumber\"\ntry {\n    $currentRelease = Invoke-WebRequest $releaseUri -Headers $reqheaders -UseBasicParsing | ConvertFrom-Json\n} catch {\n    if ($_.Exception.Response.StatusCode.Value__ -ne 404) {\n        $result = $_.Exception.Response.GetResponseStream()\n        $reader = New-Object System.Io.StreamReader($result);\n        $responseBody = $reader.ReadToEnd();\n        throw \"Error occurred: $responseBody\"\n    }\n}\n\n# Update the release notes for the current release\n$currentRelease.ReleaseNotes = $aggregateNotesText\nWrite-Host \"Updating release notes for $thisReleaseNumber`:`n`n\"\nWrite-Host $aggregateNotesText\ntry {\n    $releaseUri = \"$baseUri$baseApiUrl/releases/$($currentRelease.Id)\"\n    $currentReleaseBody = $currentRelease | ConvertTo-Json -Depth 10\n    $result = Invoke-WebRequest $releaseUri -Method Post -Headers $putReqHeaders -Body $currentReleaseBody -UseBasicParsing | ConvertFrom-Json\n} catch {\n    $result = $_.Exception.Response.GetResponseStream()\n    $reader = New-Object System.Io.StreamReader($result);\n    $responseBody = $reader.ReadToEnd();\n    Write-Host $responseBody\n    throw \"Error occurred: $responseBody\"\n}",
    "Octopus.Action.Script.ScriptFileName": null,
    "Octopus.Action.Package.FeedId": null,
    "Octopus.Action.Package.PackageId": null
  },
  "Category": "Octopus",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates//opt/buildagent/work/75443764cd38076d/step-templates/octopus-consolidate-releasenotes.json",
  "Website": "/step-templates/fa570d27-1405-4030-87b2-c0abf12bb833",
  "Logo": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1QTFRFT6Tl////L5Pg8vj9Y67omsvwPJrisdfzfbzs5fL7y+T32Ov5isLucLXqvt31CJPHWwAABMJJREFUeNrs3deW4jAMAFDF3U75/89dlp0ZhiU4blJEjvQ8hYubLJsA00UCBCIQgQhEIAIRiEAEIhCBCEQgAhGIQAQiEIEIhD8kJm+t+QprfdKfB9HbYpx6CWfspj8HMi+gMgHL/AmQA8W3JTKH+ALFvzCeL0RbpyoCPE9IJeNOSQwh5Z3qd6yRGWQ2qi2cZQWxqj1WzQYSjeoJmJlAklOd4VlArOqPhQEkqBERToeMcfRJBkC0Uep8CfBpjz4JsHJ0zF3dkEWNje0kiB/sUC6eApndaIiCMyAa1PiwJ0AWhRGJHJJQHG2dC7h1rNbO1QOxSA7lNCkkKrQIpJCAB1GREILYIC1NAiwbpKFJgGWDNExcwGstfExcZBCHC6nOglshHtmhViLIig1RNBCN7qjtW8C0Z1UvJcC1Z9XmwMBzzvobmgAyEzgq91dtEEsBsQSQQAFZCSBAATEEEApHZbrVBIkkEIUPSVeB+KtALA0kXQUSrwKZBCIQBnk8Y4i5CsReBeKvkqLM+BCSDWJlrZFvGk9SRTHshkgjZCGAaArIxm3H3grhVzFlW2msfl1ca79UJ1bofYvsDHHlNdTZnlh5MghuPd5NdBDUNZHyCkfktIh03XzALGRPlBDPac7qgWjHZzWcmF5zmmkhidMQ6boKiDXcDTUEaylZqCGJ0Vjvu/fLJtHqhSANEvqb2OYqkOUqEHuVMbJcZdZCGiPhKhC4yjqiIjEE7XThMp8fAWII3mY3kUIQD+AMKQTzPiBhgQ63HlT/KSvgtoi0dq5mCPah1UIE0eh3sT0NhOByvKeAkFzi8PgQomumFhsyOxpIzZN4gLOj5plVwNpR0b2AuePWKBEHQu24pSsJA+LVCeHHQxZ1SiyDIdqok8IOhSSnTottHEQTdyt4ettAj4KkzA4dMikk2Dht2S5ptm1vswnPDxn0YyDZ5oDM3iToo2T5voWaYe+Q+vdjH80QyAzZhCgcDtLMI1Tmtz9w++XHgziHQHJJu/OZ3bs9Xn8gQ72NcP3dKqEfkp10F51xhoIi2I91R+LurXV/5q7pH+wx061CzO16oSQleMyr8fXvwMA0Pro8432DPD/ySx8XrHfSuDAM8n6UhnjQabaiXf5Bq/lREHvEeNtn1rJ08+C/uXkQZHeguxAPC3UvtcJYUogLzZX5hhZZvS6onG5lxXtzWGaygwb79vT/IXhdlNibwlKYOR6T8xjI7W8n+xV7T+GH4tMzWwR+lZhRkJYSsC0thpmCYqyngOz3rN2FLBZ2wZflBCggUHF0Vnp88JKienzIXLSEZCZqU7IKr/gQW9yx3pzV7Y9kvWZWTRRIqDmTtRUnU7b2lLcTYmoqHqnmiO1poER0SPkAeZMAZxaJx0Y3TCdAclsIqDz03ALcyxfTCZBsthoGXWmigGyVhWPLFJJfuuKQWycoEFdXbH4dJJoJxNR1eD/kshz6yn48cF8yW8sFoitflB1w6Q8n+/15Za7oA17/pYNmYgP5fmWm8L1NOHPWgK8kuFew1/JXtOA0yJCv7ah7X8ObUuT5kObU30+fDZm8+zqP+HTIpK0xQ796b5Kv2hSIQAQiEIEIRCACEYhABCIQgQhEIAIRiEAEIpBf8UeAAQAEjtYmlDTcCgAAAABJRU5ErkJggg==",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Thursday, March 9, 2023