1- const nodefetch = require ( "node-fetch" ) ;
21const { join } = require ( "path" ) ;
32
43const config = {
54 appStoreUrl : "https://appstore.home.mendix.com/rest/packagesapi/v2" ,
6- contributorUrl : "https://contributor.mendixcloud .com/apis/v1" ,
5+ contributorUrl : "https://contributor.mendix .com/apis/v1" ,
76 // This one, for some reasons, needs to be added as OpenID header to contributor request.
87 // The open id value (a39025a8-55b8-4532-bc5d-4e74901d11f9) is taken from widgets@mendix.com
98 // account and could be found at Profile -> Advanced -> Personal Info -> View My Data -> Open id
@@ -44,6 +43,8 @@ async function uploadModuleToAppStore(pkgName, marketplaceId, version, minimumMX
4443 const postResponse = await createDraft ( marketplaceId , version , minimumMXVersion ) ;
4544 await publishDraft ( postResponse . UUID ) ;
4645 console . log ( `Successfully uploaded ${ pkgName } to the Mendix Marketplace.` ) ;
46+
47+ await verifyReleasePublished ( marketplaceId , version , pkgName ) ;
4748 } catch ( error ) {
4849 error . message = `Failed uploading ${ pkgName } to appstore with error: ${ error . message } ` ;
4950 throw error ;
@@ -61,7 +62,7 @@ async function getGithubAssetUrl() {
6162 for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
6263 console . log ( `Attempt ${ attempt } /${ maxRetries } : Fetching release for tag ${ tag } ` ) ;
6364
64- const releaseData = await fetch (
65+ const releaseData = await fetchData (
6566 "GET" ,
6667 `https://api.github.com/repos/mendix/native-widgets/releases/tags/${ tag } `
6768 ) ;
@@ -126,13 +127,13 @@ async function fetchContributor(method, path, body) {
126127 const pass = process . env . CPAPI_PASS_PROD ;
127128 const credentials = `${ user } :${ pass } ` ;
128129
129- return fetch ( method , `${ config . contributorUrl } /${ path } ` , body , {
130+ return fetchData ( method , `${ config . contributorUrl } /${ path } ` , body , {
130131 OpenID : config . openIdUrl ,
131132 Authorization : `Basic ${ Buffer . from ( credentials ) . toString ( "base64" ) } `
132133 } ) ;
133134}
134135
135- async function fetch ( method , url , body , additionalHeaders ) {
136+ async function fetchData ( method , url , body , additionalHeaders ) {
136137 let response ;
137138 const httpsOptions = {
138139 method,
@@ -147,7 +148,7 @@ async function fetch(method, url, body, additionalHeaders) {
147148
148149 console . log ( `Fetching URL (${ method } ): ${ url } ` ) ;
149150 try {
150- response = await nodefetch ( url , httpsOptions ) ;
151+ response = await fetch ( url , httpsOptions ) ;
151152 } catch ( error ) {
152153 throw new Error ( `An error occurred while retrieving data from ${ url } . Technical error: ${ error . message } ` ) ;
153154 }
@@ -178,3 +179,78 @@ function packageMetadata() {
178179 const { name, widgetName, version, marketplace } = require ( pkgPath ) ;
179180 return { name, widgetName, version, marketplace } ;
180181}
182+
183+ async function verifyReleasePublished ( contentId , expectedVersion , pkgName ) {
184+ const normalizedExpectedVersion = expectedVersion . startsWith ( "v" ) ? expectedVersion . substring ( 1 ) : expectedVersion ;
185+
186+ console . log ( `Verifying release ${ normalizedExpectedVersion } is published for content ID ${ contentId } ...` ) ;
187+
188+ const patToken = process . env . MENDIX_PAT_TOKEN ;
189+ if ( ! patToken ) {
190+ console . warn ( "WARNING: MENDIX_PAT_TOKEN environment variable is not set. Skipping release verification." ) ;
191+ return ;
192+ }
193+
194+ const maxRetries = 5 ;
195+ const initialDelayMs = 60000 ;
196+ const retryDelayMs = 60000 ;
197+
198+ await new Promise ( resolve => setTimeout ( resolve , initialDelayMs ) ) ;
199+
200+ for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
201+ console . log ( `Verification attempt ${ attempt } /${ maxRetries } : Checking for version ${ expectedVersion } ` ) ;
202+
203+ try {
204+ // Call the Mendix Content API to get all released module versions
205+ const versionsResponse = await fetch (
206+ `https://marketplace-api.mendix.com/v1/content/${ contentId } /versions` ,
207+ {
208+ method : "GET" ,
209+ headers : {
210+ Accept : "application/json" ,
211+ Authorization : `MxToken ${ patToken } `
212+ }
213+ }
214+ ) ;
215+
216+ if ( ! versionsResponse . ok ) {
217+ const errorText = await versionsResponse . text ( ) ;
218+ throw new Error (
219+ `Content API returned status ${ versionsResponse . status } : ${ versionsResponse . statusText } . Response: ${ errorText } `
220+ ) ;
221+ }
222+
223+ const responseData = await versionsResponse . json ( ) ;
224+
225+ if ( ! responseData . items || ! Array . isArray ( responseData . items ) ) {
226+ throw new Error ( `Unexpected API response structure: ${ JSON . stringify ( responseData ) } ` ) ;
227+ }
228+
229+ const versions = responseData . items ;
230+
231+ const versionFound = versions . some ( v => v . versionNumber === normalizedExpectedVersion ) ;
232+
233+ if ( versionFound ) {
234+ console . log (
235+ `Successfully verified: Version ${ normalizedExpectedVersion } is published on Mendix Marketplace!`
236+ ) ;
237+ return ;
238+ }
239+
240+ if ( attempt < maxRetries ) {
241+ await new Promise ( resolve => setTimeout ( resolve , retryDelayMs ) ) ;
242+ }
243+ } catch ( error ) {
244+ console . error ( `Error during verification attempt ${ attempt } : ${ error . message } ` ) ;
245+ if ( attempt < maxRetries ) {
246+ await new Promise ( resolve => setTimeout ( resolve , retryDelayMs ) ) ;
247+ }
248+ }
249+ }
250+
251+ throw new Error (
252+ `Release verification FAILED: Version ${ normalizedExpectedVersion } for ${ pkgName } (content ID: ${ contentId } ) ` +
253+ `was not found on Mendix Marketplace after ${ maxRetries } attempts. ` +
254+ `The publish step reported success, but the version is not publicly available. `
255+ ) ;
256+ }
0 commit comments