repomatic.github.workflow_files module¶

Find, read and walk the GitHub Actions workflow files of a repository.

Every reader of a workflow goes through this module: the repository lint, the workflow lint, the CI status report, repomatic init and the pin updaters. So they agree on which files count as workflows (both extensions GitHub accepts), on how a file parses, and on what a job or a step is.

A leaf module: it imports nothing from the rest of the package, so any module can use it without the risk of an import cycle.

repomatic.github.workflow_files.WORKFLOW_DIR: Final[Path] = PosixPath('.github/workflows')¶

Directory GitHub reads a repository’s workflows from, relative to its root.

repomatic init writes the workflows there and every check reads them from there, so the generator and the checks cannot disagree about where a workflow lives.

repomatic.github.workflow_files.GITHUB_YAML_PATTERNS: Final[tuple[str, ...]] = ('.github/workflows/*.yaml', '.github/workflows/*.yml', '.github/actions/**/*.yaml', '.github/actions/**/*.yml')¶

Globs matching every workflow and composite-action file of a repository.

Rooted at the repository root rather than at .github/, so the same patterns work against the current directory and against an arbitrary target tree. Both .yml and .yaml are listed because GitHub accepts either, whatever this project’s own long-extension convention prefers: a downstream repository is free to have picked the short one.

The pin updaters read the pins to bump from these files, and repomatic init reads them to floor a new pin. The two must agree on which files carry a pin, or init would floor against a file sync-workflow-pins never bumps.

repomatic.github.workflow_files.WORKFLOW_SUFFIXES: Final[frozenset[str]] = frozenset({'.yaml', '.yml'})¶

File extensions GitHub reads a workflow from.

repomatic.github.workflow_files.github_yaml_paths(root)[source]¶

Every workflow and composite-action file under root.

Parameters:

root (Path) – Root of the repository to scan.

Return type:

list[Path]

Returns:

The files matching GITHUB_YAML_PATTERNS, sorted.

repomatic.github.workflow_files.workflow_paths(directory=PosixPath('.github/workflows'))[source]¶

Every workflow file in directory.

Parameters:

directory (Path) – Directory holding the workflow files.

Return type:

list[Path]

Returns:

The .yaml and .yml files, sorted. Empty when the directory does not exist.

repomatic.github.workflow_files.read_workflow_texts(directory=PosixPath('.github/workflows'))[source]¶

Read every workflow file in directory, skipping the unreadable ones.

The raw-text half of the workflow walk, for the checks that match against the file as written rather than as parsed: an argument inside a folded scalar is one opaque string to a YAML parser, whichever way the file is loaded.

Parameters:

directory (Path) – Directory holding the workflow files.

Return type:

dict[Path, str]

Returns:

A mapping of path to file content, in sorted path order.

repomatic.github.workflow_files.load_workflow(text)[source]¶

Parse the text of one workflow file.

Parameters:

text (str) – The file content.

Return type:

dict[str, Any] | None

Returns:

The parsed document, or None when text is not YAML or does not parse into a mapping, which is the only shape a workflow can take.

repomatic.github.workflow_files.parse_workflow_texts(texts)[source]¶

Parse pre-read workflow texts, keeping the ones that hold a mapping.

The parsed half of the workflow walk. A file that does not parse is reported as a warning naming it, then skipped.

Parameters:

texts (Mapping[Path, str]) – Raw file contents keyed by path, from read_workflow_texts().

Return type:

dict[Path, dict[str, Any]]

Returns:

A mapping of path to parsed document.

repomatic.github.workflow_files.load_workflows(directory=PosixPath('.github/workflows'))[source]¶

Read and parse every workflow file in directory.

Parameters:

directory (Path) – Directory holding the workflow files.

Return type:

dict[Path, dict[str, Any]]

Returns:

A mapping of path to parsed document, in sorted path order.

repomatic.github.workflow_files.workflow_triggers(data)[source]¶

Extract a parsed workflow’s on: mapping.

Note

PyYAML follows YAML 1.1, where a bare on key parses as the boolean True while a quoted "on" stays a string. Both spellings occur in the wild, so every reader of a workflow’s triggers has to try the boolean key first and the string key second. Resolving that here once keeps the quirk from being re-remembered at each call site.

Parameters:

data (object) – A parsed workflow, from load_workflow().

Return type:

dict[str, Any]

Returns:

The trigger mapping, empty when data is not a mapping or declares no triggers.

repomatic.github.workflow_files.jobs_of(data)[source]¶

Yield (job_id, job) for every job mapping of one workflow.

The one place the “a job is a mapping” guard lives: a jobs: key that is not a mapping yields nothing, and a malformed job (a string, a list) is skipped, so no walker trips over either.

Parameters:

data (Mapping[str, Any]) – One parsed workflow document.

Return type:

Iterator[tuple[str, dict[str, Any]]]

repomatic.github.workflow_files.steps_of(job)[source]¶

Yield every step mapping of one job, with the guard of jobs_of().

Parameters:

job (Mapping[str, Any]) – One job mapping.

Return type:

Iterator[dict[str, Any]]

repomatic.github.workflow_files.iter_jobs(workflows)[source]¶

Yield (path, job_id, job) for every job across workflows.

Parameters:

workflows (Mapping[Path, Mapping[str, Any]]) – Parsed workflow documents, keyed by path.

Return type:

Iterator[tuple[Path, str, dict[str, Any]]]

repomatic.github.workflow_files.iter_steps(workflows)[source]¶

Yield (path, job_id, step) for every step across workflows.

Parameters:

workflows (Mapping[Path, Mapping[str, Any]]) – Parsed workflow documents, keyed by path.

Return type:

Iterator[tuple[Path, str, dict[str, Any]]]

repomatic.github.workflow_files.literal_runners(workflow_dir=PosixPath('.github/workflows'), workflows=None)[source]¶

Every runner image this repository names outright, and where.

Only literals: a value built from an expression (${{ matrix.os }}) names no image here, and the axis it draws from is checked at its definition. A thin caller declares no steps: and runs on whatever the reusable workflow chose, which is that workflow’s business rather than this repository’s.

Separate from KNOWN_RUNNERS, and deliberately so. That set is what this project has chosen; this function reports what it is running, and the two diverge exactly when something has been left behind. Callers wanting “an image this repository has a stake in” need the union of both.

Parameters:
  • workflow_dir (Path) – Directory holding the workflow files. Ignored when workflows is supplied.

  • workflows (Mapping[Path, Mapping[str, Any]] | None) – Pre-parsed workflows, read from disk when None.

Return type:

dict[str, list[str]]

Returns:

A mapping of runner label to the file.yaml:job-id locations naming it, empty when no job names one literally.