Skip to content

basou: Measure the name of a file and the paths of files on a board - #363

Merged
takashi-matsuyama merged 3 commits into
board/shape-v3from
board/measure-file-name
Oct 18, 2026
Merged

takashi-matsuyama merged 3 commits into
board/shape-v3from
board/measure-file-name

Conversation

@takashi-matsuyama

Copy link
Copy Markdown
Member

The third of the changes that move basou board (experimental) to a new shape of its declaration and its records. Like the first two, it lands on the integration branch board/shape-v3, not on main; all of them go to main and out in one release.

What changes

  • Two kinds of measure over a repo's files (from board_version: 3). Both take repo, include, exclude and at as a file_count does, and are not measured where a file_count is not (a fixed directory with nothing under it, a directory git could not list, a symlink that leaves the repository, a repo or revision that cannot be read).

    measures:
      - { id: latest_migration, kind: file_name, repo: ../app, include: ["db/migrations/*.sql"], pick: last, pattern: "^(\\d{8})_", unit: date }
      - { id: migrations, kind: file_paths, repo: ../app, include: ["db/migrations/*.sql"], unit: files }
    • file_name picks the first or the last of the files matched (pick, required), in the byte order of their paths in the repository, as git orders them, and its value is that file's name. With a pattern, it picks only among the files whose name the pattern matches, and the value is what the pattern's group holds. The names are narrowed before one is picked, so a name with no match at the end of the order (schema.sql after the dated ones) does not hide the one before it.
    • group is filled in as 1 only when there is a pattern; a group without a pattern is refused, so a declaration's snapshot never holds a group that means nothing. A group the pattern does not have is refused, as for a regex_capture.
    • No file to pick, no name the pattern matches, or a group that took no part in the match is a null with that as the reason: a string has no zero.
    • file_paths gives the paths matched, in byte order, up to 1000 (BOARD_FILE_PATHS_MAX, fixed with version 3: a measure has no method version, so changing it would turn the same repository's value between null and a list unseen). More is a null with that as the reason. Nothing matched under a directory that is there is an empty list. Two paths that are not UTF-8 and read as the same text are kept once.
    • A ratio takes neither (ratios[0].numerator: 'latest_migration' is a file_name, which is not a number).
    • A board of version 1 or 2 that has one is told that version 3 reads it (measures[0].kind: 'file_name' is read from board_version 3 on; this file is board_version 2).
  • The value of a measure may be a list of strings. In the difference from the previous record, a measure whose value is a list in both records is compared as a set: each path that came in is added (measures.migrations.value["db/migrations/20261001_x.sql"]), each that went out removed. When one of the two is not a list (not measured, or no such measure then), the value is compared whole. The difference is not part of a record.

  • basou board measure prints a list as its count under Measures: (migrations 12 files (paths in --json) [data]), and --json gives the paths. Under Since the previous record, the paths that came in and went out are a line each, and a list compared whole is printed whole.

  • The board page draws a list in its lane as a count, with the paths folded under it (<details>), and reads a record whose measure holds one; a record whose measure holds a list of anything but strings is not drawn.

  • basou board guide says that Measures: in measure.txt gives a list as a count, where to read the paths, and how the difference gives them (each path when both records hold a list, the list whole when only one does). basou board init's comment on measures names the two kinds.

Tests

  • Declaration: what each kind takes and refuses (pick, group with and without a pattern, a group past the pattern's, a key the kind does not take, a repo the manifest does not declare), group filled only with a pattern, a ratio of either refused, the kinds a version 3 board names, and which version a version 1 or 2 board is told reads them.
  • Measure: first and last in byte order, narrowed by the pattern before the pick; the group, group 0, at a revision, with an exclude; the order by the whole path in bytes, not by the name or the locale (B before a, and a name whose first byte is 0xc3 after z); the paths matched, an empty list, the lane; no file, no name, a group that took no part, a fixed directory with nothing under it (in the working tree and at a revision), a repo not on disk; two non-UTF-8 paths that read as the same text kept once; 1000 paths kept and 1001 not measured; a symlink that leaves the repository.
  • Diff: paths added and removed, none for the same set in another order, the rest of the measure compared as before, the value whole when one of the two is not a list, and an id that is not a plain word quoted.
  • Board page: a version 3 record with a name and a list drawn in its lane, and one with a list of numbers not drawn; the page script draws a list as a closed <details> with its count and unit.
  • board measure prints a list as a count and --json gives the paths; the guide's line and init's comment.
  • Mutation checks in a copy: each of 38 mutations of the new code fails a test (the declaration's kinds, pick, group and the ratio and repo checks; the order, the narrowing, the name, the dedupe and the limit; the set diff; the page's reader and its drawing; the text output). Sorting the decoded text instead of the bytes passed at first and is held by the second commit's test.
  • pnpm -r build, pnpm typecheck, pnpm -r test:coverage, pnpm test:scripts, pnpm lint, pnpm lint:lang and pnpm lint:paths pass locally.

- board.yaml: board_version 3 adds two kinds of measure over a repo's
  files, with include, exclude and at as a file_count has them, and not
  measured where a file_count is not. file_name picks the first or the
  last of the files matched (pick), in the byte order of their paths, and
  its value is that file's name; with a pattern it picks only among the
  files whose name the pattern matches, and the value is what the
  pattern's group holds (1 when it names none, and a group without a
  pattern is refused). file_paths gives the paths matched, in byte order,
  up to 1000; more is not measured. No file to pick is not measured: a
  string has no zero. A ratio takes neither, and a board of version 1 or 2
  is told that version 3 reads them.
- The value of a measure may be a list of strings. The difference from the
  previous record lists each path that came in or went out when both hold
  a list, and the value whole otherwise.
- board measure prints a list as a count, and --json gives the paths; the
  board page draws it in its lane as a count, with the paths folded under
  it, and reads a record whose measure holds one.
- board guide says where to read the paths and how the difference gives
  them; board init's comment on measures names the two kinds.
A name of four bytes from 0xf0 (U+1F600) is after one from 0xef (U+FF5E)
in byte order, though its first UTF-16 unit is before. The test now tells
the two orders apart, so sorting by the decoded text fails it.
- board guide and CHANGELOG: it is the Measures section of board measure
  that gives a list as a count. The difference from the previous record
  gives each path that came in or went out when both records hold a list,
  and the list whole when only one does.
- The comment of BOARD_DEFAULT_CAPTURE_GROUP names a file_name measure
  with a pattern, which takes it too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant