SharePoint Framework mit Renovate aktuell halten
Einleitung SharePoint Framework mit Renovate aktuell halten
In meinen vorhergehenden Blogposts habe ich meine Vorstellung der idealen CI/CD-Pipeline einer Adaptive Card Extension (ACE) für Viva Connections beschrieben.
In Teil 1 der Blogpost-Serie [1] habe ich erklärt, wie ich Abhängigkeiten aktuell halte und dass dafür Renovate [2] zum Einsatz kommt. In diesem Blogpost möchte ich etwas ausführlicher auf Renovate eingehen und meine Optimierungen vorstellen.
Die Antwort auf die Frage "Was ist Renovate?" spare ich mir dabei und verweise auf den Artikel "Flutter-Projekte aktuell halten: Automatische Dependency-Updates mit Renovate" [3] meines Kollegen, der diese Frage bereits beantwortet hat.
Renovate konfigurieren
Bei meinem Kunden betreibe ich Renovate als *self-hosted solution* in einem separaten Repository. Die Pipeline wird entweder durch *cron* getriggert oder durch manuelles Bauen mit dem optionalen Parameter "TARGET_REPO".
Renovate wird als NPM Paket mit dem Befehl "npx renovate@<TARGETVERSION>" gestartet. Je nach Branch (dev/main), wird zusätzlich die Option "--dry-run=full" verwendet. In der globalen Konfigurationsdatei renovate.js habe ich die wichtigsten Einstellungen festgelegt:
Inhalt der Datei renovate.js
module.exports = {
"baseBranchPatterns": ["/^(dev|develop)$/"],
"autodiscover": true,
"autodiscoverFilter": ["<MYPROJECT>/*"],
"onboarding": false,
"requireConfig": "required",
"branchPrefix": "renovate/",
"minimumReleaseAge": "5 days",
"hostRules": [
{
"hostType": "bitbucket-server",
"matchHost": "<MYREPOSERVER>"
},
{
"hostType": "npm",
"matchHost": "<MYNPMREPO>"
}
],
"packageRules": [
{
"matchDatasources": ["npm"],
"matchPackageNames": ["/^@<MYPROJECT>\\//"],
"minimumReleaseAge": "0 days",
"registryUrls": [
"https://<MYNPMREPO>/repository/npm-group/"
]
}
],
"extends": [
"config:recommended",
":disableDependencyDashboard",
"mergeConfidence:all-badges"
]
};
Mit dieser Konfiguration stelle ich sicher, dass Renovate nur Dev-Branches trifft. Mit den Einstellungen im "autodiscover"-Abschnitt lege ich fest, wie Entwickler ihre Projekte zu Renovate hinzufügen können ("onboarding"). Da 'autodiscover' aktiviert und auf mein Projekt beschränkt ist, 'onboarding' aber deaktiviert ist, müssen Entwickler einfach nur eine "renovate.json" zum Default-Branch ihres Projekts hinzufügen, um es von Renovate auf dem aktuellen Stand zu halten. Mit den weiteren Einstellungen stelle ich sicher, dass das firmeneigene NPM Repository verwendet wird, und wie viele Tage alt ein neues Paket mindestens sein soll, um berücksichtigt zu werden.
Renovate Presets
Im Renovate Repository habe ich das Verzeichnis "presets" angelegt. Darin habe ich die Renovate Konfigurationsdatei ace.json angelegt, die speziell auf ACE Projekte abzielt.
Inhalt der Datei ace.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"description": "Shared Renovate preset for SPFx Adaptive Card Extension repositories",
"extends": [
"config:recommended",
":pinDevDependencies"
],
"labels": [
"renovate"
],
"assignees": [],
"dependencyDashboard": true,
"rangeStrategy": "bump",
"rebaseWhen": "conflicted",
"platformAutomerge": false,
"packageRules": [
{
"description": "Group Fluent UI packages",
"matchPackageNames": [
"/^@fluentui\\//",
"office-ui-fabric-react"
],
"groupName": "Fluent UI packages"
},
{
"description": "Do not update cheerio, keep at 1.0.0-rc.10",
"matchPackageNames": [
"cheerio"
],
"allowedVersions": "1.0.0-rc.10"
},
{
"description": "SPFx repositories using React 17 must not update React beyond 17.0.1",
"matchPackageNames": [
"react",
"react-dom"
],
"allowedVersions": "17.0.1"
},
{
"description": "Group SPFx packages",
"matchPackageNames": [
"/^@microsoft/sp-/", "/^@microsoft/spfx-(?!cli$)/", "/^@microsoft/eslint-.+-spfx$/"
],
"groupName": "SPFx monorepo",
"matchUpdateTypes": [
"digest",
"patch",
"minor",
"major"
]
},
{
"description": "Group React type packages",
"matchPackageNames": [
"@types/react",
"@types/react-dom",
"@types/react-is"
],
"allowedVersions": "17.x",
"groupName": "React type packages"
},
{
"description": "Group Jest packages",
"extends": [
"monorepo:jest"
],
"groupName": "Jest monorepo",
"matchUpdateTypes": [
"digest",
"patch",
"minor",
"major"
]
},
{
"description": "Group ESLint packages",
"matchPackageNames": [
"eslint",
"eslint-config-next"
],
"groupName": "ESLint packages"
},
{
"description": "Only allow Node.js v22",
"matchPackageNames": [
"node"
],
"matchDatasources": [
"node-version"
],
"allowedVersions": "22.x",
"groupName": "Node.js"
},
{
"description": "Group TypeScript-related packages",
"matchPackageNames": [
"typescript",
"@types/node"
],
"groupName": "TypeScript-related packages"
},
{
"description": "Group npm non-major updates",
"matchManagers": [
"npm"
],
"matchUpdateTypes": [
"minor",
"patch"
],
"groupName": "npm non-major updates"
}
]
}
Mit dieser Konfigurationsdatei stelle ich sicher, dass aktuelle SharePoint Framework Abhängigkeiten wie React v17.0.1 oder Node.js v22 eingehalten werden. Außerdem Gruppiere ich bestimmte Pakete, sog. 'Monorepo', z. B. SPFx oder Jest. Für "devDependencies" stelle ich sicher, dass sie als gebündelter Pull-Request angelegt werden, was das Mergen von Pull-Requests vereinfacht. "Automerge" ist komplett deaktiviert, was mit dem automatischen Deployment der SPFx Lösungen zu tun hat, wie in Teil 2 [4] meiner Blogpost-Serie beschrieben.
Besonderheit monorepo:spfx
Als einzige Besonderheit sehe ich die Einstellungen zu SPFx-Paketen. Bei Renovate gibt es zwar das Monorepo "monorepo:spfx" [5], aber leider umfasst es nicht alle SPFx-Pakete. Die Definition des Monorepo ist:
{
"matchPackageNames": [
"/^@microsoft/sp-/",
"/^@microsoft/eslint-.+-spfx$/"
]
}
Diese Definition deckt leider nicht die neuen Pakete "@microsoft/spfx-heft-plugins" und "@microsoft/spfx-web-build-rig" ab, die aber ebenfalls Teil vom SharePoint Framework sind.
Renovate onboarden
Möchte ein Entwickler sein ACE-Projekt "onboarden", also die Paket-Abhängigkeiten des Repositories von Renovate auf dem aktuellen Stand halten lassen, dann reicht es, wenn der Entwickler die Datei renovate.json im Root-Verzeichnis seines Projekts anlegt.
Eine entsprechende Vorlage finden Entwickler im "templates" Verzeichnis des Renovate Repositories. Eine minimale renovate.json sieht dann so aus:
Inhalt der Datei renovate.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"enabled": true,
"extends": ["local><MYPROJECT>/renovate//presets/ace"],
"assignees": [],
"packageRules": []
}
Fazit SharePoint Framework mit Renovate aktuell halten
Das hier vorgestellte Setup hat einige Vorteile, wie ich finde. Durch "self-hosted" habe ich die volle Kontrolle und die Anwendung läßt sich elegant in der Dev-Platform des Kunden betreiben. Mit der globalen Konfiguration stelle ich eine gewisse Sicherheit bei den Updates sicher ("minimumReleaseAge"). Das Onboaring neuer Projekte, speziell ACE-Projekte, ist mit dem Preset relativ einfach. Mit dem Preset für ACE-Projekte habe ich eine zentrale Konfiguration, die ich bei Bedarf leicht an neue Randbedingungen anpassen kann. Die Anzahl erzeugter Pull-Requests ist minimal, was es dem Entwickler erlaubt, sie schnell und bequem zu mergen.