repomatic.github.outputs module¶

What a command hands back to GitHub Actions: step outputs and annotations.

A step output travels in $GITHUB_OUTPUT, inline when its size is bounded and as a file path when it is a report. An annotation is a workflow command printed to the log. Both have size and format rules that this module applies in one place.

repomatic.github.outputs.MAX_STEP_OUTPUT_BYTES = 130048¶

Ceiling for a single $GITHUB_OUTPUT value, in UTF-8 bytes.

A step output only exists to be read by a later step, and the two ways of reading one both land it in the consumer’s environment: env: mapping a steps.*.outputs.* expression, and action inputs, which the runner exports as INPUT_*. Linux caps a single argv/envp string at MAX_ARG_STRLEN, 32 pages, so a value past that makes the runner’s execve() of /usr/bin/bash fail with E2BIG before the step’s own command exists:

##[error]An error occurred trying to start process '/usr/bin/bash' with
working directory '/home/runner/work/orchard/orchard'. Argument list too long

The 1 KiB reserve covers the NAME= prefix the kernel counts as part of the same string, well beyond the longest name in use.

This ceiling only binds a value the environment has to carry. A report that grows without bound belongs in a file instead: see format_file_output(), which hands the consumer a path and leaves the content untrimmed.

Caution

This is a transport limit, counted in bytes, and is deliberately looser than repomatic.github.pr_body.GITHUB_BODY_MAX_CHARS, which is a content limit counted in UTF-16 code units. A value can clear this one and still be trimmed later by repomatic.github.pr_body.build_pr_body(), which is the layer that leaves the reader a truncation notice.

class repomatic.github.outputs.AnnotationLevel(*values)[source]¶

Bases: Enum

Annotation levels for GitHub Actions workflow commands.

Mirrors the three levels GitHub supports, even where the codebase only emits a subset.

ERROR = 'error'¶
WARNING = 'warning'¶
NOTICE = 'notice'¶
property glyph: str¶

The symbol that opens a terminal line reporting at this level.

✗ for an error and ⚠ for a warning. A notice reads ℹ, the symbol a skipped check prints too: neither one asks the reader to act.

repomatic.github.outputs.generate_delimiter()[source]¶

Generate a unique delimiter for GitHub Actions multiline output.

GitHub Actions requires a unique delimiter to encode multiline values in $GITHUB_OUTPUT. This function generates a random delimiter that is extremely unlikely to appear in the output content.

The delimiter format is GHA_DELIMITER_NNNNNNNNN where N is a digit, producing a 9-digit random suffix.

Return type:

str

Returns:

A unique delimiter string.

repomatic.github.outputs.trim_to_budget(text, budget, measure)[source]¶

Keep the leading whole lines of text that fit in budget.

Cutting on line boundaries keeps the trimmed markdown rendering: a table missing rows still renders, one cut mid-row does not.

The one trimming loop behind both of GitHub’s size ceilings, which count in different units: measure prices a line in whatever unit the caller’s budget is denominated in (UTF-8 bytes for a step output, UTF-16 code units for a PR or issue body).

Parameters:
  • text (str) – Content to trim.

  • budget (int) – Available room, in measure’s unit.

  • measure (Callable[[str], int]) – Returns the size of one line in that unit.

Return type:

str

Returns:

The kept lines, right-stripped; empty when nothing fits.

repomatic.github.outputs.trim_to_byte_budget(text, budget)[source]¶

Keep the leading whole lines of text that fit in budget UTF-8 bytes.

trim_to_budget() in the step-output unit. Trimming whole lines also keeps the result valid UTF-8, which slicing a byte string cannot promise.

Parameters:
  • text (str) – Content to trim.

  • budget (int) – Available room, in UTF-8 bytes.

Return type:

str

Returns:

The kept lines, right-stripped; empty when nothing fits.

repomatic.github.outputs.format_multiline_output(name, value)[source]¶

Format a multiline value for GitHub Actions output.

Produces output in the heredoc format required by $GITHUB_OUTPUT:

name<<GHA_DELIMITER_NNNNNNNNN
value line 1
value line 2
GHA_DELIMITER_NNNNNNNNN

Values over MAX_STEP_OUTPUT_BYTES are trimmed to fit, so a step reading this output cannot be killed by E2BIG before it starts.

Parameters:
  • name (str) – The output variable name.

  • value (str) – The multiline value.

Return type:

str

Returns:

Formatted string for $GITHUB_OUTPUT.

repomatic.github.outputs.write_output_file(name, value)[source]¶

Write a step output’s value to a file, and return that file’s path.

The file lands in RUNNER_TEMP where the runner exports it, which is per-job and cleaned up by the runner itself, and in the system temporary directory otherwise. Either is shared by every step of a job, which is what makes the handoff work: producer and consumer are separate processes on one filesystem.

Parameters:
  • name (str) – The step output name, which the filename carries so a spilled report is recognisable in a temporary directory.

  • value (str) – The content to write.

Return type:

Path

Returns:

Path of the file holding value.

repomatic.github.outputs.format_file_output(name, value)[source]¶

Format a value as a file-backed output, for a consumer to read back.

Writes value out with write_output_file() and names the step output <name>_file, so the consuming step receives a path instead of content:

harvest_file=/home/runner/work/_temp/repomatic-harvest-8m1t0p.md

This is the escape hatch from MAX_STEP_OUTPUT_BYTES. A report grows with the repository it describes and has no ceiling of its own: the release notes of a dependency sweep can reach twice what the environment carries, and trimming to fit loses content. A path keeps the environment holding a hundred-odd bytes whatever the report weighs, and leaves any trimming to repomatic.github.pr_body.build_pr_body(), which is the layer that knows GitHub’s own body limit and marks the cut for the reader.

Parameters:
  • name (str) – The output variable name, before the _file suffix.

  • value (str) – The content to hand over.

Return type:

str

Returns:

Formatted string for $GITHUB_OUTPUT.

repomatic.github.outputs.read_file_output(name)[source]¶

Read the content of a file-backed value, from its <NAME>_FILE path.

The consuming half of format_file_output(): the workflow maps the <name>_file step output to the <NAME>_FILE variable of the step that reads it.

Parameters:

name (str) – The environment variable name, before the _FILE suffix.

Return type:

str

Returns:

The content of the file, empty when the variable is not set.

repomatic.github.outputs.write_text_output(content, output)[source]¶

Write content to an --output path, then close what was opened.

For -, prep_path returns the live sys.stdout when stdout has no file descriptor, as under a test runner. Only a stream it opened is closed: closing the live one would end every later write of the run.

Parameters:
  • content (str) – The text to write. A trailing newline is added.

  • output (Path) – The destination path, or - for stdout.

Return type:

None

repomatic.github.outputs.emit_report(body, output, output_format, key='diff_table', outputs=None)[source]¶

Write a markdown report to --output, optionally as a step output.

The shared tail of every report-producing command: nothing is written when no output path is set or the body is empty; with --output-format github-actions the body is spilled to a file and the step output named <key>_file carries its path, for $GITHUB_OUTPUT consumption.

A report is the one value here with no ceiling of its own, so it is the one that must not travel inline: see format_file_output().

Parameters:
  • body (str) – The markdown report.

  • output (Path | None) – The --output path (None to skip, - for stdout).

  • output_format (str) – markdown or github-actions.

  • key (str) – The step output variable name, before the _file suffix, for the github-actions format.

  • outputs (Mapping[str, str] | None) – Single-line step outputs written beside the report’s path, for the github-actions format only. prep_path truncates the file it opens, so every output of a step has to go through this one write.

Return type:

None

repomatic.github.outputs.emit_annotation(level, message)[source]¶

Emit a GitHub Actions workflow annotation.

Prints a workflow command that creates an annotation visible in the GitHub Actions UI and PR checks.

Parameters:
  • level (AnnotationLevel) – The annotation level.

  • message (str) – The annotation message.

Return type:

None

repomatic.github.outputs.add_problem_matcher(path)[source]¶

Register the problem matcher at path with the GitHub Actions runner.

The runner reads the file when it processes the command, so the file must outlast the process that prints it. The command is flushed at once: a tool started next writes its findings to the same stream, and the runner must read the command before the first of them.

Return type:

None

repomatic.github.outputs.remove_problem_matcher(owner)[source]¶

Unregister the problem matcher of owner from the GitHub Actions runner.

Return type:

None

repomatic.github.outputs.report_finding(level, message)[source]¶

Report one finding in the log and as a workflow annotation.

Emits the annotation first, then prints the line the terminal reader sees, opened by the AnnotationLevel.glyph of level. Every lint that reports a failure goes through here, so the symbol and the annotation level of a finding always agree.

Parameters:
  • level (AnnotationLevel) – Severity of the finding.

  • message (str) – The finding, one line.

Return type:

None