From 4b83f83d72d9b31b0fcf68cadfeae66aecca5696 Mon Sep 17 00:00:00 2001 From: Saurabh Chavan Date: Tue, 21 Jul 2026 12:36:40 +0530 Subject: [PATCH 1/4] Added base structure of scripts from master branch about release scripts --- .github/scripts/package-lock.json | 255 ++++++++++++++++++++ .github/scripts/package.json | 10 + .github/scripts/release-native-template.mjs | 191 +++++++++++++++ 3 files changed, 456 insertions(+) create mode 100644 .github/scripts/package-lock.json create mode 100644 .github/scripts/package.json create mode 100644 .github/scripts/release-native-template.mjs diff --git a/.github/scripts/package-lock.json b/.github/scripts/package-lock.json new file mode 100644 index 00000000..9dfdf84a --- /dev/null +++ b/.github/scripts/package-lock.json @@ -0,0 +1,255 @@ +{ + "name": "scripts", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@octokit/rest": "^22.0.1", + "simple-git": "^3.32.2" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "license": "MIT" + }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", + "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.3", + "@octokit/request": "^10.0.6", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.3.tgz", + "integrity": "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", + "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.6", + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", + "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", + "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz", + "integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.8.tgz", + "integrity": "sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.3", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "fast-content-type-parse": "^3.0.0", + "json-with-bigint": "^3.5.3", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/rest": { + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz", + "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==", + "license": "MIT", + "dependencies": { + "@octokit/core": "^7.0.6", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-request-log": "^6.0.0", + "@octokit/plugin-rest-endpoint-methods": "^17.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "license": "Apache-2.0" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/fast-content-type-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", + "integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/json-with-bigint": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.3.tgz", + "integrity": "sha512-QObKu6nxy7NsxqR0VK4rkXnsNr5L9ElJaGEg+ucJ6J7/suoKZ0n+p76cu9aCqowytxEbwYNzvrMerfMkXneF5A==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/simple-git": { + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.32.2.tgz", + "integrity": "sha512-n/jhNmvYh8dwyfR6idSfpXrFazuyd57jwNMzgjGnKZV/1lTh0HKvPq20v4AQ62rP+l19bWjjXPTCdGHMt0AdrQ==", + "license": "MIT", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + } + } +} diff --git a/.github/scripts/package.json b/.github/scripts/package.json new file mode 100644 index 00000000..136a96bc --- /dev/null +++ b/.github/scripts/package.json @@ -0,0 +1,10 @@ +{ + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "simple-git": "^3.32.2", + "@octokit/rest": "^22.0.1" + } +} diff --git a/.github/scripts/release-native-template.mjs b/.github/scripts/release-native-template.mjs new file mode 100644 index 00000000..86be5aa8 --- /dev/null +++ b/.github/scripts/release-native-template.mjs @@ -0,0 +1,191 @@ +import fs from "fs"; +import os from "os"; +import path from "path"; +import { Octokit } from "@octokit/rest"; +import { fileURLToPath } from "url"; +import simpleGit from "simple-git"; + +const required = [ + "MENDIX_MOBILE_DOCS_PR_GITHUB_PAT", + "STUDIO_PRO_MAJOR", +]; + +const missing = required.filter((k) => !process.env[k]); +if (missing.length) { + console.error("Missing env vars:", missing.join(", ")); + process.exit(1); +} + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const DOCS_CLONE_PREFIX = "mendix-docs-"; + +const MENDIX_MOBILE_DOCS_PR_GITHUB_PAT = + process.env.MENDIX_MOBILE_DOCS_PR_GITHUB_PAT; + +const NATIVE_TEMPLATE_VERSION = readVersionFromPackageJson(); +const NATIVE_TEMPLATE_MAJOR = NATIVE_TEMPLATE_VERSION.split(".")[0]; +const STUDIO_PRO_MAJOR = process.env.STUDIO_PRO_MAJOR; + +const GIT_AUTHOR_NAME = "MendixMobile"; +const GIT_AUTHOR_EMAIL = "moo@mendix.com"; + +// Docs Repo Settings +const DOCS_REPO_NAME = "docs"; +const DOCS_REPO_OWNER = "MendixMobile"; +const DOCS_UPSTREAM_OWNER = "mendix"; +const DOCS_BRANCH_NAME = `update-native-template-release-notes-v${NATIVE_TEMPLATE_VERSION}`; + +const DOCS_PARENT_DIR = `content/en/docs/releasenotes/mobile/native-template/nt-studio-pro-${STUDIO_PRO_MAJOR}-parent`; +const TARGET_FILE = `${DOCS_PARENT_DIR}/nt-${NATIVE_TEMPLATE_MAJOR}-rn.md`; + +const octokit = new Octokit({ auth: MENDIX_MOBILE_DOCS_PR_GITHUB_PAT }); + +function extractUnreleasedChangelog() { + const changelogPath = path.resolve( + path.join(__dirname, "..", "..", "CHANGELOG.md"), + ); + const changelog = fs.readFileSync(changelogPath, "utf-8"); + const unreleasedRegex = + /^## \[Unreleased\](.*?)(?=^## \[\d+\.\d+\.\d+\][^\n]*|\Z)/ms; + const match = changelog.match(unreleasedRegex); + if (!match) throw new Error("No [Unreleased] section found!"); + const unreleasedContent = match[1].trim(); + if (!unreleasedContent) throw new Error("No changes under [Unreleased]!"); + return unreleasedContent; +} + +function buildFrontmatter() { + return `---\ntitle: "Native Template ${NATIVE_TEMPLATE_MAJOR}"\nurl: /releasenotes/mobile/nt-${NATIVE_TEMPLATE_MAJOR}-rn/\nweight: 1\ndescription: "Native Template ${NATIVE_TEMPLATE_MAJOR}"\n---`; +} + +// Docs +function injectUnreleasedToDoc(docPath, unreleasedContent) { + if (!fs.existsSync(DOCS_PARENT_DIR)) { + throw new Error( + `Parent directory not found: ${DOCS_PARENT_DIR}\nA new Studio Pro parent folder requires manual setup in the docs repo.`, + ); + } + + const date = new Date(); + const formattedDate = date.toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }); + const releaseHeading = `## ${NATIVE_TEMPLATE_VERSION}\n\n**Release date: ${formattedDate}**`; + + if (!fs.existsSync(docPath)) { + console.log(`${docPath} not found — creating new file for Native Template ${NATIVE_TEMPLATE_MAJOR}.`); + return `${buildFrontmatter()}\n\n${releaseHeading}\n\n${unreleasedContent}\n`; + } + + const doc = fs.readFileSync(docPath, "utf-8"); + const frontmatterMatch = doc.match(/^---[\s\S]*?---/); + if (!frontmatterMatch) throw new Error("Frontmatter not found!"); + const frontmatter = frontmatterMatch[0]; + const rest = doc.slice(frontmatter.length).trimStart(); + + const firstReleaseHeadingIndex = rest.search(/^##\s+\d+\.\d+\.\d+/m); + const beforeReleases = + firstReleaseHeadingIndex > 0 + ? `${rest.slice(0, firstReleaseHeadingIndex).trimEnd()}\n\n` + : ""; + const releaseSections = + firstReleaseHeadingIndex >= 0 + ? rest.slice(firstReleaseHeadingIndex).trimStart() + : rest.trimStart(); + + return `${frontmatter}\n\n${beforeReleases}${releaseHeading}\n\n${unreleasedContent}\n\n${releaseSections}`; +} + +// This file exists only in the fork (MendixMobile/docs) and not in upstream (mendix/docs). +// Removing it in our branch ensures it doesn't appear in the cross-fork PR diff. +const FORK_SYNC_FILE = ".github/workflows/sync.yml"; + +async function cloneDocsRepo() { + const git = simpleGit(); + const docsCloneDir = fs.mkdtempSync( + path.join(os.tmpdir(), DOCS_CLONE_PREFIX), + ); + + await git.clone( + `https://x-access-token:${MENDIX_MOBILE_DOCS_PR_GITHUB_PAT}@github.com/${DOCS_REPO_OWNER}/${DOCS_REPO_NAME}.git`, + docsCloneDir, + ["--depth", "1"], + ); + + process.chdir(docsCloneDir); + + await git.addConfig("user.name", GIT_AUTHOR_NAME, false, "global"); + await git.addConfig("user.email", GIT_AUTHOR_EMAIL, false, "global"); +} + +async function checkoutLocalBranch(git) { + await git.checkoutLocalBranch(DOCS_BRANCH_NAME); +} + +async function updateDocsNTReleaseNotes(unreleasedContent) { + const newDocContent = injectUnreleasedToDoc(TARGET_FILE, unreleasedContent); + fs.writeFileSync(TARGET_FILE, newDocContent, "utf-8"); +} + +async function createPRUpdateDocsNTReleaseNotes(git) { + // Remove the fork's sync.yml so it doesn't appear in the cross-fork PR diff. + if (fs.existsSync(FORK_SYNC_FILE)) { + await git.rm(FORK_SYNC_FILE); + } + await git.add(TARGET_FILE); + await git.commit( + `docs: update mobile release notes for v${NATIVE_TEMPLATE_VERSION}`, + ); + await git.push("origin", DOCS_BRANCH_NAME, ["--force"]); + + const prBody = ` +Automated sync of the latest release notes for v${NATIVE_TEMPLATE_VERSION} from [native-template](https://github.com/mendix/native-template). + +--- + +**Note:** +This pull request was automatically generated by an automation process managed by the Mobile team. +**Please do not take any action on this pull request unless it has been reviewed and approved by a member of the Mobile team.** +`; + + await octokit.pulls.create({ + owner: DOCS_UPSTREAM_OWNER, + repo: DOCS_REPO_NAME, + title: `Update mobile app release notes for v${NATIVE_TEMPLATE_VERSION}`, + head: `${DOCS_REPO_OWNER}:${DOCS_BRANCH_NAME}`, + base: "development", + body: prBody, + draft: true, + }); +} + +// Update NT Release Notes in Docs repo +async function updateNTReleaseNotes(unreleasedContent) { + try { + await cloneDocsRepo(); + const git = simpleGit(); + await checkoutLocalBranch(git); + updateDocsNTReleaseNotes(unreleasedContent); + await createPRUpdateDocsNTReleaseNotes(git); + } catch (err) { + console.error("❌ Updating NT Release Notes failed:", err); + process.exit(1); + } +} + +function readVersionFromPackageJson() { + const packageJsonPath = path.resolve( + path.join(__dirname, "..", "..", "package.json"), + ); + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")); + return packageJson.version; +} + +(async () => { + const unreleasedContent = extractUnreleasedChangelog(); + + await updateNTReleaseNotes(unreleasedContent); +})(); From b456ddb89100560fc05f16a5460f0bee3607c8a1 Mon Sep 17 00:00:00 2001 From: Saurabh Chavan Date: Tue, 21 Jul 2026 16:41:53 +0530 Subject: [PATCH 2/4] add publishing docs pr and changelog logic to release job --- .github/scripts/release-native-template.mjs | 99 ++++++++++++++++++--- .github/workflows/release-it.yml | 25 ++++++ 2 files changed, 110 insertions(+), 14 deletions(-) diff --git a/.github/scripts/release-native-template.mjs b/.github/scripts/release-native-template.mjs index 86be5aa8..e23166c4 100644 --- a/.github/scripts/release-native-template.mjs +++ b/.github/scripts/release-native-template.mjs @@ -30,6 +30,11 @@ const STUDIO_PRO_MAJOR = process.env.STUDIO_PRO_MAJOR; const GIT_AUTHOR_NAME = "MendixMobile"; const GIT_AUTHOR_EMAIL = "moo@mendix.com"; +// Native Template Repo Settings +const NT_REPO_OWNER = process.env.GITHUB_REPOSITORY_OWNER; +const NT_REPO_NAME = process.env.GITHUB_REPOSITORY.split("/")[1]; +const NT_CHANGELOG_BRANCH_NAME = `update-changelog-v${NATIVE_TEMPLATE_VERSION}`; + // Docs Repo Settings const DOCS_REPO_NAME = "docs"; const DOCS_REPO_OWNER = "MendixMobile"; @@ -41,6 +46,14 @@ const TARGET_FILE = `${DOCS_PARENT_DIR}/nt-${NATIVE_TEMPLATE_MAJOR}-rn.md`; const octokit = new Octokit({ auth: MENDIX_MOBILE_DOCS_PR_GITHUB_PAT }); +function getToday() { + const today = new Date(); + const yyyy = today.getFullYear(); + const mm = String(today.getMonth() + 1).padStart(2, "0"); + const dd = String(today.getDate()).padStart(2, "0"); + return `${yyyy}-${mm}-${dd}`; +} + function extractUnreleasedChangelog() { const changelogPath = path.resolve( path.join(__dirname, "..", "..", "CHANGELOG.md"), @@ -52,19 +65,80 @@ function extractUnreleasedChangelog() { if (!match) throw new Error("No [Unreleased] section found!"); const unreleasedContent = match[1].trim(); if (!unreleasedContent) throw new Error("No changes under [Unreleased]!"); - return unreleasedContent; + return { changelog, unreleasedContent, changelogPath }; } function buildFrontmatter() { return `---\ntitle: "Native Template ${NATIVE_TEMPLATE_MAJOR}"\nurl: /releasenotes/mobile/nt-${NATIVE_TEMPLATE_MAJOR}-rn/\nweight: 1\ndescription: "Native Template ${NATIVE_TEMPLATE_MAJOR}"\n---`; } +// Changelog Update for Native Template Repo +function updateChangelog({ changelog, unreleasedContent, changelogPath }) { + const today = getToday(); + const newSection = `## [${NATIVE_TEMPLATE_VERSION}] - ${today}\n\n${unreleasedContent}\n\n`; + const unreleasedRegex = + /^## \[Unreleased\](.*?)(?=^## \[\d+\.\d+\.\d+\][^\n]*|\Z)/ms; + const updatedChangelog = changelog.replace( + unreleasedRegex, + `## [Unreleased]\n\n${newSection}` + ); + fs.writeFileSync(changelogPath, updatedChangelog, "utf-8"); +} + +// Raise a PR to update the CHANGELOG.md in the native-template repo +async function createPRUpdateChangelog() { + const git = simpleGit(); + + await git.addConfig("user.name", GIT_AUTHOR_NAME, ["--global"]); + await git.addConfig("user.email", GIT_AUTHOR_EMAIL, ["--global"]); + + // Get the current branch name (the one selected in GitHub Actions UI) + const currentBranch = await git.revparse(["--abbrev-ref", "HEAD"]); + + await git.checkoutLocalBranch(NT_CHANGELOG_BRANCH_NAME); + + await git.add("CHANGELOG.md"); + await git.commit(`chore: update CHANGELOG for v${NATIVE_TEMPLATE_VERSION}`); + await git.push("origin", NT_CHANGELOG_BRANCH_NAME, ["--force"]); + + const prBody = ` +Automated update of CHANGELOG.md for v${NATIVE_TEMPLATE_VERSION}. + +This PR moves the \`[Unreleased]\` section content to a new versioned section \`[${NATIVE_TEMPLATE_VERSION}]\`. + +--- + +**Note:** +This pull request was automatically generated by an automation process managed by the Mobile team. +**Please do not take any action on this pull request unless it has been reviewed and approved by a member of the Mobile team.** +`; + + await octokit.pulls.create({ + owner: NT_REPO_OWNER, + repo: NT_REPO_NAME, + title: `Update CHANGELOG for v${NATIVE_TEMPLATE_VERSION}`, + head: NT_CHANGELOG_BRANCH_NAME, + base: currentBranch, + body: prBody, + draft: true, + }); +} + +async function updateNTChangelog(changelog, unreleasedContent, changelogPath) { + try { + updateChangelog({ changelog, unreleasedContent, changelogPath }); + await createPRUpdateChangelog(); + } catch (err) { + console.error("❌ Updating NT Changelog failed:", err); + process.exit(1); + } +} + // Docs function injectUnreleasedToDoc(docPath, unreleasedContent) { if (!fs.existsSync(DOCS_PARENT_DIR)) { - throw new Error( - `Parent directory not found: ${DOCS_PARENT_DIR}\nA new Studio Pro parent folder requires manual setup in the docs repo.`, - ); + console.log(`Parent directory not found. Creating: ${DOCS_PARENT_DIR}`); + fs.mkdirSync(DOCS_PARENT_DIR, { recursive: true }); } const date = new Date(); @@ -99,10 +173,6 @@ function injectUnreleasedToDoc(docPath, unreleasedContent) { return `${frontmatter}\n\n${beforeReleases}${releaseHeading}\n\n${unreleasedContent}\n\n${releaseSections}`; } -// This file exists only in the fork (MendixMobile/docs) and not in upstream (mendix/docs). -// Removing it in our branch ensures it doesn't appear in the cross-fork PR diff. -const FORK_SYNC_FILE = ".github/workflows/sync.yml"; - async function cloneDocsRepo() { const git = simpleGit(); const docsCloneDir = fs.mkdtempSync( @@ -131,10 +201,6 @@ async function updateDocsNTReleaseNotes(unreleasedContent) { } async function createPRUpdateDocsNTReleaseNotes(git) { - // Remove the fork's sync.yml so it doesn't appear in the cross-fork PR diff. - if (fs.existsSync(FORK_SYNC_FILE)) { - await git.rm(FORK_SYNC_FILE); - } await git.add(TARGET_FILE); await git.commit( `docs: update mobile release notes for v${NATIVE_TEMPLATE_VERSION}`, @@ -171,7 +237,7 @@ async function updateNTReleaseNotes(unreleasedContent) { updateDocsNTReleaseNotes(unreleasedContent); await createPRUpdateDocsNTReleaseNotes(git); } catch (err) { - console.error("❌ Updating NT Release Notes failed:", err); + console.error("❌ Updating NT Release Notes in Docs failed:", err); process.exit(1); } } @@ -185,7 +251,12 @@ function readVersionFromPackageJson() { } (async () => { - const unreleasedContent = extractUnreleasedChangelog(); + const { changelog, unreleasedContent, changelogPath } = + extractUnreleasedChangelog(); + + // Update CHANGELOG.md in native-template repo + await updateNTChangelog(changelog, unreleasedContent, changelogPath); + // Update release notes in docs repo await updateNTReleaseNotes(unreleasedContent); })(); diff --git a/.github/workflows/release-it.yml b/.github/workflows/release-it.yml index d0a15926..959b9522 100644 --- a/.github/workflows/release-it.yml +++ b/.github/workflows/release-it.yml @@ -15,6 +15,14 @@ on: - preminor - premajor - prepatch + studio_pro_version: + description: 'Studio Pro major version (determines the docs parent folder for changelog publishing)' + required: true + default: 'Studio Pro 10.x' + type: choice + options: + - 'Studio Pro 10.x' + - 'Studio Pro 11.x' jobs: release: @@ -37,4 +45,21 @@ jobs: git config --global user.name "github-action" release-it -VV --increment=${{ github.event.inputs.version }} --ci --github.release --github.draft --git.commitMessage="chore: release v\${version}" --git.tagName="v\${version}" + - name: Sync docs fork with upstream + if: ${{ contains(fromJSON('["patch","minor","major"]'), github.event.inputs.version) }} + run: gh repo sync MendixMobile/docs --branch development --force + env: + GH_TOKEN: ${{ secrets.MENDIX_MOBILE_DOCS_PR_GITHUB_PAT }} + + - name: Install docs release script dependencies + if: ${{ contains(fromJSON('["patch","minor","major"]'), github.event.inputs.version) }} + run: npm ci --prefix .github/scripts + + - name: Create Changelog PR in native-template and release notes PR in mendix/docs + if: ${{ contains(fromJSON('["patch","minor","major"]'), github.event.inputs.version) }} + env: + MENDIX_MOBILE_DOCS_PR_GITHUB_PAT: ${{ secrets.MENDIX_MOBILE_DOCS_PR_GITHUB_PAT }} + STUDIO_PRO_MAJOR: ${{ github.event.inputs.studio_pro_version == 'Studio Pro 10.x' && '10' || '11' }} + run: node .github/scripts/release-native-template.mjs + From 7f15fa12475a219132c2ed9b7867eec2acb52b29 Mon Sep 17 00:00:00 2001 From: Saurabh Chavan Date: Tue, 21 Jul 2026 16:45:21 +0530 Subject: [PATCH 3/4] add publish job for testing purpose --- .../workflows/publish-changelog-to-docs.yml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/publish-changelog-to-docs.yml diff --git a/.github/workflows/publish-changelog-to-docs.yml b/.github/workflows/publish-changelog-to-docs.yml new file mode 100644 index 00000000..08d2acec --- /dev/null +++ b/.github/workflows/publish-changelog-to-docs.yml @@ -0,0 +1,39 @@ +name: Publish Changelog to Mendix Docs + +on: + workflow_dispatch: + inputs: + branch: + description: 'Branch to read the changelog and version from' + required: true + default: 'master' + type: string + studio_pro_version: + description: 'Studio Pro major version (determines the docs parent folder)' + required: true + default: 'Studio Pro 11.x' + type: choice + options: + - 'Studio Pro 10.x' + - 'Studio Pro 11.x' + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.branch }} + + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc + + - name: Install docs release script dependencies + run: npm ci --prefix .github/scripts + + - name: Create release notes PR in mendix/docs Github repository + env: + MENDIX_MOBILE_DOCS_PR_GITHUB_PAT: ${{ secrets.MENDIX_MOBILE_DOCS_PR_GITHUB_PAT }} + STUDIO_PRO_MAJOR: ${{ github.event.inputs.studio_pro_version == 'Studio Pro 10.x' && '10' || '11' }} + run: node .github/scripts/release-native-template.mjs \ No newline at end of file From 2085c272e1d04a020a4b7d69e69c92cf48a0364d Mon Sep 17 00:00:00 2001 From: Saurabh Chavan Date: Tue, 21 Jul 2026 16:50:13 +0530 Subject: [PATCH 4/4] revert publish changelog to docs change --- .../workflows/publish-changelog-to-docs.yml | 39 ------------------- 1 file changed, 39 deletions(-) delete mode 100644 .github/workflows/publish-changelog-to-docs.yml diff --git a/.github/workflows/publish-changelog-to-docs.yml b/.github/workflows/publish-changelog-to-docs.yml deleted file mode 100644 index 08d2acec..00000000 --- a/.github/workflows/publish-changelog-to-docs.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Publish Changelog to Mendix Docs - -on: - workflow_dispatch: - inputs: - branch: - description: 'Branch to read the changelog and version from' - required: true - default: 'master' - type: string - studio_pro_version: - description: 'Studio Pro major version (determines the docs parent folder)' - required: true - default: 'Studio Pro 11.x' - type: choice - options: - - 'Studio Pro 10.x' - - 'Studio Pro 11.x' - -jobs: - publish: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.event.inputs.branch }} - - - uses: actions/setup-node@v3 - with: - node-version-file: .nvmrc - - - name: Install docs release script dependencies - run: npm ci --prefix .github/scripts - - - name: Create release notes PR in mendix/docs Github repository - env: - MENDIX_MOBILE_DOCS_PR_GITHUB_PAT: ${{ secrets.MENDIX_MOBILE_DOCS_PR_GITHUB_PAT }} - STUDIO_PRO_MAJOR: ${{ github.event.inputs.studio_pro_version == 'Studio Pro 10.x' && '10' || '11' }} - run: node .github/scripts/release-native-template.mjs \ No newline at end of file