Stop the compat check from failing after every release (#3189)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-09-25 11:22:46 +02:00
1 parent ef870bb928
commit 3460091414
3 files changed
+31 -6

No files matched your search

+1 -1
View File
@@ -125,7 +125,7 @@ It reports what the release has and the build lost, one key per line:
| `js:tabler.esm.js:tabler` | a top-level export is gone |
| `file:dist/libs/litepicker/dist/litepicker.js` | a file is gone from the package |
Fix each one with the patterns from section 3, then run it again. Known breaks are listed in `.build/compat-baseline.txt`; when you fix one, delete its line, or the check fails on the stale entry. Never add a line to the baseline to make a PR green. A line gets ` # accepted: <why>` only after the maintainers decided to ship that break. CI runs the check after the build. The Release workflow runs it with `--strict` on every push to `dev`, before it opens the versions pull request or publishes, so nothing reaches npm while an unaccepted line is left.
Fix each one with the patterns from section 3, then run it again. Known breaks are listed in `.build/compat-baseline.txt`; when you fix one, delete its line, or the check fails on the stale entry. Never add a line to the baseline to make a PR green. A line gets ` # accepted: <why>` only after the maintainers decided to ship that break. The file's `# against: <version>` line names the release the list was written for. Once a newer release is on npm, every listed break shipped in it, so the check ignores the list and only warns; run `pnpm run check:compat --reset` and commit the emptied file. CI runs the check after the build. The Release workflow runs it with `--strict` on every push to `dev`, before it opens the versions pull request or publishes, so nothing reaches npm while an unaccepted line is left.
`check:compat` compares names. `check:compat-fixture` covers behaviour: `.build/compat-fixture/` is a small project written the way a user of the last release would write it (`@use … with` on old variables, old functions, `rgba(var(--tblr-primary-rgb), .5)`, an empty `.legend`, the libraries in `dist/libs`, `tabler.tabler.getColor()`), and the check runs it against the release and against the working tree. Every assertion has to give the same answer on both.
+26 -3
View File
@@ -20,11 +20,16 @@
// longer breaks, so fixing one means deleting its line. `--strict` also fails
// while any unaccepted line is left: the release runs it that way.
//
// The baseline names the release it was written against (`# against: 1.6.0`).
// Once a newer release is on npm, every listed break shipped in it, so none of
// them can break against it: the check ignores the stale list and only warns.
// `--reset` empties the list and points it at the current release.
//
// Needs `core/dist`, so run it after the core build. See the `backward-compat`
// skill for how to fix what it reports.
//
// Usage: tsx .build/check-compat.ts [--strict]
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'
// Usage: tsx .build/check-compat.ts [--strict | --reset]
import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
import { join, relative } from 'node:path'
import { compileString } from 'sass'
import { pkgName, releasedPackage } from './released-package'
@@ -32,6 +37,8 @@ import { pkgName, releasedPackage } from './released-package'
const coreDir = 'core'
const baselineFile = '.build/compat-baseline.txt'
const strict = process.argv.includes('--strict')
const reset = process.argv.includes('--reset')
const againstPattern = /^#\s*against:\s*(\S+)\s*$/
function walk(root: string, dir = root): string[] {
if (!existsSync(dir)) return []
@@ -210,13 +217,29 @@ async function main() {
const { dir: released, version } = await releasedPackage()
const breaks = new Set([...cssBreaks(released, coreDir), ...sassBreaks(released, coreDir), ...sassTypeBreaks(released, coreDir), ...jsBreaks(released, coreDir), ...fileBreaks(released, coreDir)])
const lines = readFileSync(baselineFile, 'utf8').split('\n')
const againstIndex = lines.findIndex((line) => againstPattern.test(line))
if (againstIndex === -1) throw new Error(`${baselineFile} has no \`# against: <version>\` line`)
const against = againstPattern.exec(lines[againstIndex]!)![1]!
if (reset) {
writeFileSync(baselineFile, [...lines.slice(0, againstIndex), `# against: ${version}`, ''].join('\n'))
console.log(`${baselineFile} emptied and pointed at ${pkgName}@${version}.`)
return
}
// Written against an older release: every listed break shipped in the current one.
const stale = against !== version
const baseline = new Map<string, boolean>() // key → accepted
for (const line of readFileSync(baselineFile, 'utf8').split('\n')) {
for (const line of stale ? [] : lines) {
const [entry, comment = ''] = line.split(' # ')
const key = entry!.trim()
if (!key || key.startsWith('#')) continue
baseline.set(key, comment.trim().startsWith('accepted:'))
}
if (stale) {
console.warn(`${baselineFile} was written against ${pkgName}@${against}, npm has ${version}: its entries no longer apply. Run \`pnpm run check:compat --reset\` and commit the file.\n`)
}
const added = [...breaks].filter((key) => !baseline.has(key)).sort()
const fixed = [...baseline.keys()].filter((key) => !breaks.has(key))
+4 -2
View File
@@ -8,5 +8,7 @@
# to a line only after the maintainers decided to ship the break, for example
# an override for a class that a third-party library dropped.
#
# Empty since 1.6.0 shipped: the breaks accepted for 1.6 are part of the release
# the check now compares with.
# The line below names the release this list is written against. Once a newer
# release is on npm the list no longer applies: the check only warns, and
# `pnpm run check:compat --reset` empties it and moves the line to that release.
# against: 1.6.0