import { Octokit } from '@octokit/rest' ; import { Endpoints } from '@octokit/types' ; import { RegionTagLocation } from './region-tag-parser' ; import { Violation } from './violations' ; type createCheckParams = Endpoints [ 'POST /repos/{owner}/{repo}/check-runs' ] [ 'parameters' ] ; type createCheckResponse = Endpoints [ 'POST /repos/{owner}/{repo}/check-runs' ] [ 'response' ] ; interface File { content : string | undefined ; } export function isFile ( file ) { return ( file as File ) . content !== undefined ; } export type Conclusion = 'success' | 'failure' | 'neutral' | 'cancelled' | 'timed_out' | 'action_required' | undefined ; /**
 * Formats the full scan report with the comment mark, so that it can
 * preserve original contents.
 */ export const formatBody = ( originalBody , commentMark , addition ) : string => { const markIndex = originalBody . indexOf ( commentMark ) ; if ( markIndex >= 0 ) { originalBody = originalBody . substr ( 0 , markIndex ) ; } return `${ originalBody }${ commentMark }

${ addition }

---
Report generated by [snippet-bot](https://github.com/apps/snippet-bot).
If you find problems with this result, please file an issue at:
https://github.com/googleapis/repo-automation-bots/issues.
` ; } ; /**
 * Formats the summary and detail as an expandable UI in the markdown.
 */ export const formatExpandable = ( summary , detail ) : string => { return `<details>
  <summary>${ summary }</summary>

  ${ detail }
</details>

` ; } ; /**
 * Formats a region tag location as a markdown with a permalink to the code.
 */ export const formatRegionTag = ( loc ) : string => { const url = `https://github.com/${ loc . owner }/${ loc . repo }/blob/${ loc . sha }/${ loc . file }#L${ loc . line }` ; return `[${ loc . file }:${ loc . line }](${ url }), tag \`${ loc . regionTag }\`` ; } ; /**
 * Formats an array of Violations for commenting.
 */ export const formatViolations = ( violations , summary ) : string => { let detail = '' ; for ( const violation of violations ) { detail += `- ${ formatRegionTag ( violation . location ) }` ; if ( violation . devsite_urls . length > 0 ) { detail += '(usage:' ; violation . devsite_urls . forEach ( ( value , index ) => { detail += ` [page ${ index + 1 }](${ value })` ; } ) ; detail += ').\n' ; } else { detail += '\n' ; } } return formatExpandable ( summary , detail ) ; } ; /**
 * Formats a violation for unmatched region tag.
 */ export const formatMatchingViolation = ( violation ) : string => { let detail = '' ; if ( violation . violationType === 'NO_MATCHING_START_TAG' ) { detail = "doesn't have a matching start tag." ; } else if ( violation . violationType === 'NO_MATCHING_END_TAG' ) { detail = "doesn't have a matching end tag." ; } else if ( violation . violationType === 'TAG_ALREADY_STARTED' ) { detail = 'already started.' ; } return `${ formatRegionTag ( violation . location ) } ${ detail }` ; } ; function aggregateCheckParams ( checks , title ) { let conclusion = 'success' ; let summary = `${ title } success` ; let text = '' ; for ( const check of checks ) { if ( check . conclusion === 'failure' ) { conclusion = check . conclusion ; summary = `${ title } failure` ; text += formatExpandable ( check . output ! . summary , check . output ! . text as string ) ; } } if ( conclusion === 'success' ) { text = `${ title } success` ; } return { owner : checks [ 0 ] . owner , repo : checks [ 0 ] . repo , name : title , conclusion : conclusion , head_sha : checks [ 0 ] . head_sha , output : { title : title , summary : summary , text : text , } , } ; } /**
 * Checks aggregator.
 */ export class CheckAggregator { private octokit : Octokit ; private checkParams : Array < createCheckParams > ; private checkTitle : string ; private aggregateChecks : boolean ; private promises : Array < Promise < createCheckResponse > > ; constructor ( octokit , checkTitle , aggregateChecks ) { this . octokit = octokit ; this . checkTitle = checkTitle ; this . checkParams = new Array < createCheckParams > ( ) ; this . aggregateChecks = aggregateChecks ; this . promises = new Array < Promise < createCheckResponse > > ( ) ; } public async add ( checkParams ) { if ( this . aggregateChecks ) { this . checkParams . push ( checkParams ) ; } else { this . promises . push ( this . octokit . checks . create ( checkParams ) ) ; } } public async submit ( ) { if ( this . aggregateChecks ) { if ( this . checkParams . length === 0 ) { return ; } const checkParams = aggregateCheckParams ( this . checkParams , this . checkTitle ) ; await this . octokit . checks . create ( checkParams ) ; } else { await Promise . all ( this . promises ) ; return ; } } }