import Ajv from 'ajv' ; import schema from './repo-metadata-schema.json' ; import * as fileIterator from './file-iterator' ; import { OctokitType } from './utils/octokit-util' ; export interface ValidationResult { status : 'success' | 'error' ; errors : Array < string > ; } const API_LIBRARY_TYPES = [ 'GAPIC_AUTO' , 'GAPIC_MANUAL' , 'AGENT' , 'GAPIC_COMBO' , ] ; const GOOGLEAPIS_OWNER = 'googleapis' ; const GOOGLEAPIS_REPO = 'googleapis' ; export class Validate { octokit : OctokitType ; cachedApiIndex ? : string ; constructor ( octokit ) { this . octokit = octokit ; } async validate ( path , repoMetadataContent ) { const ajv = new Ajv ( { allErrors : true , } ) ; const validate = ajv . compile ( schema ) ; const result = { status : 'success' , errors : [ ] } ; try { JSON . parse ( repoMetadataContent ) ; } catch ( err ) { result . status = 'error' ; result . errors . push ( `could not parse ${ path }` ) ; return result ; } const repoMetadata = JSON . parse ( repoMetadataContent ) ; const valid = validate ( repoMetadata ) ; if ( valid === false ) { result . status = 'error' ; for ( const error of validate . errors || [ ] ) { result . errors . push ( `${ error . instancePath ? error . instancePath . replace ( /^\/(.*)/ , '$1 ' ) : '' }${ error . message } in ${ path }` ) ; } } if ( API_LIBRARY_TYPES . includes ( repoMetadata . library_type ) ) { if ( ! repoMetadata . api_shortname ) { result . status = 'error' ; result . errors . push ( `api_shortname field missing from ${ path }` ) ; } else { const apiShortNames = await this . validApiShortNames ( ) ; if ( ! apiShortNames . has ( repoMetadata . api_shortname ) ) { result . status = 'error' ; result . errors . push ( `api_shortname '${ repoMetadata . api_shortname }' invalid in ${ path }` ) ; } } } return result ; } async validApiShortNames ( ) { if ( ! this . cachedApiIndex ) { const iterator = new fileIterator . FileIterator ( GOOGLEAPIS_OWNER , GOOGLEAPIS_REPO , this . octokit ) ; this . cachedApiIndex = await iterator . getFile ( 'api-index-v1.json' ) ; } const apiIndex = JSON . parse ( this . cachedApiIndex ) as { apis : Array < { hostName : string ; } > ; } ; const apiShortNames = new Set < string > ( ) ; for ( const api of apiIndex . apis ) { const match = api . hostName . match ( /(?<service>[^.]+)/ ) ; if ( match && match . groups ) { apiShortNames . add ( match . groups . service ) ; } } return apiShortNames ; } }