func_Issues.ps1

# ---------------------------------------------------------------------
# Group issues API
# https://docs.gitlab.com/ee/api/issues.html#list-group-issues

# get a list of group issues
function Get-GitlabGroupIssues( [Parameter(Mandatory=$true)] [string] $group
                              , [Parameter(Mandatory=$false)][switch] $closed
                              , [Parameter(Mandatory=$false)][switch] $opened
                              , [Parameter(Mandatory=$false)][string] $assignee
                              , [Parameter(Mandatory=$false)][string] $assignee_id
                              , [Parameter(Mandatory=$false)][string] $labels
                              , [Parameter(Mandatory=$false)][string] $milestone
                              , [Parameter(Mandatory=$false)][string] $search
                              )
{
  [string] $GAPI_ISSUES = "$CI_API_V4_URL/groups/$group/issues?scope=all&per_page=100&order_by=updated_at&sort=asc"

  if ($closed) {
    $GAPI_ISSUES += "&state=closed"
  }
  elseif ($opened) {
    $GAPI_ISSUES += "&state=opened"
  }

  if ($PSBoundParameters.ContainsKey('assignee_id')) {
    $GAPI_ISSUES += "&assignee_id=$assignee_id"
  }
  elseif ($PSBoundParameters.ContainsKey('assignee')) {
    $GAPI_ISSUES += "&assignee_username=$assignee"
  }

  if ($PSBoundParameters.ContainsKey('labels')) {
    $labels = [uri]::EscapeDataString($labels)
    $GAPI_ISSUES += "&labels=$labels"
  }

  if ($PSBoundParameters.ContainsKey('milestone')) {
    $milestone = [uri]::EscapeDataString($milestone)
    $GAPI_ISSUES += "&milestone=$milestone"
  }

  if (![string]::IsNullOrWhiteSpace($search)) {
    $search = [uri]::EscapeDataString($search)
    $GAPI_ISSUES += "&search=$search"
  }

  return @(Invoke-WebRequestContentToJson -headers $GLPT -uri $GAPI_ISSUES)
}


# ---------------------------------------------------------------------
# Issues API
# https://docs.gitlab.com/ee/api/issues.html

# get a list of issues from project
function Get-GitlabIssues( [Parameter(Mandatory=$true)] [string] $project
                         , [Parameter(Mandatory=$false)][switch] $closed
                         , [Parameter(Mandatory=$false)][switch] $opened
                         , [Parameter(Mandatory=$false)][string] $assignee
                         , [Parameter(Mandatory=$false)][string] $assignee_id
                         , [Parameter(Mandatory=$false)][string] $labels
                         , [Parameter(Mandatory=$false)][string] $milestone
                         , [Parameter(Mandatory=$false)][string] $milestone_id
                         , [Parameter(Mandatory=$false)][string] $search
                         , [Parameter(Mandatory=$false)][switch] $search_desc
                         , [Parameter(Mandatory=$false)][switch] $search_title
                         , [Parameter(Mandatory=$false)][string] $type
                         )
{
  [string] $GAPI_ISSUES = "$CI_API_V4_URL/projects/$project/issues?scope=all&per_page=100&order_by=updated_at&sort=asc"

  if ($closed) {
    $GAPI_ISSUES += "&state=closed"
  }
  elseif ($opened) {
    $GAPI_ISSUES += "&state=opened"
  }

  if ($PSBoundParameters.ContainsKey('assignee_id')) {
    $GAPI_ISSUES += "&assignee_id=$assignee_id"
  }
  elseif ($PSBoundParameters.ContainsKey('assignee')) {
    $GAPI_ISSUES += "&assignee_username=$assignee"
  }

  if ($PSBoundParameters.ContainsKey('labels')) {
    $GAPI_ISSUES += "&labels=$labels"
  }

  if ($PSBoundParameters.ContainsKey('milestone_id')) {
    $GAPI_ISSUES += "&milestone_id=$milestone_id"
  }
  elseif ($PSBoundParameters.ContainsKey('milestone')) {
    $milestone = [uri]::EscapeDataString($milestone)
    $GAPI_ISSUES += "&milestone=$milestone"
  }

  if (![string]::IsNullOrWhiteSpace($search)) {
    $search = [uri]::EscapeDataString($search)
    $GAPI_ISSUES += "&search=$search"

    if ($search_desc) {
      $GAPI_ISSUES += "&in=description"
    }
    elseif ($search_title) {
      $GAPI_ISSUES += "&in=title"
    }
  }

  if ($PSBoundParameters.ContainsKey('type')) {
    $GAPI_ISSUES += "&issue_type=$type"
  }

  return @(Invoke-WebRequestContentToJson -headers $GLPT -uri $GAPI_ISSUES)
}

# get a single issue
function Get-GitlabIssue( [Parameter(Mandatory=$true)] [string] $project
                        , [Parameter(Mandatory=$true)] [string] $iid
                        )
{
  [string] $GAPI_ISSUES_IID = "$CI_API_V4_URL/projects/$project/issues/$iid"
  return (Invoke-RestMethod -headers $GLPT -uri $GAPI_ISSUES_IID -method GET)
}

# modify an existing issue
function Set-GitlabIssue( [Parameter(Mandatory=$true)] [string] $project
                        , [Parameter(Mandatory=$true)] [string] $iid
                        , [Parameter(Mandatory=$false)][switch] $close
                        , [Parameter(Mandatory=$false)][switch] $reopen
                        , [Parameter(Mandatory=$false)][string] $assignee
                        , [Parameter(Mandatory=$false)][string] $assignee_id
                        , [Parameter(Mandatory=$false)][string] $description
                        , [Parameter(Mandatory=$false)][string] $add_labels
                        , [Parameter(Mandatory=$false)][string] $remove_labels
                        , [Parameter(Mandatory=$false)][string] $labels
                        , [Parameter(Mandatory=$false)][string] $milestone
                        , [Parameter(Mandatory=$false)][string] $milestone_id
                        , [Parameter(Mandatory=$false)][string] $title
                        , [Parameter(Mandatory=$false)][string] $type
                        )
{
  [string] $GAPI_ISSUES_IID = "$CI_API_V4_URL/projects/$project/issues/$iid"
  $body_json = @{}

  if ($close) {
    $body_json += @{ "state_event" = "close" }
  }
  elseif ($reopen) {
    $body_json += @{ "state_event" = "reopen" }
  }

  if ($PSBoundParameters.ContainsKey('assignee_id')) {
    $body_json += @{ "assignee_ids" = @( $assignee_id ) }
  }
  elseif ($PSBoundParameters.ContainsKey('assignee')) {
    $assignee_id = Get-GitlabUserID $assignee
    $body_json += @{ "assignee_ids" = @( $assignee_id ) }
  }

  if ($PSBoundParameters.ContainsKey('description')) {
    [string] $desc_coded = $description -replace "\r\n", "`n"
    $body_json += @{ "description" = "$desc_coded" }
  }

  if ($PSBoundParameters.ContainsKey('add_labels')) {
    $body_json += @{ "add_labels" = "$add_labels" }
  }
  elseif ($PSBoundParameters.ContainsKey('remove_labels')) {
    $body_json += @{ "remove_labels" = "$remove_labels" }
  }
  elseif ($PSBoundParameters.ContainsKey('labels')) {
    $body_json += @{ "labels" = "$labels" }
  }

  if ($PSBoundParameters.ContainsKey('milestone_id')) {
    $body_json += @{ "milestone_id" = $milestone_id }
  }
  elseif ($PSBoundParameters.ContainsKey('milestone')) {
    $milestone_id = Get-GitlabMilestoneID -project $project -title $milestone
    $body_json += @{ "milestone_id" = $milestone_id }
  }

  if ($PSBoundParameters.ContainsKey('title')) {
    $body_json += @{ "title" = "$title" }
  }

  if ($PSBoundParameters.ContainsKey('type')) {
    $body_json += @{ "issue_type" = "$type" }
  }

  if (!$body_json.Count) { return $null }
  [string] $body = $body_json | ConvertTo-Json -depth 10

  return (Invoke-RestMethod -headers $GLPT -uri $GAPI_ISSUES_IID -method PUT -ContentType 'application/json' -body $body)
}

# create a new project issue
# title and description can contain unescaped quotes "
# description can be multiline, but markdown formatted
function New-GitlabIssue( [Parameter(Mandatory=$true)] [string] $project
                        , [Parameter(Mandatory=$true)] [string] $title
                        , [Parameter(Mandatory=$false)][string] $author
                        , [Parameter(Mandatory=$false)][string] $assignee
                        , [Parameter(Mandatory=$false)][string] $assignee_id
                        , [Parameter(Mandatory=$false)][string] $description
                        , [Parameter(Mandatory=$false)][string] $labels
                        , [Parameter(Mandatory=$false)][string] $milestone
                        , [Parameter(Mandatory=$false)][string] $milestone_id
                        , [Parameter(Mandatory=$false)][string] $type
                        )
{
  [string] $GAPI_ISSUES = "$CI_API_V4_URL/projects/$project/issues"
  if ($PSBoundParameters.ContainsKey('author')) {
    $GAPI_ISSUES += "?sudo=$author"
  }

  [string] $title_coded = $title.Trim(" .")
           $title_coded = $title_coded -replace '[\u201C\u201D\u201E\u201F]', '"' # “”„‟

  [string] $desc_coded = $description -replace "\r\n", "`n"
           $desc_coded = $desc_coded  -replace '[\u201C\u201D\u201E\u201F]', '"'  # “”„‟

  $body_json = @{ "title"       = "$title_coded";
                  "description" = "$desc_coded";
                }

  if ($PSBoundParameters.ContainsKey('assignee_id')) {
    $body_json += @{ "assignee_ids" = @( $assignee_id ) }
  }
  elseif ($PSBoundParameters.ContainsKey('assignee')) {
    $assignee_id = Get-GitlabUserID $assignee
    $body_json += @{ "assignee_ids" = @( $assignee_id ) }
  }

  if ($PSBoundParameters.ContainsKey('labels')) {
    $body_json += @{ "labels" = "$labels" }
  }

  if ($PSBoundParameters.ContainsKey('milestone_id')) {
    $body_json += @{ "milestone_id" = $milestone_id }
  }
  elseif ($PSBoundParameters.ContainsKey('milestone')) {
    $milestone_id = Get-GitlabMilestoneID -project $project -title $milestone
    $body_json += @{ "milestone_id" = $milestone_id }
  }

  if ($PSBoundParameters.ContainsKey('title')) {
    $body_json += @{ "title" = "$title" }
  }

  if ($PSBoundParameters.ContainsKey('type')) {
    $body_json += @{ "issue_type" = "$type" }
  }

  [string] $body = $body_json | ConvertTo-Json -depth 10
  return (Invoke-RestMethod -headers $GLPT -uri $GAPI_ISSUES -method POST -ContentType 'application/json' -body $body)
}

# delete an issue
function Remove-GitlabIssue( [Parameter(Mandatory=$true)] [string] $project
                           , [Parameter(Mandatory=$true)] [string] $iid
                           )
{
  [string] $GAPI_ISSUES_IID = "$CI_API_V4_URL/projects/$project/issues/$iid"
  return (Invoke-RestMethod -headers $GLPT -uri $GAPI_ISSUES_IID -method DELETE)
}

# get all the merge requests that are related to the issue
function Get-GitlabIssueRelatedMergeRequests( [Parameter(Mandatory=$true)] [string] $project
                                            , [Parameter(Mandatory=$true)] [string] $iid
                                            )
{
  [string] $GAPI_ISSUES_IID = "$CI_API_V4_URL/projects/$project/issues/$iid/related_merge_requests"
  return @(Invoke-RestMethod -headers $GLPT -uri $GAPI_ISSUES_IID -method GET)
}

# get all merge requests that close a particular issue when merged
function Get-GitlabMergeRequestsClosedByIssue( [Parameter(Mandatory=$true)] [string] $project
                                             , [Parameter(Mandatory=$true)] [string] $issue_iid
                                             )
{
  [string] $GAPI_ISSUES_IID = "$CI_API_V4_URL/projects/$project/issues/$issue_iid/closed_by"
  return @(Invoke-RestMethod -headers $GLPT -uri $GAPI_ISSUES_IID -method GET)
}