Public/Update-JiraTicket.ps1

function Update-JiraTicket {
    <#
    .SYNOPSIS
        Updates a Jira Cloud issue: transitions it, changes fields and/or adds a comment.
    .DESCRIPTION
        Performs the requested changes in this order, each as a separate REST call:
        1. -MarkDone / -MarkResolved: moves the issue to the 'Done' or 'Resolved' status, like
           Invoke-JiraIssueTransition -Status Done (or Resolved). The transition is chosen by its
           target status first, then by its exact name.
        2. -Summary / -OptionalFields: PUT /rest/api/3/issue/<key> with the fields.
        3. -Comment: POST /rest/api/3/issue/<key>/comment (the text is sent as an ADF paragraph).

        A failed transition (including when no transition leads to the status) or field update
        writes a non-terminating error and the remaining changes are still attempted; use
        -ErrorAction Stop to stop on the first failure. A failed comment is a terminating error
        (the original error from Invoke-JiraRequest). Supports -WhatIf and -Confirm.

        Issue keys can be piped in, for example from Find-JiraIssue (any object with an IssueKey
        or Key property).
    .PARAMETER IssueKey
        The issue key or id, for example PROJ-123. Accepts pipeline input by property name
        (IssueKey or Key).
    .PARAMETER Summary
        A new summary for the issue.
    .PARAMETER Comment
        A plain-text comment to add to the issue.
    .PARAMETER OptionalFields
        A hashtable of other fields to set, keyed by field id, for example @{ labels = @('ops') }.
    .PARAMETER MarkDone
        Transitions the issue to the Done status.
    .PARAMETER MarkResolved
        Transitions the issue to the Resolved status.
    .EXAMPLE
        Update-JiraTicket -IssueKey 'PROJ-123' -Comment 'Deployed to production' -MarkDone

        Transitions the issue to Done and adds a comment.
    .EXAMPLE
        Update-JiraTicket -IssueKey 'PROJ-123' -Summary 'New title' -OptionalFields @{ labels = @('ops', 'urgent') }

        Changes the summary and labels.
    .EXAMPLE
        Find-JiraIssue -JQL 'project = PROJ AND labels = stale' | Update-JiraTicket -Comment 'Closing stale issue' -MarkDone

        Comments on and closes every issue that the query returns.
    .OUTPUTS
        None.
    #>

    [CmdletBinding(DefaultParameterSetName = 'Default', SupportsShouldProcess = $true)]
    param (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Default')]
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'MarkDone')]
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'MarkResolved')]
        [Alias('Key')]
        [ValidatePattern('^([A-Za-z][A-Za-z0-9_]*-\d+|\d+)$')]
        [string]$IssueKey,

        [Parameter(ParameterSetName = 'Default', HelpMessage = 'A new summary for the ticket.')]
        [Parameter(ParameterSetName = 'MarkDone', HelpMessage = 'A new summary for the ticket.')]
        [Parameter(ParameterSetName = 'MarkResolved', HelpMessage = 'A new summary for the ticket.')]
        [string]$Summary,

        [Parameter(ParameterSetName = 'Default', HelpMessage = 'A new comment to add to the ticket.')]
        [Parameter(ParameterSetName = 'MarkDone', HelpMessage = 'A new comment to add to the ticket.')]
        [Parameter(ParameterSetName = 'MarkResolved', HelpMessage = 'A new comment to add to the ticket.')]
        [string]$Comment,

        [Parameter(ParameterSetName = 'Default', HelpMessage = 'A hashtable of other fields to update.')]
        [Parameter(ParameterSetName = 'MarkDone', HelpMessage = 'A hashtable of other fields to update.')]
        [Parameter(ParameterSetName = 'MarkResolved', HelpMessage = 'A hashtable of other fields to update.')]
        [hashtable]$OptionalFields,

        [Parameter(Mandatory = $true, ParameterSetName = 'MarkDone', HelpMessage = 'Mark the ticket as Done (transition to Done status)')]
        [switch]$MarkDone,

        [Parameter(Mandatory = $true, ParameterSetName = 'MarkResolved', HelpMessage = 'Mark the ticket as Resolved (transition to Resolved status)')]
        [switch]$MarkResolved
    )

    process {
        $TelemetryArgs = @{
            ModuleName    = $MyInvocation.MyCommand.Module.Name
            ModuleVersion = [string]$MyInvocation.MyCommand.Module.Version
            CommandName   = $MyInvocation.MyCommand.Name
            ExecutionID   = [guid]::NewGuid().ToString()
        }
        Invoke-TelemetryCollection @TelemetryArgs -Stage Start -ClearTimer
        try {
            if (-not $Summary -and -not $Comment -and -not $OptionalFields -and -not $MarkDone -and -not $MarkResolved) {
                throw 'You must provide at least one of -Summary, -Comment, -OptionalFields, -MarkDone or -MarkResolved to update a ticket.'
            }
            Write-Verbose "Starting Update-JiraTicket for '$IssueKey'"

            # --- Transition (Done / Resolved) ---
            $targetStatus = $null
            if ($MarkDone) { $targetStatus = 'Done' }
            if ($MarkResolved) { $targetStatus = 'Resolved' }
            if ($targetStatus -and $PSCmdlet.ShouldProcess($IssueKey, "Transition to $targetStatus")) {
                try {
                    $null = Invoke-JiraTransitionRequest -IssueKey $IssueKey -Status $targetStatus
                    Write-Verbose "Ticket $IssueKey transitioned to $targetStatus."
                }
                catch {
                    $failure = New-Object -TypeName System.InvalidOperationException -ArgumentList "Failed to transition ticket $IssueKey to $targetStatus. $($_.Exception.Message)", $_.Exception
                    Write-Error -Exception $failure -Category $_.CategoryInfo.Category -ErrorId 'JiraTransitionFailed' -TargetObject $IssueKey
                }
            }

            # --- Update fields ---
            Invoke-JiraFieldUpdate -Cmdlet $PSCmdlet -IssueKey $IssueKey -Summary $Summary -SetSummary:($PSBoundParameters.ContainsKey('Summary')) -OptionalFields $OptionalFields -Description 'ticket'

            # --- Add comment (a failure rethrows the original error) ---
            if ($PSBoundParameters.ContainsKey('Comment') -and $PSCmdlet.ShouldProcess($IssueKey, 'Add comment')) {
                $null = Add-JiraIssueComment -IssueKey $IssueKey -Text $Comment
            }

            Write-Verbose "Finished Update-JiraTicket for '$IssueKey'"
            Invoke-TelemetryCollection @TelemetryArgs -Stage End
        }
        catch {
            Invoke-TelemetryCollection @TelemetryArgs -Stage End -Failed $true -Exception $_
            throw
        }
    }
}