From ecc4e8b11315491a8e43255b8c77990056660a76 Mon Sep 17 00:00:00 2001 From: vadymv-mendix Date: Thu, 19 Feb 2026 14:53:29 +0100 Subject: [PATCH 1/6] chore: update @mendix/native to v9.3.0 for iOS encrypted storage fixes --- CHANGELOG.md | 7 +++++++ package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3672b18..9285c730 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +- We fixed an iOS crash in encrypted storage by correcting native error handling, so Keychain failures no longer trigger an unrecognized selector abort. +- We changed iOS Keychain item accessibility to After First Unlock for encrypted storage and persisted session cookies. +- We added a required one-time Keychain migration to update existing stored items; for compatibility, this Native Template version still works with older Studio Pro 10.24.x, but migration support requires Studio Pro 10.24.16 or newer plus a new iOS app build and rollout. Without migration, the original Keychain accessibility issue can still occur, although improved error handling reduces crash impact. + +## [14.1.12] - 2026-01-22 + - We added the `LocationWhenInUse` permission to the iOS configuration to support react-native-permissions. +- ## [14.1.11] - 2026-01-12 - We updated `@mendix/native` to v9.2.2, enabling session cookie persistence and restoration on iOS. diff --git a/package-lock.json b/package-lock.json index b0d71f07..e5cff97d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "dependencies": { "@gorhom/bottom-sheet": "^5.1.1", - "@mendix/native": "9.2.2", + "@mendix/native": "9.3.0", "@op-engineering/op-sqlite": "9.2.7", "@react-native-async-storage/async-storage": "2.0.0", "@react-native-camera-roll/camera-roll": "7.4.0", @@ -1784,9 +1784,9 @@ } }, "node_modules/@mendix/native": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/@mendix/native/-/native-9.2.2.tgz", - "integrity": "sha512-9nW2xfM7QQVj91nwbOsLWUftAv66QYktfE4Nh6blHX+HVwxpgCO9nZ7ekE4wYcKFExps/xOyx+8MSfZFLIgrDQ==" + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@mendix/native/-/native-9.3.0.tgz", + "integrity": "sha512-FR8iyrCjDXfjU9HS3h8SSzIJ2g1PqTKzChzhQbBw5k/nFdWYwyIcPu8WHgYEDi6xldSmRmi3Ica/zn/3+isU7w==" }, "node_modules/@mendix/native-mobile-toolkit": { "version": "1.0.127", diff --git a/package.json b/package.json index 5e328e29..907e3f60 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "@gorhom/bottom-sheet": "^5.1.1", - "@mendix/native": "9.2.2", + "@mendix/native": "9.3.0", "@op-engineering/op-sqlite": "9.2.7", "@react-native-async-storage/async-storage": "2.0.0", "@react-native-camera-roll/camera-roll": "7.4.0", From f725cb7ddb8e880b6887484e12ec71ee756f57ed Mon Sep 17 00:00:00 2001 From: vadymv-mendix Date: Tue, 24 Feb 2026 14:36:24 +0100 Subject: [PATCH 2/6] chore: automate docs release notes PR in release workflow --- .github/pull_request_template.md | 5 +- .github/scripts/package-lock.json | 255 ++++++++++++++++++++ .github/scripts/package.json | 10 + .github/scripts/release-native-template.mjs | 189 +++++++++++++++ .github/workflows/check-docs-pr.yml | 88 ------- .github/workflows/release-it.yml | 12 + .gitignore | 2 +- 7 files changed, 468 insertions(+), 93 deletions(-) create mode 100644 .github/scripts/package-lock.json create mode 100644 .github/scripts/package.json create mode 100644 .github/scripts/release-native-template.mjs delete mode 100644 .github/workflows/check-docs-pr.yml diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fc4b5c4d..ffaaaa98 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -6,8 +6,7 @@ Please provide a clear and concise description of what this pull request address To ensure this pull request meets the requirements for merging, please complete the checklist below: -- [ ] **Release Note:** I have added a release note in the [Mendix Docs repository](https://github.com/mendix/docs) relevant to the changes introduced in this PR. - - **Link to release note:** [Provide the link here] +- [ ] **Release Note:** As a part of the release process, an automated PR will be created for the [Mendix Docs repository](https://github.com/mendix/docs) relevant to the changes introduced in this PR. Post release, please ensure that the release note accurately reflects the changes and impacts of this PR. - [ ] **Breaking Changes:** This PR introduces breaking changes (e.g., changes that require updates to existing configurations, dependencies). - [ ] If yes, I have documented these breaking changes and provided guidance for users to adapt. - **Details about breaking changes:** [Provide details here, if applicable] @@ -22,9 +21,7 @@ To ensure this pull request meets the requirements for merging, please complete ## Important Notes -- PRs **will not be merged** without a corresponding release note update in the Mendix Docs repository. - Make sure the release note accurately describes the changes and impacts introduced by this PR. -- If documentation update is not required, add a comment with `skip-docs-check` to skip the docs check. Thank you for keeping our documentation up-to-date! 🚀 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..d4a894af --- /dev/null +++ b/.github/scripts/release-native-template.mjs @@ -0,0 +1,189 @@ +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", + "NATIVE_TEMPLATE_VERSION_BUMP_TYPE", +]; + +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 NATIVE_TEMPLATE_VERSION_BUMP_TYPE = + process.env.NATIVE_TEMPLATE_VERSION_BUMP_TYPE; // patch, minor, major + +const MENDIX_MOBILE_DOCS_PR_GITHUB_PAT = + process.env.MENDIX_MOBILE_DOCS_PR_GITHUB_PAT; + +const NATIVE_TEMPLATE_VERSION = determineVersionFromBumpType( + NATIVE_TEMPLATE_VERSION_BUMP_TYPE, +); + +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 TARGET_FILE = + "content/en/docs/releasenotes/mobile/native-template/nt-studio-pro-10-parent/nt-14-rn.md"; +// Other options: +// - content/en/docs/releasenotes/mobile/native-template/nt-studio-pro-11-parent/nt-15-rn.md +// - content/en/docs/releasenotes/mobile/native-template/nt-studio-pro-11-parent/nt-16-rn.md +// - content/en/docs/releasenotes/mobile/native-template/nt-studio-pro-11-parent/nt-17-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; +} + +// Docs +function injectUnreleasedToDoc(docPath, unreleasedContent) { + 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 firstParagraphMatch = rest.match(/^(.*?\n)(\s*\n)/s); + if (!firstParagraphMatch) throw new Error("First paragraph not found!"); + const firstParagraph = firstParagraphMatch[1]; + const afterFirstParagraph = rest.slice(firstParagraph.length).trimStart(); + + const date = new Date(); + const formattedDate = date.toLocaleDateString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }); + const title = `## ${NATIVE_TEMPLATE_VERSION}\n\n**Release date: ${formattedDate}**`; + + return `${frontmatter}\n\n${firstParagraph}\n${title}\n\n${unreleasedContent}\n\n${afterFirstParagraph}`; +} + +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) { + 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 [make-it-native](https://github.com/mendix/make-it-native). + +--- + +**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 determineVersionFromBumpType(bumpType = "patch") { + const packageJsonPath = path.resolve( + path.join(__dirname, "..", "..", "package.json"), + ); + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")); + const currentVersion = packageJson.version; + + const [major, minor, patch] = currentVersion.split(".").map(Number); + let newVersion; + switch (bumpType) { + case "major": + newVersion = `${major + 1}.0.0`; + break; + case "minor": + newVersion = `${major}.${minor + 1}.0`; + break; + case "patch": + newVersion = `${major}.${minor}.${patch + 1}`; + break; + default: + throw new Error( + `Invalid bump type for docs release notes: ${bumpType}. Expected one of: patch, minor, major.`, + ); + } + return newVersion; +} + +(async () => { + const unreleasedContent = extractUnreleasedChangelog(); + + await updateNTReleaseNotes(unreleasedContent); +})(); diff --git a/.github/workflows/check-docs-pr.yml b/.github/workflows/check-docs-pr.yml deleted file mode 100644 index 5c21b00f..00000000 --- a/.github/workflows/check-docs-pr.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Check Docs PR - -on: - pull_request: - types: [opened, edited] - pull_request_review_comment: - types: [created] - -jobs: - check-docs-pr: - runs-on: ubuntu-latest - permissions: - pull-requests: write - contents: read - steps: - - uses: actions/checkout@v3 - - - name: Check Skip Docs Check Comment - id: check-skip - env: - GH_TOKEN: ${{ github.token }} - run: | - # Get PR comments - COMMENTS=$(gh pr view ${{ github.event.pull_request.number }} --json comments --jq '.comments[].body') - - # Check if skip-docs-check comment exists - if echo "$COMMENTS" | grep -q "skip-docs-check"; then - echo "skip_check=true" >> $GITHUB_OUTPUT - else - echo "skip_check=false" >> $GITHUB_OUTPUT - fi - - - name: Check Docs PR Link - if: steps.check-skip.outputs.skip_check == 'false' - id: check-docs - env: - GH_TOKEN: ${{ github.token }} - run: | - # Get PR description - PR_DESCRIPTION=$(gh pr view ${{ github.event.pull_request.number }} --json body --jq .body) - - # Check if docs PR link exists - if echo "$PR_DESCRIPTION" | grep -q "https://github.com/mendix/docs/pull"; then - echo "docs_pr=found" >> $GITHUB_OUTPUT - else - echo "docs_pr=missing" >> $GITHUB_OUTPUT - fi - - - name: Check Existing Docs Check Comment - id: check-existing-comment - env: - GH_TOKEN: ${{ github.token }} - run: | - # Get PR comments - COMMENTS=$(gh pr view ${{ github.event.pull_request.number }} --json comments --jq '.comments[].body') - - # Check if our docs check comment exists - if echo "$COMMENTS" | grep -q "please add a link to the corresponding docs PR"; then - echo "has_comment=true" >> $GITHUB_OUTPUT - else - echo "has_comment=false" >> $GITHUB_OUTPUT - fi - - - name: Add Label if Missing - if: steps.check-docs.outputs.docs_pr == 'missing' && steps.check-skip.outputs.skip_check == 'false' - env: - GH_TOKEN: ${{ github.token }} - PR_AUTHOR: ${{ github.event.pull_request.user.login }} - run: | - # Add missing-docs-pr label - gh pr edit ${{ github.event.pull_request.number }} --add-label missing-docs-pr - - # Add comment to PR only if it doesn't exist - if [ "${{ steps.check-existing-comment.outputs.has_comment }}" = "false" ]; then - gh pr comment ${{ github.event.pull_request.number }} --body "Hi @$PR_AUTHOR, please add a link to the corresponding docs PR in the description. If documentation update is not required for this PR, you can add a comment with 'skip-docs-check' to skip this check." - fi - - # Fail the workflow - echo "Docs PR link is missing in the description" - exit 1 - - - name: Remove Label if Found or Skip Check - if: steps.check-docs.outputs.docs_pr == 'found' || steps.check-skip.outputs.skip_check == 'true' - env: - GH_TOKEN: ${{ github.token }} - run: | - # Remove missing-docs-pr label if it exists - gh pr edit ${{ github.event.pull_request.number }} --remove-label missing-docs-pr diff --git a/.github/workflows/release-it.yml b/.github/workflows/release-it.yml index d0a15926..9828e9d2 100644 --- a/.github/workflows/release-it.yml +++ b/.github/workflows/release-it.yml @@ -28,7 +28,19 @@ jobs: with: node-version-file: '.nvmrc' + - name: Install docs release script dependencies + if: ${{ contains(fromJSON('["patch","minor","major"]'), github.event.inputs.version) }} + run: npm ci --prefix .github/scripts + + - name: Create release notes PR in mendix/docs Github repository + if: ${{ contains(fromJSON('["patch","minor","major"]'), github.event.inputs.version) }} + env: + NATIVE_TEMPLATE_VERSION_BUMP_TYPE: ${{ github.event.inputs.version }} + MENDIX_MOBILE_DOCS_PR_GITHUB_PAT: ${{ secrets.MENDIX_MOBILE_DOCS_PR_GITHUB_PAT }} + run: node .github/scripts/release-native-template.mjs + - name: Release a new version + if: success() env: GITHUB_TOKEN: ${{ secrets.PUBLIC_REPO_ADMIN_TOKEN }} run: | diff --git a/.gitignore b/.gitignore index d8e8e804..b60662e1 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,7 @@ ios/MendixAppDelegate.m # node.js # # Use / before node_modules because iOS assets folder has a node_modules folder that should not be excluded. -/node_modules/ +node_modules/ npm-debug.log yarn-error.log From 99640b1814d314bde5218712bd0245864617ca5e Mon Sep 17 00:00:00 2001 From: github-action Date: Tue, 24 Feb 2026 13:47:43 +0000 Subject: [PATCH 3/6] chore: release v14.1.13 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5cff97d..29e33e0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "native-template", - "version": "14.1.12", + "version": "14.1.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "native-template", - "version": "14.1.12", + "version": "14.1.13", "hasInstallScript": true, "dependencies": { "@gorhom/bottom-sheet": "^5.1.1", diff --git a/package.json b/package.json index 907e3f60..99963ae0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "native-template", - "version": "14.1.12", + "version": "14.1.13", "private": true, "scripts": { "postinstall": "node patches/apply-patches.js && jetify", From 1354cf2a18d643901d5ceb90cbb6c8648fe4cb85 Mon Sep 17 00:00:00 2001 From: vadymv-mendix Date: Tue, 24 Feb 2026 15:11:10 +0100 Subject: [PATCH 4/6] fix: insert docs release notes before latest version heading --- .github/scripts/release-native-template.mjs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/scripts/release-native-template.mjs b/.github/scripts/release-native-template.mjs index d4a894af..6fe63b26 100644 --- a/.github/scripts/release-native-template.mjs +++ b/.github/scripts/release-native-template.mjs @@ -70,10 +70,15 @@ function injectUnreleasedToDoc(docPath, unreleasedContent) { const frontmatter = frontmatterMatch[0]; const rest = doc.slice(frontmatter.length).trimStart(); - const firstParagraphMatch = rest.match(/^(.*?\n)(\s*\n)/s); - if (!firstParagraphMatch) throw new Error("First paragraph not found!"); - const firstParagraph = firstParagraphMatch[1]; - const afterFirstParagraph = rest.slice(firstParagraph.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(); const date = new Date(); const formattedDate = date.toLocaleDateString("en-US", { @@ -83,7 +88,7 @@ function injectUnreleasedToDoc(docPath, unreleasedContent) { }); const title = `## ${NATIVE_TEMPLATE_VERSION}\n\n**Release date: ${formattedDate}**`; - return `${frontmatter}\n\n${firstParagraph}\n${title}\n\n${unreleasedContent}\n\n${afterFirstParagraph}`; + return `${frontmatter}\n\n${beforeReleases}${title}\n\n${unreleasedContent}\n\n${releaseSections}`; } async function cloneDocsRepo() { @@ -121,7 +126,7 @@ async function createPRUpdateDocsNTReleaseNotes(git) { await git.push("origin", DOCS_BRANCH_NAME, ["--force"]); const prBody = ` -Automated sync of the latest release notes for v${NATIVE_TEMPLATE_VERSION} from [make-it-native](https://github.com/mendix/make-it-native). +Automated sync of the latest release notes for v${NATIVE_TEMPLATE_VERSION} from [native-template](https://github.com/mendix/native-template). --- From d50dc8fce3a9874862f92ee0f9898a2677ff254d Mon Sep 17 00:00:00 2001 From: vadymv-mendix Date: Tue, 24 Feb 2026 15:11:44 +0100 Subject: [PATCH 5/6] Revert "chore: release v14.1.13" This reverts commit 99640b1814d314bde5218712bd0245864617ca5e. --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 29e33e0c..e5cff97d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "native-template", - "version": "14.1.13", + "version": "14.1.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "native-template", - "version": "14.1.13", + "version": "14.1.12", "hasInstallScript": true, "dependencies": { "@gorhom/bottom-sheet": "^5.1.1", diff --git a/package.json b/package.json index 99963ae0..907e3f60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "native-template", - "version": "14.1.13", + "version": "14.1.12", "private": true, "scripts": { "postinstall": "node patches/apply-patches.js && jetify", From dca6106e50a61185090bff56d9b8987a46664799 Mon Sep 17 00:00:00 2001 From: github-action Date: Tue, 24 Feb 2026 14:14:14 +0000 Subject: [PATCH 6/6] chore: release v14.1.13 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5cff97d..29e33e0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "native-template", - "version": "14.1.12", + "version": "14.1.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "native-template", - "version": "14.1.12", + "version": "14.1.13", "hasInstallScript": true, "dependencies": { "@gorhom/bottom-sheet": "^5.1.1", diff --git a/package.json b/package.json index 907e3f60..99963ae0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "native-template", - "version": "14.1.12", + "version": "14.1.13", "private": true, "scripts": { "postinstall": "node patches/apply-patches.js && jetify",