Skip to content
Merged
38 changes: 19 additions & 19 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,25 @@
"extends": ["config:js-lib"]
},
// By Package Manager
{
// Generated from apps/playgrounds/*/package.json arkenvExamples metadata.
"description": "Disable sync-generated example apps",
"matchFileNames": [
// BEGIN GENERATED SYNC EXAMPLES
"examples/basic/**",
"examples/basic-js/**",
"examples/with-bun/**",
"examples/with-bun-react/**",
"examples/with-nextjs/**",
"examples/with-nextjs-strict/**",
"examples/with-nuxt/**",
"examples/with-solid-start/**",
"examples/with-standard-schema/**",
"examples/with-vite-react/**"
// END GENERATED SYNC EXAMPLES
],
"enabled": false
},
{
// Group pnpm workspace updates (minor/patch) across selected dirs
"groupName": "the pnpm group",
Expand Down Expand Up @@ -97,25 +116,6 @@
"matchPackagePatterns": ["^@arkenv/"],
"automerge": true,
"automergeType": "pr"
},
{
// Sync-generated examples only — packageManager comes from catalog + transform.js.
// Hand-maintained examples (with-zod, with-valibot) stay Renovate-updatable via the pnpm group.
"description": "Disable packageManager bumps for sync-generated examples; versions come from the catalog + transform.js",
"matchPackageNames": ["npm", "pnpm", "bun"],
"matchFileNames": [
"examples/basic/**",
"examples/basic-js/**",
"examples/with-nextjs/**",
"examples/with-nextjs-strict/**",
"examples/with-nuxt/**",
"examples/with-solid-start/**",
"examples/with-standard-schema/**",
"examples/with-vite-react/**",
"examples/with-bun/**",
"examples/with-bun-react/**"
],
"enabled": false
}
]
}
10 changes: 10 additions & 0 deletions scripts/sync-examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
import { basename, join } from "node:path";
import { argv } from "node:process";
import { PLAYGROUNDS_DIR } from "./sync-lib/constants.js";
import { syncRenovateConfig } from "./sync-lib/renovate.js";
import { syncPlayground } from "./sync-lib/sync.js";
import { parseCatalog } from "./sync-lib/workspace.js";

Expand All @@ -39,6 +40,7 @@ function main() {
.map((d) => join(PLAYGROUNDS_DIR, d.name));

let hasChanges = false;
const generatedExampleNames = [];

for (const playgroundPath of playgroundDirs) {
const pkgPath = join(playgroundPath, "package.json");
Expand All @@ -65,6 +67,7 @@ function main() {
continue;
}

generatedExampleNames.push(exampleConfig.name);
const changes = syncPlayground(
playgroundPath,
exampleConfig,
Expand All @@ -82,6 +85,13 @@ function main() {
}
}

if (syncRenovateConfig(generatedExampleNames, checkOnly)) {
hasChanges = true;
console.log(
"\n ✗ Renovate config is out of sync with playground metadata.",
);
}

if (checkOnly) {
if (hasChanges) {
console.log("\n❌ Examples are out of sync with playgrounds.");
Expand Down
50 changes: 50 additions & 0 deletions scripts/sync-lib/renovate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { ROOT_DIR } from "./constants.js";

const RENOVATE_CONFIG_PATH = join(ROOT_DIR, ".github", "renovate.json");
const START_MARKER = "// BEGIN GENERATED SYNC EXAMPLES";
const END_MARKER = "// END GENERATED SYNC EXAMPLES";

function generatedMatchFileNames(exampleNames) {
return [
`\t\t\t\t${START_MARKER}`,
...exampleNames.flatMap((name, index) => [
`\t\t\t\t"examples/${name}/**"${index === exampleNames.length - 1 ? "" : ","}`,
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
]),
`\t\t\t\t${END_MARKER}`,
].join("\n");
}

/**
* Keep Renovate's generated-example exclusion in sync with playground metadata.
*/
export function syncRenovateConfig(exampleNames, checkOnly = false) {
const content = readFileSync(RENOVATE_CONFIG_PATH, "utf8");
const markerStart = content.indexOf(START_MARKER);
const start = content.lastIndexOf("\n", markerStart) + 1;
const end = content.indexOf(END_MARKER);

if (markerStart === -1 || end === -1 || end < start) {
throw new Error(
`Renovate config must contain ${START_MARKER} and ${END_MARKER}`,
);
}

const generated = generatedMatchFileNames([...new Set(exampleNames)].sort());
const current = content.slice(start, end + END_MARKER.length);
const updated =
content.slice(0, start) +
generated +
content.slice(end + END_MARKER.length);

if (checkOnly) {
return current !== generated;
}

if (current !== generated) {
writeFileSync(RENOVATE_CONFIG_PATH, updated);
}

return false;
}
Loading