Skip to content

Commit 4fe81d1

Browse files
[MOO-2322] : Marketplace deployement API update (#518)
2 parents 82f0d38 + 39ace08 commit 4fe81d1

2 files changed

Lines changed: 83 additions & 6 deletions

File tree

.github/workflows/MarketplaceRelease.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
CPAPI_USERNAME: ${{ secrets.CPAPI_USERNAME }}
5151
CPAPI_PASS_PROD: ${{ secrets.CPAPI_PASS_PROD }}
5252
TAG: ${{ steps.variables.outputs.tag }}
53+
MENDIX_PAT_TOKEN: ${{ secrets.MENDIX_PAT_TOKEN }}
5354
- name: "Send slack msg on failure"
5455
if: ${{ failure() }}
5556
uses: ./.github/actions/slack-notification

scripts/release/marketplaceRelease.js

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
const nodefetch = require("node-fetch");
21
const { join } = require("path");
32

43
const 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

Comments
 (0)