~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
134 lines · 5.5 KB Raw History
// Which tests a change needs: the source files changed since tests last
// passed through `just t-changed`, and the cargo test runs that cover them.
//
//   node harness/changed.mjs          list them
//   node harness/changed.mjs --run    run them, against the harness
//                                     `just pds` left up if there is one,
//                                     and mark them passed
//
// Passing is a stamp file's time, target/tested.stamp; with none, every
// file counts as changed. The map is coarse on purpose: a change to the
// core crate runs everything, as everything is built on it.

import { spawnSync } from 'node:child_process'
import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from 'node:fs'
import { dirname, join, relative, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

const root = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const stamp = join(root, 'target/tested.stamp')
const since = existsSync(stamp) ? statSync(stamp).mtimeMs : 0
const skip = new Set(['target', 'node_modules', '.git', 'build', '.svelte-kit'])

const walk = (dir, out = []) => {
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
    if (skip.has(entry.name)) continue
    const path = join(dir, entry.name)
    if (entry.isDirectory()) walk(path, out)
    else if (statSync(path).mtimeMs > since) out.push(relative(root, path))
  }
  return out
}
const changed = ['crates', 'harness', 'web', 'Cargo.toml', 'Cargo.lock']
  .map((p) => join(root, p))
  .filter(existsSync)
  .flatMap((p) =>
    statSync(p).isDirectory() ? walk(p) : statSync(p).mtimeMs > since ? [relative(root, p)] : [],
  )

const serve = (...tests) => [
  ['-p', 'knotless-serve', '--lib'],
  ...tests.map((t) => ['-p', 'knotless-serve', '--test', t]),
]
/// The test runs for a file, and whether the pages may look different.
const runs = (file) => {
  const m = (re) => file.match(re)
  let x
  if (
    m(/^crates\/knotless\/(src|tests\/common)\//) ||
    m(/^(Cargo\.(toml|lock)|harness\/pds\.mjs|harness\/package)/)
  ) {
    return { runs: [['--workspace']], pages: true }
  }
  if ((x = m(/^crates\/(knotless-\w+)\/Cargo\.toml$/)))
    return { runs: [['-p', x[1]]], pages: x[1] === 'knotless-serve' }
  if (m(/^crates\/knotless\/Cargo\.toml$/)) return { runs: [['--workspace']], pages: true }
  if ((x = m(/^crates\/knotless\/tests\/(\w+)\.rs$/)))
    return { runs: [['-p', 'knotless', '--test', x[1]]] }
  if (m(/^crates\/knotless-mcp\//)) return { runs: [['-p', 'knotless-mcp']] }
  if (m(/^crates\/knotless-run\//)) return { runs: [['-p', 'knotless-run']] }
  if ((x = m(/^crates\/knotless-serve\/tests\/(\w+)\.rs$/)))
    return { runs: [['-p', 'knotless-serve', '--test', x[1]]] }
  if (m(/^crates\/knotless-serve\/src\/web\//)) return { runs: serve('web'), pages: true }
  if ((x = m(/^crates\/knotless-serve\/src\/(\w+)\.rs$/))) {
    const pages = { runs: serve('web'), pages: true }
    return (
      {
        web: pages,
        highlight: pages,
        diff: pages,
        objects: pages,
        gateway: { runs: serve('gateway') },
        api: { runs: serve('serve') },
        smart: { runs: serve('serve') },
        firehose: { runs: serve('jetstream', 'forge') },
        jetstream: { runs: serve('jetstream', 'forge') },
        index: { runs: serve('forge', 'web'), pages: true },
        appview: { runs: serve('forge', 'web'), pages: true },
      }[x[1]] ?? {
        runs: [
          ['-p', 'knotless-serve'],
          ['-p', 'knotless-mcp'],
        ],
        pages: true,
      }
    )
  }
  if (m(/^crates\/knotless-serve\//)) return { runs: [['-p', 'knotless-serve']], pages: true }
  if (m(/^harness\/shots\//) || m(/^web\//)) return { runs: [], pages: true }
  if (m(/^harness\/authorize\.mjs$/)) return { runs: [['-p', 'knotless', '--test', 'oauth']] }
  return { runs: [] }
}

const planned = changed.map(runs)
let all = planned.flatMap((p) => p.runs)
// A whole package, or the workspace, covers the narrower runs within it.
if (all.some((r) => r[0] === '--workspace')) all = [['--workspace']]
const whole = new Set(all.filter((r) => r.length === 2).map((r) => r[1]))
all = all.filter((r) => r.length === 2 || !whole.has(r[1]))
const unique = [...new Map(all.map((r) => [r.join(' '), r])).values()]
const pages = planned.some((p) => p.pages)

if (changed.length === 0) {
  console.log('Nothing changed since tests last passed.')
  process.exit(0)
}
console.log(
  `Changed since tests last passed${since ? '' : ' (no record of a pass, so everything)'}:`,
)
for (const f of changed.slice(0, 20)) console.log(`  ${f}`)
if (changed.length > 20) console.log(`  … and ${changed.length - 20} more`)
console.log(unique.length ? 'Tests:' : 'No tests cover these.')
for (const r of unique) console.log(`  cargo test ${r.join(' ')}`)
if (pages) console.log('The pages may look different: `just shots` shows what moved since main.')

if (process.argv.includes('--run')) {
  const started = Date.now()
  const env = { ...process.env, KNOTLESS_TEST_NET: join(root, 'target/test-net.json') }
  for (const r of unique) {
    console.log(`\n$ cargo test ${r.join(' ')}`)
    const res = spawnSync('rustup', ['run', 'stable', 'cargo', 'test', ...r], {
      cwd: root,
      env,
      stdio: 'inherit',
    })
    if (res.status !== 0) process.exit(res.status ?? 1)
  }
  // Marked as of when the run began, so a file changed during it is not
  // taken for tested.
  mkdirSync(dirname(stamp), { recursive: true })
  writeFileSync(stamp, '')
  const { utimesSync } = await import('node:fs')
  utimesSync(stamp, started / 1000, started / 1000)
  console.log('\nPassed; marked.')
}