repomatic.cli.ci module

CI commands of the repomatic CLI: run status, runners and the test matrix.

repomatic.cli.main.COMMANDS registers each command here, and files it under its help section.

repomatic.cli.ci.AXIS_HEADER_LABELS = {'os': 'OS', 'python-version': 'Python', 'state': 'State'}

Display names for the job keys show-test-matrix heads a row or column with.

A key absent from here heads its column under the raw name a matrix declares it as, which is also how a caller names it on the command line.

repomatic.cli.ci.UNIVERSAL_AXIS_KEYS = ('os', 'python-version', 'state')

The job keys every test matrix carries, whatever a project configures.

The base cross-product declares the first two and the state include stamps the third, so no [tool.repomatic.test-matrix] directive can leave a matrix without them. That makes them the safe answer when the real matrix cannot be read at all, which is the only time MatrixAxis needs one.

repomatic.cli.ci.CELL_STATE_SEPARATOR = ', '

Joins the labels of the distinct states one grid cell holds.

repomatic.cli.ci.EMPTY_CELL = '—'

What a grid cell shows where the matrix puts no job, like an excluded one.

repomatic.cli.ci.JOB_COUNT_MARK = '×'

Introduces the job count of a cell standing for more than one job.

A cell collapses every job at its intersection, so a matrix varying on a third axis renders five jobs exactly like one. The mark is the East Asian Ambiguous U+00D7, like the EMPTY_CELL placeholder: a terminal drawing ambiguous characters double-width misaligns both alike, and neither before the other.

repomatic.cli.ci.TEST_MATRIX_STATE_DISPLAY = {'stable': '✅ stable', 'unstable': '⁉️ unstable'}

Emoji-decorated labels for job states in the show-test-matrix grid.

The same two glyphs the workflow templates stamp onto each matrix job’s name, and that repomatic.github.ci_status.JobStatus.required() reads back off it, so the grid and the CI verdict cannot come to disagree about which mark means “allowed to fail”.

class repomatic.cli.ci.MatrixAxis[source]

Bases: LazyChoice

A job key naming one axis of the show-test-matrix grid.

A Choice rather than a bare type, so the accepted keys reach the reader through Click’s own [a|b|c] metavar and click-extra’s choice styling, and the shell completes them: a hand-written help line would render none of that. Its values are read at render time rather than declared at import, because they are the project’s own. A repository varying its matrix on a click-version can pivot on it, and that is exactly the axis a fixed list would omit.

The listing is the full matrix’s, the superset: variations and full-include rows reach it alone, while every other directive reaches both matrices. Which one the caller names is not parsed yet when a type converts, so show-test-matrix re-checks the axis against the matrix they did name, and refuses the few keys pr drops.

name: str = 'axis'

the descriptive name of this type

fallback: tuple[str, ...] = ('os', 'python-version', 'state')

Every matrix carries these three, so an unreadable one still pivots.

resolve()[source]

The values this type accepts, read from the project.

Return type:

tuple[str, ...]

class repomatic.cli.ci.WorkflowFile[source]

Bases: LazyChoice

A workflow file name, as .github/workflows/ spells it.

Both commands taking one read the current repository’s own CI, so the checkout is the authority on what may be named. Every file counts, not just the ones monitored_workflows() watches by default: a schedule-only workflow has runs worth reading too.

name: str = 'workflow'

the descriptive name of this type

resolve()[source]

The values this type accepts, read from the project.

Return type:

tuple[str, ...]

repomatic.cli.ci.matrix_axis_sort_key(axis, matrix_name)[source]

Canonical ordering for one grid axis, or None to keep job order.

Keyed on which axis it is rather than on which side of the grid it landed: a transposed grid earns the runner order its columns get by default, and reads as arbitrarily shuffled without it. An axis the test matrix does not define an order for (a click-version) keeps the order the job stream presents it in, which is the matrix author’s own.

Return type:

Callable[[str], Any] | None

repomatic.cli.ci.state_label(state, emoji=True)[source]

Label one job state, glyph-decorated unless emoji says otherwise.

A state the matrix carries but this CLI has no label for renders as itself, so a new one shows up in the grid rather than vanishing from it.

Return type:

str

repomatic.cli.ci.flat_matrix_table(jobs, leading=(), emoji=True)[source]

Lay a solved job stream out as one row per job, one column per key.

A grid has two axes and collapses every other one into its cells, which is what a matrix varying on a third loses. Here each key is a column instead, so nothing collapses and the table is the job list CI will run.

Columns are collected across the whole stream, since a job may carry a key its neighbour does not (the python-label only a prerelease needs), and the state lands last as the outcome the other columns explain. A job missing a key renders empty there rather than shifting its row.

Parameters:
  • jobs (Sequence[Mapping[str, str]]) – The solved job stream, already in the order to render.

  • leading (Sequence[str]) – Keys to column first, in this order, before the ones the stream contributes. A listing sorted on an axis reads as unsorted with that axis buried in the middle, so the caller leads with the axes it ordered by. A key no job carries is skipped rather than columned empty.

  • emoji (bool) – Label the state with its glyph rather than its bare word.

Return type:

tuple[tuple[str, ...], tuple[tuple[str, ...], ...]]

Returns:

A (headers, rows) pair, in the order print_table takes them the other way round.

repomatic.cli.ci.format_matrix_cell(tally, emoji=True)[source]

Render one show-test-matrix grid cell from the jobs that landed in it.

Every state is labelled on its own. A cell holds more than one when the matrix carries an axis beyond its two (a click-version variation, say): both jobs land on the same intersection, and each keeps its own label.

A state carrying several jobs also states how many, since the grid gives a reader no other way to tell five stable jobs from one.

Parameters:
  • tally (Counter[str] | None) – That intersection’s job count per state, as pivot_counts() reports it, or None where the matrix puts no job at all.

  • emoji (bool) – Label each state with its glyph rather than its bare word. A count is not decoration, and shows either way.

Return type:

str

Returns:

The cell text, or EMPTY_CELL for an empty intersection.