From 9acef4275cf045623e18afac4c812fbd51378137 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Tue, 8 Sep 2026 04:45:51 +0200 Subject: [PATCH 1/4] =?UTF-8?q?ci(prek):=20quieten=20the=20CI=20log=20?= =?UTF-8?q?=E2=80=94=20drop=20--verbose,=20skip=20the=20identity=20hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two sources of noise around the one thing a reader opens the log for. `identity` is a meta-hook that echoes every file passed to the static checks. Useful locally when working out why a hook did or did not fire; on `--all-files` it prints the entire repository into the log before any result appears. It stays enabled locally and is skipped only in CI. `--verbose` was added on the belief that it bought live progress in a non-TTY log. Measured, it does not: first output and total runtime coincide with the flag and without it, so prek emits nothing until the run finishes either way. It streams only when stdout is a TTY, where it draws an in-place progress UI with cursor-control escapes; against a pipe it suppresses that renderer and prints one block at the end. `--no-progress` behaves identically and `-q` prints nothing at all. The flag's only effect in CI was to add every passing hook's stdout to that final block. Failures still print their output, and `--show-diff-on-failure` still shows what a fixer hook changed. Note for anyone editing this later: `--skip a,b` is not a list. Prek takes one HOOK|PROJECT per occurrence and merely warns that a comma-joined value matched no hooks, so the comma form reads as working while skipping nothing — which is what my first attempt did, caught by running the command rather than trusting it. Generated-by: Claude Code (Opus 5) --- .github/workflows/pre-commit.yml | 36 ++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index a8e3ba313..060b9a1c1 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -103,11 +103,35 @@ jobs: # CI, so skip it — the hook still runs locally on `git commit` / # `prek run`, where there is no separate matrix. # - # `--verbose`: without it prek renders a progress UI that a - # non-TTY CI log buffers and only flushes at the end, so a long - # run shows nothing while it works. Verbose prints each hook's - # result and output as it completes, giving live progress in the - # Actions log. + # `--skip identity`: the `identity` meta-hook echoes every file + # passed to the static checks. That is a useful local + # troubleshooting aid, but on `--all-files` it prints the whole + # repository into the CI log ahead of any actual result, burying + # the failure a reader came for. It stays enabled locally. + # + # No `--verbose`. It was added believing it bought live progress in + # a non-TTY log. It does not — measured on this repo, first output + # and total runtime coincide with the flag and without it: prek + # emits nothing until the run finishes either way. prek streams + # only when stdout is a TTY, where it draws an in-place progress UI + # (spinner, cursor-control escapes, redrawn lines); with stdout a + # pipe it suppresses that renderer and prints the whole result + # block at the end. `--no-progress` behaves identically, and `-q` + # prints nothing at all on success. + # + # So the flag's only effect in CI is to add every *passing* hook's + # stdout to that final block — several hundred lines around the one + # thing worth reading. Failures still print their output, and + # `--show-diff-on-failure` still shows what a fixer hook changed. + # + # Real streaming would mean allocating a pty (`script -qec …`), + # which fills the Actions log with ANSI redraw escapes. Waiting for + # the block is the better trade. + # + # Note the repeated flag: `--skip a,b` is NOT a list — prek takes a + # single HOOK|PROJECT per occurrence, and a comma-joined value + # matches no hook at all. It warns rather than failing, so the + # comma form looks like it worked while skipping nothing. run: >- prek run --show-diff-on-failure --color=always --all-files - --verbose --skip workspace-pytest + --skip workspace-pytest --skip identity From 3c0d1aef18496389aea06f44ca3320f2e3af1911 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Tue, 8 Sep 2026 04:54:08 +0200 Subject: [PATCH 2/4] ci(prek): allocate a pty so prek streams progress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Experiment to validate on the runner: prek streams per-hook results only when stdout is a TTY. `script -qec` allocates one; `--no-progress` suppresses the spinner whose in-place redraws would otherwise fill the log with cursor-control escapes. `-e` propagates the exit status, without which a failing prek would report as a passing step. Cannot be verified locally — script(1) has no terminal to attach to in this sandbox — so this is measured against the real Actions log and kept or reverted on that evidence. Generated-by: Claude Code (Opus 5) --- .github/workflows/pre-commit.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 060b9a1c1..b823d6de2 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -124,14 +124,20 @@ jobs: # thing worth reading. Failures still print their output, and # `--show-diff-on-failure` still shows what a fixer hook changed. # - # Real streaming would mean allocating a pty (`script -qec …`), - # which fills the Actions log with ANSI redraw escapes. Waiting for - # the block is the better trade. + # `script -qec … /dev/null` allocates a pty so prek uses its + # streaming renderer instead. `-e` propagates the command's exit + # status, without which a failing prek would be reported as a + # passing step. `--no-progress` suppresses the spinner that the + # streaming renderer would otherwise redraw in place, which is + # what would otherwise fill this log with ESC[2K / ESC[2A + # sequences — the pty buys progress, --no-progress pays for it in + # cursor control we do not want. # # Note the repeated flag: `--skip a,b` is NOT a list — prek takes a # single HOOK|PROJECT per occurrence, and a comma-joined value # matches no hook at all. It warns rather than failing, so the # comma form looks like it worked while skipping nothing. run: >- - prek run --show-diff-on-failure --color=always --all-files - --skip workspace-pytest --skip identity + script -qec "prek run --show-diff-on-failure --color=always + --all-files --no-progress --skip workspace-pytest --skip identity" + /dev/null From 968ff9508d11a1c146a4b38b71fac3942cfab058 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Tue, 8 Sep 2026 04:56:03 +0200 Subject: [PATCH 3/4] ci(prek): keep the pty, drop --no-progress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pty plus --no-progress streamed nothing. `--no-progress` hides the streaming renderer itself, not merely its spinner — the progress rendering and the live per-hook output are the same mechanism, so suppressing one suppresses the other. That combination paid the pty's cost and bought none of its benefit. Keeping the pty alone: prek streams, at the price of the in-place redraw escapes the spinner emits. Generated-by: Claude Code (Opus 5) --- .github/workflows/pre-commit.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index b823d6de2..66c116c1c 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -125,13 +125,17 @@ jobs: # `--show-diff-on-failure` still shows what a fixer hook changed. # # `script -qec … /dev/null` allocates a pty so prek uses its - # streaming renderer instead. `-e` propagates the command's exit - # status, without which a failing prek would be reported as a - # passing step. `--no-progress` suppresses the spinner that the - # streaming renderer would otherwise redraw in place, which is - # what would otherwise fill this log with ESC[2K / ESC[2A - # sequences — the pty buys progress, --no-progress pays for it in - # cursor control we do not want. + # streaming renderer, which is the only way to get live progress: + # with stdout a plain pipe prek suppresses that renderer and emits + # one block when the whole run finishes. `-e` propagates the + # command's exit status, without which a failing prek would be + # reported as a passing step. + # + # No `--no-progress` here, despite the redraw escapes it would + # remove. That flag hides *the streaming renderer itself*, not + # just its spinner — pty plus --no-progress streams nothing, which + # is both halves of the cost and neither half of the benefit. The + # progress rendering and the live output are the same mechanism. # # Note the repeated flag: `--skip a,b` is NOT a list — prek takes a # single HOOK|PROJECT per occurrence, and a comma-joined value @@ -139,5 +143,5 @@ jobs: # comma form looks like it worked while skipping nothing. run: >- script -qec "prek run --show-diff-on-failure --color=always - --all-files --no-progress --skip workspace-pytest --skip identity" + --all-files --skip workspace-pytest --skip identity" /dev/null From 8285e6dc145e1f4400caa3e59602c1141a57bf5f Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Tue, 8 Sep 2026 05:01:30 +0200 Subject: [PATCH 4/4] =?UTF-8?q?ci(prek):=20revert=20the=20pty=20=E2=80=94?= =?UTF-8?q?=20Actions=20shows=20one=20block=20regardless?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured on the runner, not assumed. Three configurations, each with every hook-result line landing in the same one-second timestamp roughly 106s into the step: plain pipe one block at the end pty (script -qec) one block at the end pty + --no-progress one block at the end A pty does make prek stream locally — spinner, in-place redraws — so the renderer itself works. That output just does not survive to the Actions log, which shows only the final state. PYTHONUNBUFFERED was never in the path: prek is a Rust binary and captures each hook's stdout to replay after the hook finishes. So the plain form comes back: identical information, no script(1) dependency, and no -e footgun, where script would otherwise return its own exit status and a failing prek would report as a passing step. --skip identity and the removal of --verbose stand on their own evidence and remain. Generated-by: Claude Code (Opus 5) --- .github/workflows/pre-commit.yml | 37 ++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 66c116c1c..7e174a247 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -124,24 +124,33 @@ jobs: # thing worth reading. Failures still print their output, and # `--show-diff-on-failure` still shows what a fixer hook changed. # - # `script -qec … /dev/null` allocates a pty so prek uses its - # streaming renderer, which is the only way to get live progress: - # with stdout a plain pipe prek suppresses that renderer and emits - # one block when the whole run finishes. `-e` propagates the - # command's exit status, without which a failing prek would be - # reported as a passing step. + # No `--verbose`, and no pty. Live progress is not achievable here; + # this was measured on the runner rather than assumed. Three + # configurations, all with every hook-result line landing in the + # same one-second timestamp ~106s into the step: # - # No `--no-progress` here, despite the redraw escapes it would - # remove. That flag hides *the streaming renderer itself*, not - # just its spinner — pty plus --no-progress streams nothing, which - # is both halves of the cost and neither half of the benefit. The - # progress rendering and the live output are the same mechanism. + # plain pipe one block at the end + # pty (`script -qec`) one block at the end + # pty + `--no-progress` one block at the end + # + # Locally, a pty does make prek stream (spinner, in-place redraws), + # so the renderer works — but that output does not survive to the + # Actions log, which shows only the final state. `--verbose` never + # helped either: with stdout a pipe, first output and total runtime + # coincide with the flag and without it. + # + # So the plain form is kept: same information, no `script` + # dependency, and no `-e` exit-status footgun (without `-e`, + # `script` returns its own status and a failing prek reports as a + # passing step). `--verbose` is dropped because its only remaining + # effect was to add every passing hook's stdout to that final + # block. Failures still print their output, and + # `--show-diff-on-failure` still shows what a fixer hook changed. # # Note the repeated flag: `--skip a,b` is NOT a list — prek takes a # single HOOK|PROJECT per occurrence, and a comma-joined value # matches no hook at all. It warns rather than failing, so the # comma form looks like it worked while skipping nothing. run: >- - script -qec "prek run --show-diff-on-failure --color=always - --all-files --skip workspace-pytest --skip identity" - /dev/null + prek run --show-diff-on-failure --color=always --all-files + --skip workspace-pytest --skip identity