modules/IssueProcessor/Jira/JiraProvider.psm1


using module '..\Enums.psm1'
using module '..\Issue.psm1'
using module '.\JiraReleaseNotes.psm1'
using module '.\JiraTechnicalNotes.psm1'

class JiraIssue {

    #region Properties

    hidden [string] $pathApi = "rest/api/2/search"
    hidden [string] $queryStrings = "jql=project={0}%20and%20fixVersion={1}%20order%20by%20issueType&startAt={2}"

    hidden [hashtable] $rejected = @('Won''t Fix', 'Duplicate', 'Incomplete', '"Won''t Do', 'Cannot Reproduce', 'Declined')
    hidden [string] $resolution = "Declined, {0}"
    hidden [hashtable] $publicStatuses = @('Closed', 'Blocked')
    hidden [string] $maskStatus = 'Blocked'

    hidden [string] $baseUrl
    hidden [string] $userName
    hidden [string] $password

    [string] $projectName
    [string] $releaseStage
    [Issue[]] $issues

    [string] $version
    [string] $build

    #endregion

    JiraIssue([PSCustomObject] $settings, [string] $releaseStage, [string] $build){
        $this.baseUrl = $settings.jira.url
        $this.userName = $settings.jira.userName
        $this.password = $settings.jira.password

        $this.releaseStage = $releaseStage
        $this.build = $build
    }

    #region Private methods

    hidden [string] getVersionAndBuild(){
        if ($this.build) {
            return $this.version + '.' + $this.build
        }
        else{
            return $this.version
        }
    }

    hidden [hashtable] getHeaders(){

        $pair = ("{0}:{1}" -f @($this.userName, $this.password))
        $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
        $basicAuthValue = "Basic $encodedCreds"

        $headers = @{
            Authorization = $basicAuthValue
        }

        return $headers
    }

    hidden [Issue[]] convertToIssues([PSCustomObject] $issues, [PUBLIC_STATUS] $statusFormat){
        $allIssues = @()

        foreach ($issue in $issues){
            [Issue] $item = [Issue]::new()

            $item.linkedIssues = @()

            $item.Key = $issue.key
            $item.summary = $issue.fields.summary
            $item.type = $issue.fields.issueType.name

            $item.statusRaw = $issue.fields.status.name
            $item.status = $this.resolveStatus($issue.fields.status.name, $statusFormat)

            $item.resolutionRaw = $issue.fields.resolution.name
            $item.resolution = $this.resolveResolution($issue.fields.resolution.name)

            $item.assignee = $issue.fields.assignee.displayName
            $item.priority = $issue.fields.priority.name

            $item.priorityIcon = $issue.fields.priority.iconUrl
            foreach ($linkIssue in $issue.fields.issuelinks){
                if ($linkIssue.inwardIssue){
                    $item.linkedIssues.add($linkIssue.inwardIssue.key, $linkIssue.type.inward)
                }

                if ($linkIssue.outwardIssue){
                    $item.linkedIssues.add($linkIssue.outwardIssue.key, $linkIssue.type.outwardIssue)
                }
            }

            $item.developerNotes = $issue.fields.customfield_12701
            $item.configurationChanges = $issue.fields.customfield_12702
            $item.databaseChanges = $issue.fields.customfield_12703

            $allIssues += $item
        }

        return $allIssues
    }

    hidden [string] resolveResolution([string] $resolution){
        if ($resolution -in $this.rejected) {
            return $this.resolution -f $resolution
        }
        else {
            return $resolution
        }
    }

    hidden [string] resolveStatus([string] $status, [PUBLIC_STATUS] $statusFormat){
        switch ($statusFormat) {
            ([PUBLIC_STATUS]::AsIs) { }
            ([PUBLIC_STATUS]::Masked) { if (-not ($status -in $this.publicStatuses)) { return $this.maskStatus } }
        }

        return $status
    }
    #endregion

    [void] getIssues([string] $projectKey, [string] $version, [PUBLIC_STATUS] $statusFormat){

        $this.version = $version

        $headers = $this.getHeaders()

        # Load Issues
        $this.issue = @(); $start=0
        do {
            $url = '{0}/{1}?{2}' -f @($this.baseUrl, $this.searchApi, ($this.queryStrings -f @($projectKey, $version, $start)))

            $response = Invoke-JsonRequest -Uri $url -Headers $headers

            $this.issue += $this.convertToIssues($response.issues, $statusFormat)
            $this.projectName = $this.response.issues[0].fields.project.name

            Write-Host ('Load JIRA issues, {0} from {1}' -f @($start + [int]$this.queryStrings.maxResults, $this.queryStrings.total))
            $start = $start + $this.queryStrings.maxResults

        } while ($start -lt $this.queryStrings.total)
    }

    [object] FormatReleaseNotes([OUTPUT_TYPE] $output){
        $notes = [JiraReleaseNotes]::new($this.projectName, $this.issues)

        switch ($output) {
            ([OUTPUT_TYPE]::Text) { return $notes.getAsObject() }
            ([OUTPUT_TYPE]::Html) { return $notes.AsHtml($this.releaseStage, $this.getVersionAndBuild()) }
        }

        return $null
    }

    [object] FormatTechnicalNotes([OUTPUT_TYPE] $output){
        $notes = [JiraTechnicalNotes]::new($this.projectName, $this.issues)

        switch ($output) {
            ([OUTPUT_TYPE]::Text) { return $notes.getAsObject() }
            ([OUTPUT_TYPE]::Html) { return $notes.AsHtml($this.releaseStage, $this.getVersionAndBuild()) }
        }

        return $null
    }
}