11import fetch from 'node-fetch' ;
22import { normalizePath } from '../utils/normalizePath' ;
3+ import { fetchVersionData } from '../utils/fetchVersionData' ;
34import { RedocExecutor } from './redocExecutor' ;
4- import { findLastSavedGitHash } from './database' ;
5+ import { findLastSavedVersionData , saveSuccessfulBuildVersionData } from './database' ;
56import { OASPageMetadata , PageBuilderOptions , RedocBuildOptions } from './types' ;
7+ import { VersionData } from './models/OASFile' ;
68
79const OAS_FILE_SERVER = 'https://mongodb-mms-prod-build-server.s3.amazonaws.com/openapi/' ;
10+ const GIT_HASH_URL = 'https://cloud.mongodb.com/version' ;
811
912const fetchTextData = async ( url : string , errMsg : string ) => {
1013 const res = await fetch ( url ) ;
@@ -15,12 +18,44 @@ const fetchTextData = async (url: string, errMsg: string) => {
1518 return res . text ( ) ;
1619} ;
1720
21+ const createFetchGitHash = ( ) => {
22+ let gitHashCache : string ;
23+ return {
24+ fetchGitHash : async ( ) => {
25+ if ( gitHashCache ) return gitHashCache ;
26+ try {
27+ const gitHash = await fetchTextData ( GIT_HASH_URL , 'Could not find current version or git hash' ) ;
28+ gitHashCache = gitHash ;
29+ return gitHash ;
30+ } catch ( e ) {
31+ console . error ( e ) ;
32+ throw new Error ( `Unsuccessful git hash fetch` ) ;
33+ }
34+ } ,
35+ resetGitHashCache : ( ) => {
36+ gitHashCache = '' ;
37+ } ,
38+ } ;
39+ } ;
40+
41+ const { fetchGitHash, resetGitHashCache } = createFetchGitHash ( ) ;
42+
1843interface AtlasSpecUrlParams {
1944 apiKeyword : string ;
2045 apiVersion ?: string ;
2146 resourceVersion ?: string ;
2247}
2348
49+ const ensureSavedVersionDataMatches = ( versions : VersionData , apiVersion ?: string , resourceVersion ?: string ) => {
50+ // Check that requested versions are included in saved version data
51+ if ( apiVersion ) {
52+ if ( ! versions . major . includes ( apiVersion ) || ( resourceVersion && ! versions [ apiVersion ] . includes ( resourceVersion ) ) ) {
53+ throw new Error ( `Last successful build data does not include necessary version data:\n
54+ Version requested: ${ apiVersion } ${ resourceVersion ? ` - ${ resourceVersion } ` : `` } ` ) ;
55+ }
56+ }
57+ } ;
58+
2459const getAtlasSpecUrl = async ( { apiKeyword, apiVersion, resourceVersion } : AtlasSpecUrlParams ) => {
2560 // Currently, the only expected API fetched programmatically is the Cloud Admin API,
2661 // but it's possible to have more in the future with varying processes.
@@ -34,10 +69,10 @@ const getAtlasSpecUrl = async ({ apiKeyword, apiVersion, resourceVersion }: Atla
3469 } `;
3570
3671 let oasFileURL ;
72+ let successfulGitHash = true ;
3773
3874 try {
39- const versionURL = 'https://cloud.mongodb.com/version' ;
40- const gitHash = await fetchTextData ( versionURL , 'Could not find current version or git hash' ) ;
75+ const gitHash = await fetchGitHash ( ) ;
4176 oasFileURL = `${ OAS_FILE_SERVER } ${ gitHash } ${ versionExtension } .json` ;
4277
4378 // Sometimes the latest git hash might not have a fully available spec file yet.
@@ -46,17 +81,22 @@ const getAtlasSpecUrl = async ({ apiKeyword, apiVersion, resourceVersion }: Atla
4681 await fetchTextData ( oasFileURL , `Error fetching data from ${ oasFileURL } ` ) ;
4782 } catch ( e ) {
4883 console . error ( e ) ;
84+ successfulGitHash = false ;
4985
50- const res = await findLastSavedGitHash ( apiKeyword ) ;
86+ const res = await findLastSavedVersionData ( apiKeyword ) ;
5187 if ( res ) {
88+ ensureSavedVersionDataMatches ( res . versions , apiVersion , resourceVersion ) ;
5289 oasFileURL = `${ OAS_FILE_SERVER } ${ res . gitHash } ${ versionExtension } .json` ;
5390 console . log ( `Using ${ oasFileURL } ` ) ;
5491 } else {
5592 throw new Error ( `Could not find a saved hash for API: ${ apiKeyword } ` ) ;
5693 }
5794 }
5895
59- return oasFileURL ;
96+ return {
97+ oasFileURL,
98+ successfulGitHash,
99+ } ;
60100} ;
61101
62102interface GetOASpecParams {
@@ -82,14 +122,21 @@ async function getOASpec({
82122} : GetOASpecParams ) {
83123 try {
84124 let spec = '' ;
125+ let isSuccessfulBuild = true ;
85126 const buildOptions : RedocBuildOptions = { } ;
86127 if ( sourceType === 'url' ) {
87128 spec = source ;
88129 } else if ( sourceType === 'local' ) {
89130 const localFilePath = normalizePath ( `${ repoPath } /source/${ source } ` ) ;
90131 spec = localFilePath ;
91132 } else if ( sourceType === 'atlas' ) {
92- spec = await getAtlasSpecUrl ( { apiKeyword : source , apiVersion, resourceVersion } ) ;
133+ const { oasFileURL, successfulGitHash } = await getAtlasSpecUrl ( {
134+ apiKeyword : source ,
135+ apiVersion,
136+ resourceVersion,
137+ } ) ;
138+ spec = oasFileURL ;
139+ isSuccessfulBuild = successfulGitHash ;
93140 // Ignore "incompatible types" warnings for Atlas Admin API/cloud-docs
94141
95142 buildOptions [ 'ignoreIncompatibleTypes' ] = true ;
@@ -102,8 +149,10 @@ async function getOASpec({
102149 const path = `${ output } /${ pageSlug } ${ filePathExtension } /index.html` ;
103150 const finalFilename = normalizePath ( path ) ;
104151 await redocExecutor . execute ( spec , finalFilename , buildOptions ) ;
152+ return isSuccessfulBuild ;
105153 } catch ( e ) {
106154 console . error ( e ) ;
155+ return false ;
107156 }
108157}
109158
@@ -114,6 +163,7 @@ export const buildOpenAPIPages = async (
114163 const redocExecutor = new RedocExecutor ( redocPath , siteUrl , siteTitle ) ;
115164
116165 for ( const [ pageSlug , data ] of entries ) {
166+ let totalSuccess = true ;
117167 const { source_type : sourceType , source, api_version : apiVersion , resource_versions : resourceVersions } = data ;
118168
119169 if ( ! apiVersion && resourceVersions && resourceVersions . length > 0 ) {
@@ -127,10 +177,41 @@ export const buildOpenAPIPages = async (
127177 // if a resource versions array is provided, then we can loop through the resourceVersions array and call the getOASpec
128178 // for each minor version
129179 for ( const resourceVersion of resourceVersions ) {
130- await getOASpec ( { source, sourceType, output, pageSlug, redocExecutor, repoPath, apiVersion, resourceVersion } ) ;
180+ const isSuccessfulBuild = await getOASpec ( {
181+ source,
182+ sourceType,
183+ output,
184+ pageSlug,
185+ redocExecutor,
186+ repoPath,
187+ apiVersion,
188+ resourceVersion,
189+ } ) ;
190+ if ( ! isSuccessfulBuild ) totalSuccess = false ;
131191 }
132192 }
133193 // apiVersion can be undefined, this case is handled within the getOASpec function
134- await getOASpec ( { source, sourceType, output, pageSlug, redocExecutor, repoPath, apiVersion } ) ;
194+ const isSuccessfulBuild = await getOASpec ( {
195+ source,
196+ sourceType,
197+ output,
198+ pageSlug,
199+ redocExecutor,
200+ repoPath,
201+ apiVersion,
202+ } ) ;
203+ if ( ! isSuccessfulBuild ) totalSuccess = false ;
204+
205+ // If all builds successful, persist git hash and version data in db
206+ if ( totalSuccess && sourceType == 'atlas' ) {
207+ try {
208+ const gitHash = await fetchGitHash ( ) ;
209+ const versions = await fetchVersionData ( gitHash ) ;
210+ await saveSuccessfulBuildVersionData ( source , gitHash , versions ) ;
211+ } catch ( e ) {
212+ console . error ( e ) ;
213+ }
214+ }
215+ resetGitHashCache ( ) ;
135216 }
136217} ;
0 commit comments